import { config } from './config.js';

// ─────────────────────────────────────────────
// Factory API HTTP Client
// ─────────────────────────────────────────────

interface ApiResponse<T> {
  ok: true;
  data: T;
  meta?: {
    requestId: string;
    timestamp: string;
    pagination?: {
      page: number;
      limit: number;
      total: number;
      totalPages: number;
      hasNext: boolean;
      hasPrev: boolean;
    };
  };
}

interface ApiError {
  ok: false;
  error: {
    code: string;
    message: string;
    details?: Record<string, unknown>;
    field?: string;
    requestId: string;
  };
}

type ApiResult<T> = ApiResponse<T> | ApiError;

export class FactoryApiError extends Error {
  constructor(
    public code: string,
    message: string,
    public statusCode: number,
    public details?: Record<string, unknown>,
  ) {
    super(message);
    this.name = 'FactoryApiError';
  }
}

class FactoryApiClient {
  private baseUrl: string;
  private apiKey: string;

  constructor() {
    this.baseUrl = config.FACTORY_API_URL;
    this.apiKey = config.FACTORY_API_KEY;
  }

  private async request<T>(
    method: string,
    path: string,
    body?: unknown,
    params?: Record<string, string | number | boolean | undefined>,
  ): Promise<T> {
    const url = new URL(`${this.baseUrl}${path}`);
    if (params) {
      for (const [key, value] of Object.entries(params)) {
        if (value !== undefined) {
          url.searchParams.set(key, String(value));
        }
      }
    }

    const headers: Record<string, string> = {
      'X-API-Key': this.apiKey,
      'Content-Type': 'application/json',
      'X-Request-Id': crypto.randomUUID(),
    };

    const response = await fetch(url.toString(), {
      method,
      headers,
      body: body ? JSON.stringify(body) : undefined,
    });

    const result = (await response.json()) as ApiResult<T>;

    if (!result.ok) {
      const err = result as ApiError;
      throw new FactoryApiError(
        err.error.code,
        err.error.message,
        response.status,
        err.error.details,
      );
    }

    return (result as ApiResponse<T>).data;
  }

  // ─── Pipelines ───────────────────────────────

  async listPipelines(params?: {
    status?: string;
    stage?: string;
    priority?: string;
    page?: number;
    limit?: number;
  }): Promise<Pipeline[]> {
    return this.request<Pipeline[]>('GET', '/pipelines', undefined, params);
  }

  async getPipeline(pipelineId: string): Promise<Pipeline> {
    return this.request<Pipeline>('GET', `/pipelines/${pipelineId}`);
  }

  async getPipelineStages(pipelineId: string): Promise<PipelineStageRecord[]> {
    return this.request<PipelineStageRecord[]>('GET', `/pipelines/${pipelineId}/stages`);
  }

  // ─── Tasks ───────────────────────────────────

  async listTasks(params?: {
    status?: string;
    priority?: string;
    type?: string;
    pipelineId?: string;
    slaBreached?: boolean;
    page?: number;
    limit?: number;
    sort?: string;
  }): Promise<Task[]> {
    return this.request<Task[]>('GET', '/tasks', undefined, params);
  }

  async getTask(taskId: string): Promise<Task> {
    return this.request<Task>('GET', `/tasks/${taskId}`);
  }

  async getTaskStats(): Promise<TaskStats> {
    return this.request<TaskStats>('GET', '/tasks/stats');
  }

  async bulkTasks(body: {
    action: 'approve' | 'reject' | 'defer';
    taskIds: string[];
    notes?: string;
  }): Promise<{ succeeded: string[]; failed: Array<{ taskId: string; error: string }> }> {
    return this.request('POST', '/tasks/bulk', body);
  }

  // ─── Approvals ───────────────────────────────

  async listApprovals(params?: {
    status?: string;
    pipelineId?: string;
  }): Promise<Approval[]> {
    return this.request<Approval[]>('GET', '/approvals', undefined, params);
  }

  async getApproval(approvalId: string): Promise<Approval> {
    return this.request<Approval>('GET', `/approvals/${approvalId}`);
  }

  async approveApproval(approvalId: string, body?: {
    notes?: string;
    conditions?: string[];
  }): Promise<Approval> {
    return this.request<Approval>('POST', `/approvals/${approvalId}/approve`, body ?? {});
  }

  async rejectApproval(approvalId: string, body: {
    reason: string;
    requestedChanges?: string[];
  }): Promise<Approval> {
    return this.request<Approval>('POST', `/approvals/${approvalId}/reject`, body);
  }

  async escalateApproval(approvalId: string, body: {
    reason: string;
    escalateTo?: string;
  }): Promise<Approval> {
    return this.request<Approval>('POST', `/approvals/${approvalId}/escalate`, body);
  }

  // ─── Dashboard ───────────────────────────────

  async getDashboardSummary(): Promise<DashboardSummary> {
    return this.request<DashboardSummary>('GET', '/dashboard/summary');
  }

