import { devopsApiUrl, platformUrl } from './product-config';

// Platform service URL for auth
const PLATFORM_SERVICE_URL = platformUrl;

export interface Service {
  id: string;
  name: string;
  scriptPath: string;
  healthUrl: string;
  repoPath: string;
  status: 'up' | 'down' | 'degraded';
  version: string;
  lastDeployedAt?: string;
  lastHealthCheckAt?: string;
  productId: string;
}

export interface Deployment {
  id: string;
  serviceId: string;
  version: string;
  status: 'running' | 'success' | 'failed';
  logs: string;
  triggeredBy: string;
  triggeredAt: string;
  completedAt?: string;
  productId: string;
}

export interface ServiceHealth {
  serviceId: string;
  status: 'up' | 'down' | 'degraded';
  responseTime?: number;
  lastCheck: string;
}

export interface ApiError {
  error: string;
  status?: number;
}

export interface DeploymentLogsResponse {
  logs: string;
  status: 'running' | 'success' | 'failed';
}

export interface EnvVar {
  id: string;
  name: string;
  value: string;
  isSecret: boolean;
  source: 'local' | 'azure-key-vault';
  azureKeyVaultName?: string;
  azureSecretName?: string;
  updatedAt: string;
}

export interface HermesOpsTimer {
  name: string;
  active: boolean;
  nextRun: string | null;
  lastRun: string | null;
}

export interface HermesOpsRepo {
  path: string;
  branch: string | null;
  clean: boolean;
  head: string | null;
  lastCommitAt: string | null;
  size: string | null;
}

export interface HermesOpsInstance {
  id: 'vijay' | 'bheem';
  label: string;
  hermesHome: string;
  gateway: {
    service: string;
    active: boolean;
    enabled: boolean;
  };
  dashboard: {
    service: string;
    active: boolean;
    url: string;
  };
  backup: {
    timer: HermesOpsTimer;
    repo: HermesOpsRepo;
    restoredFileCount: number | null;
    restoredCronJobs: number | null;
  };
  google: {
    workspaceToken: boolean;
    driveFolder: string;
  };
}

export interface HermesOpsSessionSummary {
  active: number;
  updatedAt: string | null;
}

export interface HermesOpsCronJob {
  name: string;
  label: string;
  active: boolean;
  nextRun: string | null;
  lastRun: string | null;
}

export interface HermesOpsLink {
  label: string;
  href: string;
  description: string;
}

// --- Hermes telemetry (Phase 3) ---------------------------------------------
// Per-instance read-only telemetry: sessions, cron, memory/skills, watchdog
// alerts, backup history. Probe sources (`hermes` CLI, watchdog log, backup
// repo) may be unavailable on a given host; each section carries its own
// `status` so the UI can show "definitely empty" vs "couldn't read".
export type HermesProbeStatus = 'up' | 'down' | 'unknown';

export interface HermesSessionStats {
  totalSessions: number;
  totalMessages: number;
  status: HermesProbeStatus;
}

export interface HermesSessionEntry {
  id: string;
  sessionKey: string;
  platform: string | null;
  chatType: string | null;
  displayName: string | null;
  createdAt: string | null;
  updatedAt: string | null;
  suspended: boolean;
  resumePending: boolean;
  totalTokens: number | null;
  estimatedCostUsd: number | null;
}

export interface HermesSessionList {
  entries: HermesSessionEntry[];
  status: HermesProbeStatus;
}

export interface HermesSessionEvent {
  id: string;
  sessionFile: string;
  timestamp: string | null;
  role: string | null;
  eventType: 'message' | 'tool-call' | 'tool-result' | 'reasoning' | 'system' | 'unknown';
  summary: string;
  toolNames: string[];
  itemTypes: string[];
  status: string | null;
}

export interface HermesSessionEventList {
  entries: HermesSessionEvent[];
  status: HermesProbeStatus;
  sourceCount: number;
}

export interface HermesCronEntry {
  id: string;
  name: string;
  schedule: string | null;
  lastRun: string | null;
  nextRun: string | null;
  lastStatus: string | null;
  active: boolean;
}

