import client from "./client";

// ── Types ───────────────────────────────────────────────────────────

export interface CampaignTest {
  id: string;
  test_id: string;
  order_index: number;
  depends_on: string | null;
  phase: string | null;
  test_name: string | null;
  test_state: string | null;
  test_result: string | null;
  technique_mitre_id: string | null;
  technique_name: string | null;
  platform: string | null;
}

export interface CampaignProgress {
  total: number;
  by_state: Record<string, number>;
  completion_pct: number;
}

export interface Campaign {
  id: string;
  name: string;
  description: string | null;
  type: string;
  status: string;
  threat_actor_id: string | null;
  threat_actor_name: string | null;
  created_by: string | null;
  start_date: string | null;
  scheduled_at: string | null;
  completed_at: string | null;
  approved_by: string | null;
  approved_at: string | null;
  rejection_reason: string | null;
  target_platform: string | null;
  tags: string[];
  created_at: string | null;
  is_recurring: boolean;
  recurrence_pattern: string | null;
  next_run_at: string | null;
  last_run_at: string | null;
  parent_campaign_id: string | null;
  tests: CampaignTest[];
  progress: CampaignProgress;
}

export interface CampaignSummary {
  id: string;
  name: string;
  description: string | null;
  type: string;
  status: string;
  threat_actor_id: string | null;
  threat_actor_name: string | null;
  target_platform: string | null;
  tags: string[];
  start_date: string | null;
  created_at: string | null;
  test_count: number;
  completion_pct: number;
}

export interface CampaignCreatePayload {
  name: string;
  description?: string;
  type?: string;
  threat_actor_id?: string;
  target_platform?: string;
  tags?: string[];
  scheduled_at?: string;
}

export interface AddTestPayload {
  test_id: string;
  order_index?: number;
  depends_on?: string;
  phase?: string;
}

export type ModificationRequestAction = "add_test" | "remove_test";
export type ModificationRequestStatus = "pending" | "approved" | "rejected";

export interface CampaignModificationRequest {
  id: string;
  campaign_id: string;
  campaign_name: string | null;
  requested_by: string | null;
  action: ModificationRequestAction;
  /** Null once the underlying Test is deleted (e.g. an approved "remove_test"
   * request) — this row is the surviving audit record, not a live link. */
  test_id: string | null;
  test_name: string | null;
  order_index: number | null;
  phase: string | null;
  justification: string;
  status: ModificationRequestStatus;
  reviewed_by: string | null;
  reviewed_at: string | null;
  review_notes: string | null;
  created_at: string | null;
}

export interface CampaignTimelineEntry {
  id: string;
  action: string;
  user_id: string | null;
  timestamp: string;
  details: Record<string, unknown>;
}

// ── API Functions ───────────────────────────────────────────────────

/** List campaigns with optional filters. */
export async function listCampaigns(params?: {
  type?: string;
  status?: string;
  threat_actor_id?: string;
  search?: string;
  offset?: number;
  limit?: number;
}): Promise<{ total: number; items: CampaignSummary[] }> {
  const { data } = await client.get("/campaigns", { params });
  return data;
}

/** Get a campaign detail with tests and progress. */
export async function getCampaign(campaignId: string): Promise<Campaign> {
  const { data } = await client.get<Campaign>(`/campaigns/${campaignId}`);
  return data;
}

/** Create a new campaign. */
export async function createCampaign(payload: CampaignCreatePayload): Promise<Campaign> {
  const { data } = await client.post<Campaign>("/campaigns", payload);
  return data;
}

/** Update a campaign. */
export async function updateCampaign(
  campaignId: string,
  payload: Partial<CampaignCreatePayload>,
): Promise<Campaign> {
  const { data } = await client.patch<Campaign>(`/campaigns/${campaignId}`, payload);
  return data;
}

/** Add a test to a campaign. */
export async function addTestToCampaign(
  campaignId: string,
  payload: AddTestPayload,
): Promise<CampaignTest> {
  const { data } = await client.post<CampaignTest>(`/campaigns/${campaignId}/tests`, payload);
  return data;
}

/** Remove a test from a campaign. */
export async function removeTestFromCampaign(
  campaignId: string,
  campaignTestId: string,
): Promise<void> {
  await client.delete(`/campaigns/${campaignId}/tests/${campaignTestId}`);
}

/** Admin-only emergency override: activate a draft campaign directly, bypassing the approval queue. */
export async function activateCampaign(campaignId: string): Promise<Campaign> {
  const { data } = await client.post<Campaign>(`/campaigns/${campaignId}/activate`);
  return data;
}

/** Mark a campaign as completed. */
export async function completeCampaign(campaignId: string): Promise<Campaign> {
  const { data } = await client.post<Campaign>(`/campaigns/${campaignId}/complete`);
  return data;
}

/** Get campaign progress. */
export async function getCampaignProgress(campaignId: string): Promise<CampaignProgress & {
  campaign_id: string;
  campaign_name: string;
}> {
  const { data } = await client.get(`/campaigns/${campaignId}/progress`);
  return data;
}

/** Generate a campaign from a threat actor. */
export async function generateCampaignFromThreatActor(
  actorId: string,
  options?: { start_date?: string },
): Promise<Campaign> {
  const { data } = await client.post<Campaign>(
    `/campaigns/from-threat-actor/${actorId}`,
    options ?? {},
  );
  return data;
}