  // ─── Deploy ──────────────────────────────────

  async deploy(pipelineId: string, target: 'staging' | 'production', options?: {
    version?: string;
    dryRun?: boolean;
  }): Promise<DeployResult> {
    return this.request<DeployResult>('POST', '/deploy', {
      pipeline_id: pipelineId,
      target,
      ...options,
    });
  }

  // ─── Blockers ────────────────────────────────

  async getBlockers(pipelineId?: string): Promise<BlockerInfo[]> {
    return this.request<BlockerInfo[]>('GET', '/blockers', undefined, {
      pipeline_id: pipelineId,
      include_suggestions: true,
    });
  }
}

// Singleton
export const api = new FactoryApiClient();

// ─────────────────────────────────────────────
// Shared types (from CONTRACTS.md)
// ─────────────────────────────────────────────

export interface Pipeline {
  id: string;
  name: string;
  slug: string;
  template: string;
  platform: string;
  currentStage: string;
  status: 'active' | 'paused' | 'completed' | 'failed' | 'archived';
  priority: 'critical' | 'high' | 'medium' | 'low';
  createdBy: string;
  assigneeId: string | null;
  config: Record<string, unknown>;
  metadata: Record<string, unknown>;
  slaDeadline: string | null;
  startedAt: string;
  completedAt: string | null;
  createdAt: string;
  updatedAt: string;
}

export interface PipelineStageRecord {
  id: string;
  pipelineId: string;
  stageName: string;
  stageOrder: number;
  status: 'pending' | 'active' | 'completed' | 'skipped' | 'failed';
  requiresApproval: boolean;
  approvalType: 'manual' | 'auto' | 'conditional';
  autoAdvance: boolean;
  validationRules: unknown[];
  enteredAt: string | null;
  completedAt: string | null;
  durationSeconds: number | null;
  createdAt: string;
}

export interface Task {
  id: string;
  pipelineId: string | null;
  stageName: string | null;
  type: 'approval' | 'review' | 'decision' | 'manual_action' | 'fix_required';
  title: string;
  description: string | null;
  context: TaskContext;
  status: 'pending' | 'claimed' | 'in_progress' | 'completed' | 'expired' | 'escalated';
  priority: 'critical' | 'high' | 'medium' | 'low';
  assigneeId: string | null;
  claimedAt: string | null;
  claimedBy: string | null;
  decision: 'approved' | 'rejected' | 'deferred' | 'escalated' | null;
  decisionNotes: string | null;
  decisionData: Record<string, unknown>;
  decidedAt: string | null;
  decidedBy: string | null;
  slaDeadline: string | null;
  slaWarningsSent: number;
  slaBreached: boolean;
  escalationLevel: number;
  blocksStageAdvance: boolean;
  blocksPipelineId: string | null;
  createdAt: string;
  updatedAt: string;
}

export interface TaskContext {
  summary: string;
  details?: string;
  testResults?: {
    total: number;
    passed: number;
    failed: number;
    skipped: number;
    coveragePercent: number;
  };
  diffSummary?: {
    filesChanged: number;
    insertions: number;
    deletions: number;
  };
  metrics?: Record<string, number>;
  relatedAssets?: string[];
  modalType?: string;
  modalConfig?: Record<string, unknown>;
}

export interface TaskStats {
  pending: number;
  inProgress: number;
  blocked: number;
  avgWaitTimeMinutes: number;
  slaBreaches: number;
  byPriority: Record<string, number>;
  byType: Record<string, number>;
}

export interface Approval {
  id: string;
  taskId: string;
  pipelineId: string;
  stageName: string;
  type: 'stage_gate' | 'deploy' | 'code_review' | 'manual_check';
  status: 'pending' | 'approved' | 'rejected' | 'expired';
  approvedBy: string | null;
  approvedAt: string | null;
  rejectionReason: string | null;
  conditions: string[];
  requiredApprovers: number;
  currentApprovers: number;
  createdAt: string;
}

export interface DashboardSummary {
  pipelines: {
    active: number;
    paused: number;
    completed: number;
    failed: number;
  };
  tasks: TaskStats;
  agents: {
    total: number;
    active: number;
    idle: number;
    error: number;
    offline: number;
  };
  recentActivity: unknown[];
  slaStatus: {
    onTrack: number;
    warning: number;
    breached: number;
  };
}

export interface DeployResult {
  deployId: string;
  pipelineId: string;
  target: 'staging' | 'production';
  status: 'started' | 'succeeded' | 'failed';
  url?: string;
  error?: string;
}

export interface BlockerInfo {
  blockerType: 'task' | 'stage' | 'agent' | 'dependency';
  entityId: string;
  title: string;
  pipelineId: string;
  pipelineName: string;
  priority: 'critical' | 'high' | 'medium' | 'low';
  hoursBlocked: number;
  blockReason: string;
  suggestedAction?: string;
}