export interface HermesCronList {
  entries: HermesCronEntry[];
  status: HermesProbeStatus;
}

export interface HermesMemoryItem {
  id: string;
  type: string;
  key: string;
  summary: string;
  updatedAt: string | null;
}

export interface HermesMemoryList {
  items: HermesMemoryItem[];
  status: HermesProbeStatus;
}

export interface HermesSkillItem {
  id: string;
  name: string;
  description: string;
  enabled: boolean;
}

export interface HermesSkillList {
  items: HermesSkillItem[];
  status: HermesProbeStatus;
}

export type HermesWatchdogSeverity = 'info' | 'warn' | 'critical';

export interface HermesWatchdogAlert {
  timestamp: string;
  severity: HermesWatchdogSeverity;
  message: string;
}

export interface HermesWatchdogFeed {
  alerts: HermesWatchdogAlert[];
  source: string | null;
  status: HermesProbeStatus;
}

export interface HermesBackupHistoryEntry {
  sha: string;
  committedAt: string;
  subject: string;
}

export interface HermesBackupHistory {
  entries: HermesBackupHistoryEntry[];
  repoPath: string | null;
  status: HermesProbeStatus;
}

export interface HermesTelemetrySnapshot {
  generatedAt: string;
  cached: boolean;
  instanceId: 'vijay' | 'bheem';
  sessions: HermesSessionStats;
  sessionList: HermesSessionList;
  sessionEvents: HermesSessionEventList;
  cron: HermesCronList;
  memory: HermesMemoryList;
  skills: HermesSkillList;
  watchdog: HermesWatchdogFeed;
  backupHistory: HermesBackupHistory;
  warnings: string[];
}

export interface HermesTokenSummary {
  sessionCount: number;
  messageCount: number;
  toolCallCount: number;
  inputTokens: number;
  outputTokens: number;
  cacheReadTokens: number;
  cacheWriteTokens: number;
  reasoningTokens: number;
  totalTokens: number;
  estimatedCostUsd: number;
  actualCostUsd: number;
  firstStartedAt: string | null;
  lastActivityAt: string | null;
}

export interface HermesTokenByModel {
  model: string;
  provider: string;
  sessionCount: number;
  totalTokens: number;
  estimatedCostUsd: number;
}

export interface HermesTokenByDay {
  day: string;
  sessionCount: number;
  totalTokens: number;
  estimatedCostUsd: number;
}

export interface HermesTokenSession {
  id: string;
  title: string | null;
  source: string | null;
  model: string;
  provider: string;
  startedAt: string | null;
  endedAt: string | null;
  totalTokens: number;
  messageCount: number;
  toolCallCount: number;
  estimatedCostUsd: number;
}

export interface HermesTokenUsageSnapshot {
  generatedAt: string;
  cached: boolean;
  instanceId: 'vijay' | 'bheem';
  status: HermesProbeStatus;
  source: string | null;
  summary: HermesTokenSummary;
  byModel: HermesTokenByModel[];
  byDay: HermesTokenByDay[];
  recentSessions: HermesTokenSession[];
  warnings: string[];
}

export interface HermesOpsSnapshot {
  generatedAt: string;
  tailscaleIp: string | null;
  emergencyDriveUpload: HermesOpsTimer;
  activeSessions: HermesOpsSessionSummary;
  cronJobs: HermesOpsCronJob[];
  recentAlerts: string[];
  quickLinks: HermesOpsLink[];
  instances: HermesOpsInstance[];
  warnings: string[];
}

let csrfToken: string | null = null;
let csrfTokenExpiresAt: number = 0;

async function getAccessToken(): Promise<string | null> {
  if (typeof window === 'undefined') return null;
  let token = getAccessTokenFromStorage();

  // If no token, try to refresh
  if (!token) {
    token = await refreshAccessToken();
  }

  return token;
}