// ── Scheduling ─────────────────────────────────────────────────────

export interface SchedulePayload {
  is_recurring: boolean;
  recurrence_pattern?: string;
  next_run_at?: string;
}

export interface CampaignHistoryEntry {
  id: string;
  name: string;
  status: string;
  test_count: number;
  completion_pct: number;
  created_at: string | null;
  completed_at: string | null;
}

/** Configure recurrence scheduling for a campaign. */
export async function scheduleCampaign(
  campaignId: string,
  payload: SchedulePayload,
): Promise<Campaign> {
  const { data } = await client.patch<Campaign>(`/campaigns/${campaignId}/schedule`, payload);
  return data;
}

/** Delete a campaign. Only draft campaigns can be deleted (admins can delete any). */
export async function deleteCampaign(
  campaignId: string,
  deleteTests: boolean = false,
): Promise<void> {
  await client.delete(`/campaigns/${campaignId}`, {
    params: { delete_tests: deleteTests },
  });
}

// ── Timing summary ─────────────────────────────────────────────────

export interface CampaignTimingBreakdown {
  test_id: string;
  test_name: string;
  state: string | null;
  red_execution_secs: number;
  blue_queue_secs: number;
  blue_evaluation_secs: number;
  total_secs: number;
  has_timing: boolean;
}

export interface CampaignTimingSummary {
  campaign_id: string;
  campaign_name: string;
  tests_total: number;
  tests_with_timing: number;
  red_execution_secs: number;
  blue_queue_secs: number;
  blue_evaluation_secs: number;
  total_secs: number;
  breakdown: CampaignTimingBreakdown[];
}

/** Get aggregated Red/Blue timing metrics for a campaign. */
export async function getCampaignTiming(campaignId: string): Promise<CampaignTimingSummary> {
  const { data } = await client.get<CampaignTimingSummary>(`/campaigns/${campaignId}/timing-summary`);
  return data;
}

/** Get execution history (child campaigns) for a recurring campaign. */
export async function getCampaignHistory(campaignId: string): Promise<{
  campaign_id: string;
  campaign_name: string;
  items: CampaignHistoryEntry[];
}> {
  const { data } = await client.get(`/campaigns/${campaignId}/history`);
  return data;
}

// ── Approval workflow ──────────────────────────────────────────────

/** Submit a draft campaign into the manager's approval queue. */
export async function submitCampaignForApproval(campaignId: string): Promise<Campaign> {
  const { data } = await client.post<Campaign>(`/campaigns/${campaignId}/submit`);
  return data;
}

/** Manager approves a pending campaign, fixing its start date. */
export async function approveCampaign(campaignId: string, startDate: string): Promise<Campaign> {
  const { data } = await client.post<Campaign>(`/campaigns/${campaignId}/approve`, {
    start_date: startDate,
  });
  return data;
}

/** Manager rejects a pending campaign with a mandatory reason. */
export async function rejectCampaign(campaignId: string, reason: string): Promise<Campaign> {
  const { data } = await client.post<Campaign>(`/campaigns/${campaignId}/reject`, { reason });
  return data;
}

// ── Modification requests ───────────────────────────────────────────

/** File a request to add/remove a test on an active campaign. */
export async function createModificationRequest(
  campaignId: string,
  payload: {
    action: ModificationRequestAction;
    test_id: string;
    justification: string;
    order_index?: number;
    phase?: string;
  },
): Promise<CampaignModificationRequest> {
  const { data } = await client.post<CampaignModificationRequest>(
    `/campaigns/${campaignId}/modification-requests`,
    payload,
  );
  return data;
}

/** List modification requests filed against a specific campaign. */
export async function listCampaignModificationRequests(
  campaignId: string,
): Promise<CampaignModificationRequest[]> {
  const { data } = await client.get<CampaignModificationRequest[]>(
    `/campaigns/${campaignId}/modification-requests`,
  );
  return data;
}

/** Manager's global queue of modification requests awaiting review. */
export async function listPendingModificationRequests(): Promise<CampaignModificationRequest[]> {
  const { data } = await client.get<CampaignModificationRequest[]>(
    "/campaigns/modification-requests/pending",
  );
  return data;
}

/** Manager approves a modification request — the test change is applied now. */
export async function approveModificationRequest(
  requestId: string,
): Promise<CampaignModificationRequest> {
  const { data } = await client.post<CampaignModificationRequest>(
    `/campaigns/modification-requests/${requestId}/approve`,
  );
  return data;
}

/** Manager rejects a modification request with mandatory review notes. */
export async function rejectModificationRequest(
  requestId: string,
  reviewNotes: string,
): Promise<CampaignModificationRequest> {
  const { data } = await client.post<CampaignModificationRequest>(
    `/campaigns/modification-requests/${requestId}/reject`,
    { review_notes: reviewNotes },
  );
  return data;
}

// ── Timeline ─────────────────────────────────────────────────────────

/** Get the audit-log timeline for a campaign. */
export async function getCampaignTimeline(campaignId: string): Promise<CampaignTimelineEntry[]> {
  const { data } = await client.get<CampaignTimelineEntry[]>(`/campaigns/${campaignId}/timeline`);
  return data;
}