async function getCsrfToken(): Promise<string | null> {
  if (csrfToken && Date.now() < csrfTokenExpiresAt) {
    return csrfToken;
  }

  try {
    const token = await getAccessToken();
    if (!token) {
      return null;
    }

    const response = await fetch(`${devopsApiUrl}/api/csrf-token`, {
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${token}`,
      },
    });

    if (response.ok) {
      const data = await response.json();
      csrfToken = data.csrfToken;
      csrfTokenExpiresAt = Date.now() + 3000000; // 50 minutes (before 1 hour expiry)
      return csrfToken;
    }
  } catch (error) {
    console.error('Failed to fetch CSRF token:', error);
  }

  return null;
}

export async function apiRequest<T>(
  endpoint: string,
  options: RequestInit = {}
): Promise<T> {
  const token = await getAccessToken();
  const headers: HeadersInit = {
    'Content-Type': 'application/json',
    ...options.headers,
  };

  if (token) {
    headers['Authorization'] = `Bearer ${token}`;
  }

  const method = options.method?.toUpperCase();
  const stateChangingMethods = ['POST', 'PUT', 'DELETE', 'PATCH'];

  if (method && stateChangingMethods.includes(method)) {
    const csrf = await getCsrfToken();
    if (csrf) {
      headers['X-CSRF-Token'] = csrf;
    }
  }

  let response = await fetch(`${devopsApiUrl}${endpoint}`, {
    ...options,
    headers,
  });

  // Handle 401 - try to refresh token and retry
  if (response.status === 401 && token) {
    const newToken = await refreshAccessToken();
    if (newToken) {
      headers['Authorization'] = `Bearer ${newToken}`;
      response = await fetch(`${devopsApiUrl}${endpoint}`, {
        ...options,
        headers,
      });
    }
  }

  // Handle 403 - CSRF token retry
  if (response.status === 403) {
    const errorData = await response.json().catch(() => ({}));
    if (errorData.error === 'Invalid CSRF token') {
      csrfToken = null;
      csrfTokenExpiresAt = 0;
      const newCsrf = await getCsrfToken();
      if (newCsrf) {
        headers['X-CSRF-Token'] = newCsrf;
        response = await fetch(`${devopsApiUrl}${endpoint}`, {
          ...options,
          headers,
        });
      }
    }
  }

  if (!response.ok) {
    const error: ApiError = {
      error: `API error: ${response.status} ${response.statusText}`,
      status: response.status
    };
    throw error;
  }

  return response.json();
}

export const api = {
  // Services
  getServices: () => apiRequest<Service[]>('/api/services'),
  getService: (id: string) => apiRequest<Service>(`/api/services/${id}`),
  createService: (data: Partial<Service>) =>
    apiRequest<Service>('/api/services', {
      method: 'POST',
      body: JSON.stringify(data),
    }),
  updateService: (id: string, data: Partial<Service>) =>
    apiRequest<Service>(`/api/services/${id}`, {
      method: 'PUT',
      body: JSON.stringify(data),
    }),
  deleteService: (id: string) =>
    apiRequest<void>(`/api/services/${id}`, {
      method: 'DELETE',
    }),

  // Deployments
  getDeployments: (limit = 20) => apiRequest<Deployment[]>(`/api/deployments?limit=${limit}`),
  getServiceDeployments: (serviceId: string, limit = 50) =>
    apiRequest<Deployment[]>(`/api/deployments/service/${serviceId}?limit=${limit}`),
  getDeployment: (id: string) => apiRequest<Deployment>(`/api/deployments/${id}`),
  getDeploymentLogs: (id: string) =>
    apiRequest<DeploymentLogsResponse>(`/api/deployments/${id}/logs`),
  triggerDeployment: (serviceId: string) =>
    apiRequest<{ deploymentId: string; status: string }>(`/api/deployments/trigger/${serviceId}`, {
      method: 'POST',
    }),

  // Health
  getHealth: () => apiRequest<ServiceHealth[]>('/api/health'),
  getServiceHealth: (serviceId: string) =>
    apiRequest<ServiceHealth>(`/api/health/${serviceId}`),
  clearHealthCache: () => apiRequest<{ message: string }>('/api/health/cache', { method: 'DELETE' }),

  // Hermes operations
  getHermesOps: () => apiRequest<HermesOpsSnapshot>('/api/hermes/ops'),

  // Hermes per-instance telemetry (Phase 3 — sessions/cron/memory/skills/
  // watchdog/backup-history). Returns a Zod-validated snapshot from the
  // backend; sections may report status:'unknown' if their underlying
  // source isn't readable in the current environment (CI / dev box).
  getHermesTelemetry: (instance: 'vijay' | 'bheem') =>
    apiRequest<HermesTelemetrySnapshot>(`/api/hermes/telemetry/${instance}`),
  getHermesTokenUsage: (instance: 'vijay' | 'bheem') =>
    apiRequest<HermesTokenUsageSnapshot>(`/api/hermes/telemetry/${instance}/token-usage`),

  // Seed
  seedServices: () => apiRequest<{ message: string }>('/api/seed', { method: 'POST' }),

  // Environment Variables
  getEnvVars: () => apiRequest<EnvVar[]>('/api/env'),
  getEnvVar: (id: string) => apiRequest<EnvVar>(`/api/env/${id}`),
  createEnvVar: (data: Partial<EnvVar>) =>
    apiRequest<EnvVar>('/api/env', {
      method: 'POST',
      body: JSON.stringify(data),
    }),
  updateEnvVar: (id: string, data: Partial<EnvVar>) =>
    apiRequest<EnvVar>(`/api/env/${id}`, {
      method: 'PUT',
      body: JSON.stringify(data),
    }),
  deleteEnvVar: (id: string) =>
    apiRequest<void>(`/api/env/${id}`, {
      method: 'DELETE',
    }),
  syncAzureKeyVault: () =>
    apiRequest<{ synced: number; errors: string[] }>('/api/env/sync-azure', {
      method: 'POST',
    }),
};

// Standalone functions for environment variables (used by env page)
export const getEnvVars = () => api.getEnvVars();
export const createEnvVar = (data: Partial<EnvVar>) => api.createEnvVar(data);
export const updateEnvVar = (id: string, data: Partial<EnvVar>) => api.updateEnvVar(id, data);
export const deleteEnvVar = (id: string) => api.deleteEnvVar(id);

// Azure Config
export interface AzureConfig {
  id: string;
  tenantId: string;
  clientId: string;
  keyVaultUrl: string;
  isActive: boolean;
  updatedAt: string;
  hasClientSecret?: boolean;
}

export const azureApi = {
  getAzureConfig: () => apiRequest<AzureConfig>('/api/azure-config'),
  createAzureConfig: (data: Partial<AzureConfig>) =>
    apiRequest<AzureConfig>('/api/azure-config', {
      method: 'POST',
      body: JSON.stringify(data),
    }),
  updateAzureConfig: (id: string, data: Partial<AzureConfig>) =>
    apiRequest<AzureConfig>(`/api/azure-config/${id}`, {
      method: 'PUT',
      body: JSON.stringify(data),
    }),
  deleteAzureConfig: (id: string) =>
    apiRequest<void>(`/api/azure-config/${id}`, {
      method: 'DELETE',
    }),
  testAzureConnection: () =>
    apiRequest<{ success: boolean; error?: string }>('/api/azure-config/test', {
      method: 'POST',
    }),
};

export const getAzureConfig = () => azureApi.getAzureConfig();
export const createAzureConfig = (data: Partial<AzureConfig>) => azureApi.createAzureConfig(data);
export const updateAzureConfig = (id: string, data: Partial<AzureConfig>) => azureApi.updateAzureConfig(id, data);
export const deleteAzureConfig = (id: string) => azureApi.deleteAzureConfig(id);
export const testAzureConnection = () => azureApi.testAzureConnection();

// Code Quality
export interface CodeQualityIssue {
  id: string;
  type: 'error' | 'warning' | 'info';
  category: 'typescript' | 'eslint' | 'build' | 'test' | 'format';
  file: string;
  line?: number;
  column?: number;
  message: string;
  rule?: string;
}

export interface CodeQualityReport {
  id: string;
  projectId: string;
  projectName: string;
  projectPath: string;
  timestamp: string;
  summary: {
    totalIssues: number;
    errors: number;
    warnings: number;
    infos: number;
  };
  categories: {
    typescript: {
      errors: number;
      warnings: number;
      duration: number;
    };
    eslint: {
      errors: number;
      warnings: number;
      duration: number;
    };
    build: {
      success: boolean;
      duration: number;
      errors: number;
    };
    test: {
      success: boolean;
      passed: number;
      failed: number;
      duration: number;
    };
  };
  issues: CodeQualityIssue[];
}

export interface CodeQualityCheckParams {
  projectId: string;
  projectPath: string;
  checks: Array<'typescript' | 'eslint' | 'build' | 'test'>;
}

export const codeQualityApi = {
  runCheck: (params: CodeQualityCheckParams) =>
    apiRequest<CodeQualityReport>('/api/code-quality/check', {
      method: 'POST',
      body: JSON.stringify(params),
    }),
};

export const runCodeQualityCheck = (params: CodeQualityCheckParams) => codeQualityApi.runCheck(params);

// VM Health
export type VmCheckLevel = 'OK' | 'WARN' | 'CRIT';

export interface VmCheck {
  level: VmCheckLevel;
  value: string;
  message: string;
}

export interface VmHealthResult {
  timestamp: string;
  hostname: string;
  overall: VmCheckLevel;
  checks: Record<string, VmCheck>;
  error?: string;
}

export interface CronRunSummary {
  timestamp: string;
  mode: 'standard' | 'full';
  diskBefore: string;
  diskAfter: string;
  freedMB: number;
  durationSecs: number;
  success: boolean;
  steps: string[];
  jsonSummary?: Record<string, unknown>;
}

export interface CronJob {
  name: string;
  schedule: string;
  description: string;
  lastRun: CronRunSummary | null;
  nextRun: string | null;
}

export interface CronStatusResponse {
  jobs: CronJob[];
  recentRuns: CronRunSummary[];
}

export interface UnhealthyContainer {
  name: string;
  status: string;
  restartCount: number;
  lastHealthLogs: string[];
  unhealthySince: string | null;
}

export interface OllamaModel {
  name: string;
  sizeGB: number;
  modifiedAt: string;
}

export interface OllamaRunning {
  name: string;
  sizeGB: number;
  processor: string;
  expiresAt: string;
}

export interface OllamaModelsResponse {
  models: OllamaModel[];
  running: OllamaRunning[];
}

export interface ContainerInfo {
  name: string;
  image: string;
  stack: string;
  state: string;
  health: string;
  uptimeSecs: number;
  cpuPercent: number;
  memMiB: number;
  memLimitMiB: number;
  restartCount: number;
}

export const vmApi = {
  getHealth: () => apiRequest<VmHealthResult>('/api/vm/health'),
  getCleanupLog: (lines = 40) =>
    apiRequest<{ log: string }>(`/api/vm/cleanup-log?lines=${lines}`),
  runCleanup: (mode: 'weekly' | 'monthly' | 'dry-run') =>
    apiRequest<{ success: boolean; output: string }>('/api/vm/cleanup', {
      method: 'POST',
      body: JSON.stringify({ mode }),
    }),
  getCronStatus: () => apiRequest<CronStatusResponse>('/api/vm/cron-status'),
  getUnhealthyContainers: () =>
    apiRequest<{ containers: UnhealthyContainer[] }>('/api/vm/containers/unhealthy'),
  restartContainer: (name: string) =>
    apiRequest<{ success: boolean; message: string }>(
      `/api/vm/containers/${encodeURIComponent(name)}/restart`,
      { method: 'POST' },
    ),
  getOllamaModels: () => apiRequest<OllamaModelsResponse>('/api/vm/ollama/models'),
  unloadOllamaModel: (name: string) =>
    apiRequest<{ success: boolean; message: string }>(
      `/api/vm/ollama/models/${encodeURIComponent(name)}`,
      { method: 'DELETE' },
    ),
  getTrend: (metric: 'disk' | 'steal' | 'io', range: '7d' | '30d') =>
    apiRequest<TrendSeries>(`/api/vm/metrics/trend?metric=${metric}&range=${range}`),
  getMemoryTrend: (range: '7d' | '30d') =>
    apiRequest<{ available: TrendSeries; swap: TrendSeries }>(
      `/api/vm/metrics/trend?metric=memory&range=${range}`,
    ),
  getAllContainers: () => apiRequest<ContainerInfo[]>('/api/vm/containers'),
  getContainerLogs: (name: string, lines = 50) =>
    apiRequest<{ logs: string }>(`/api/vm/containers/${encodeURIComponent(name)}/logs?lines=${lines}`),
};

export interface TrendPoint { t: number; v: number }

export interface TrendSeries {
  metric: string;
  unit: string;
  points: TrendPoint[];
  latest: number;
  avg: number;
  peak: number;
}

// Auth API - calls platform-service for authentication
export interface LoginRequest {
  email: string;
  password: string;
  productId: string;
}

export interface LoginResponse {
  accessToken: string;
  refreshToken: string;
  user: {
    id: string;
    email: string;
    role: string;
    plan: string;
    displayName: string;
    products?: Array<{
      productId: string;
      plan: string;
      role: string;
    }>;
  };
}

export interface RefreshRequest {
  refreshToken: string;
}

export interface RefreshResponse {
  accessToken: string;
  refreshToken: string;
}

export interface MeResponse {
  id: string;
  email: string;
  role: string;
  plan: string;
  displayName: string;
  emailVerified: boolean;
  currentProduct: string;
  products: Array<{
    productId: string;
    plan: string;
    role: string;
  }>;
  mfaEnabled: boolean;
  mfaMethods: string[];
}

export const authApi = {
  login: async (data: LoginRequest): Promise<LoginResponse> => {
    const response = await fetch(`${PLATFORM_SERVICE_URL}/auth/login`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(data),
    });

    if (!response.ok) {
      const error = await response.json().catch(() => ({ error: 'Login failed' }));
      throw new Error(error.error || 'Login failed');
    }

    return response.json();
  },

  refresh: async (data: RefreshRequest): Promise<RefreshResponse> => {
    const response = await fetch(`${PLATFORM_SERVICE_URL}/auth/refresh`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(data),
    });

    if (!response.ok) {
      throw new Error('Token refresh failed');
    }

    return response.json();
  },

  me: async (token: string): Promise<MeResponse> => {
    const response = await fetch(`${PLATFORM_SERVICE_URL}/auth/me`, {
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${token}`,
      },
    });

    if (!response.ok) {
      throw new Error('Failed to get user info');
    }

    return response.json();
  },
};

// Helper functions for auth state management
export function setAccessToken(token: string): void {
  if (typeof window !== 'undefined') {
    localStorage.setItem('access_token', token);
  }
}

export function setRefreshToken(token: string): void {
  if (typeof window !== 'undefined') {
    localStorage.setItem('refresh_token', token);
  }
}

export function getAccessTokenFromStorage(): string | null {
  if (typeof window === 'undefined') return null;
  return localStorage.getItem('access_token');
}

export function getRefreshTokenFromStorage(): string | null {
  if (typeof window === 'undefined') return null;
  return localStorage.getItem('refresh_token');
}

export function clearAuthTokens(): void {
  if (typeof window !== 'undefined') {
    localStorage.removeItem('access_token');
    localStorage.removeItem('refresh_token');
  }
}

export async function refreshAccessToken(): Promise<string | null> {
  const refreshToken = getRefreshTokenFromStorage();
  if (!refreshToken) return null;

  try {
    const response = await authApi.refresh({ refreshToken });
    setAccessToken(response.accessToken);
    setRefreshToken(response.refreshToken);
    return response.accessToken;
  } catch {
    clearAuthTokens();
    return null;
  }
}
