import client from "./client";
import type {
  Test,
  TestResult,
  ContainmentResult,
  AttackSuccessResult,
  DataClassification,
  TestState,
  TestTimelineEntry,
} from "../types/models";

// ── Payloads ───────────────────────────────────────────────────────

export interface TestCreatePayload {
  technique_id: string;
  name: string;
  description?: string;
  platform?: string;
  procedure_text?: string;
  tool_used?: string;
}

export interface TestUpdatePayload {
  name?: string;
  description?: string;
  platform?: string;
  procedure_text?: string;
  tool_used?: string;
  result?: TestResult;
}

export interface RedUpdatePayload {
  name?: string;
  description?: string;
  procedure_text?: string;
  tool_used?: string;
  attack_success?: AttackSuccessResult;
  red_summary?: string;
  execution_start_time?: string;
  execution_end_time?: string;
}

export interface BlueUpdatePayload {
  detection_result?: TestResult;
  containment_result?: ContainmentResult;
  detection_time?: string;
  containment_time?: string;
  blue_summary?: string;
}

export interface RedValidationPayload {
  red_validation_status: "approved" | "rejected";
  red_validation_notes?: string;
}

export interface BlueValidationPayload {
  blue_validation_status: "approved" | "rejected";
  blue_validation_notes?: string;
}

/** Legacy payload — kept for backwards compat. */
export interface TestValidatePayload {
  result: TestResult;
  comments?: string;
}

export interface TestListFilters {
  state?: TestState;
  technique_id?: string;
  platform?: string;
  created_by?: string;
  pending_validation_side?: "red" | "blue";
  not_in_any_campaign?: boolean;
  assigned_to_me?: boolean;
  unassigned_red?: boolean;
  unassigned_blue?: boolean;
  offset?: number;
  limit?: number;
}

// ── CRUD ───────────────────────────────────────────────────────────

/** List tests with optional filters. */
export async function getTests(filters?: TestListFilters): Promise<Test[]> {
  const params = new URLSearchParams();
  if (filters?.state) params.append("state", filters.state);
  if (filters?.technique_id) params.append("technique_id", filters.technique_id);
  if (filters?.platform) params.append("platform", filters.platform);
  if (filters?.created_by) params.append("created_by", filters.created_by);
  if (filters?.pending_validation_side) params.append("pending_validation_side", filters.pending_validation_side);
  if (filters?.not_in_any_campaign) params.append("not_in_any_campaign", "true");
  if (filters?.offset !== undefined) params.append("offset", String(filters.offset));
  if (filters?.limit !== undefined) params.append("limit", String(filters.limit));

  const { data } = await client.get<Test[]>(
    `/tests${params.toString() ? `?${params}` : ""}`,
  );
  return data;
}

/** Create a new test. */
export async function createTest(payload: TestCreatePayload): Promise<Test> {
  const { data } = await client.post<Test>("/tests", payload);
  return data;
}

/** Create a test from an existing template, with optional field overrides. */
export async function createTestFromTemplate(
  templateId: string,
  techniqueId: string,
  overrides?: {
    name?: string;
    description?: string;
    platform?: string;
    procedure_text?: string;
    tool_used?: string;
  },
): Promise<Test> {
  const { data } = await client.post<Test>("/tests/from-template", {
    template_id: templateId,
    technique_id: techniqueId,
    ...overrides,
  });
  return data;
}

/** Get test by ID (with evidences). */
export async function getTestById(testId: string): Promise<Test> {
  const { data } = await client.get<Test>(`/tests/${testId}`);
  return data;
}

/** Update a test (only draft/rejected). */
export async function updateTest(
  testId: string,
  payload: TestUpdatePayload,
): Promise<Test> {
  const { data } = await client.patch<Test>(`/tests/${testId}`, payload);
  return data;
}

/** Update the data classification label for a test (admin only). */
export async function updateTestClassification(
  testId: string,
  dataClassification: DataClassification,
): Promise<Test> {
  const { data } = await client.patch<Test>(`/tests/${testId}/classification`, {
    data_classification: dataClassification,
  });
  return data;
}

// ── Red Team ───────────────────────────────────────────────────────

/** Red Team updates their fields (draft, red_executing). */
export async function updateTestRed(
  testId: string,
  payload: RedUpdatePayload,
): Promise<Test> {
  const { data } = await client.patch<Test>(`/tests/${testId}/red`, payload);
  return data;
}

/** Move test from draft → red_executing. */
export async function startExecution(testId: string): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/start-execution`);
  return data;
}

/** Red Team finalises — red_executing → blue_evaluating. */
export async function submitRedEvidence(testId: string): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/submit-red`);
  return data;
}

// ── Timer Controls ─────────────────────────────────────────────────

/** Pause the active phase timer. */
export async function pauseTimer(testId: string): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/pause-timer`);
  return data;
}

/** Resume a paused phase timer. */
export async function resumeTimer(testId: string): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/resume-timer`);
  return data;
}

// ── Blue Team ──────────────────────────────────────────────────────

/** Blue Team updates their fields (blue_evaluating only). */
export async function updateTestBlue(
  testId: string,
  payload: BlueUpdatePayload,
): Promise<Test> {
  const { data } = await client.patch<Test>(`/tests/${testId}/blue`, payload);
  return data;
}

/** Blue Team finalises — blue_evaluating → in_review. */
export async function submitBlueEvidence(testId: string): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/submit-blue`);
  return data;
}

/** Blue tech picks up the test to start evaluating — sets the Tempo timer start. */
export async function startBlueWork(testId: string): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/start-blue-work`);
  return data;
}

// ── Lead Review Gates (red_review / blue_review) ────────────────────

export interface RedReviewPayload {
  decision: "approve" | "reopen";
  notes?: string;
}

export interface BlueReviewPayload {
  decision: "approve" | "reopen" | "gap";
  notes?: string;
  system_gaps?: string;
}

/** Assigned Red Lead approves or reopens a test sitting in red_review. */
export async function reviewAsRedLead(testId: string, payload: RedReviewPayload): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/review-red`, payload);
  return data;
}

/** Assigned Blue Lead approves, reopens, or flags a capability gap on a test in blue_review. */
export async function reviewAsBlueLead(testId: string, payload: BlueReviewPayload): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/review-blue`, payload);
  return data;
}

// ── Lead Validation ────────────────────────────────────────────────

/** Red Lead approves/rejects the red side. */
export async function validateAsRedLead(
  testId: string,
  payload: RedValidationPayload,
): Promise<Test> {
  const { data } = await client.post<Test>(
    `/tests/${testId}/validate-red`,
    payload,
  );
  return data;
}

/** Blue Lead approves/rejects the blue side. */
export async function validateAsBlueLead(
  testId: string,
  payload: BlueValidationPayload,
): Promise<Test> {
  const { data } = await client.post<Test>(
    `/tests/${testId}/validate-blue`,
    payload,
  );
  return data;
}

// ── Dispute resolution ───────────────────────────────────────────────

export interface ResolveDisputePayload {
  target_team: "red" | "blue";
  notes?: string;
}

/** The approving lead flips to reject, choosing which team must redo the work. */
export async function resolveDispute(testId: string, payload: ResolveDisputePayload): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/resolve-dispute`, payload);
  return data;
}

// ── Reopen ─────────────────────────────────────────────────────────

/** Reopen a rejected test — moves back to draft. */
export async function reopenTest(testId: string): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/reopen`);
  return data;
}

// ── Assignment ─────────────────────────────────────────────────────

/** Assign red_tech and/or blue_tech operators to a test. Admin/leads only. */
export async function assignTest(
  testId: string,
  payload: { red_tech_assignee?: string | null; blue_tech_assignee?: string | null },
): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/assign`, payload);
  return data;
}

// ── On Hold ────────────────────────────────────────────────────────

/** Place a test on hold with a mandatory reason. */
export async function holdTest(testId: string, reason: string): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/hold`, { reason });
  return data;
}

/** Resume a test that was placed on hold. */
export async function resumeTest(testId: string): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/resume`);
  return data;
}

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

/** Get the audit-log timeline for a test. */
export async function getTestTimeline(
  testId: string,
): Promise<TestTimelineEntry[]> {
  const { data } = await client.get<TestTimelineEntry[]>(
    `/tests/${testId}/timeline`,
  );
  return data;
}

// ── Retest Chain ────────────────────────────────────────────────────

export interface RetestChainEntry {
  id: string;
  name: string;
  state: string | null;
  retest_of: string | null;
  retest_count: number;
  result: string | null;
  detection_result: string | null;
  remediation_status: string | null;
  created_at: string | null;
}

/** Get the full retest chain for a test. */
export async function getRetestChain(testId: string): Promise<RetestChainEntry[]> {
  const { data } = await client.get<RetestChainEntry[]>(`/tests/${testId}/retest-chain`);
  return data;
}

// ── Legacy (kept for backwards compat) ─────────────────────────────

/** Validate a test (legacy endpoint). */
export async function validateTest(
  testId: string,
  payload: TestValidatePayload,
): Promise<Test> {
  const { data } = await client.post<Test>(
    `/tests/${testId}/validate`,
    payload,
  );
  return data;
}

/** Reject a test (legacy endpoint). */
export async function rejectTest(testId: string): Promise<Test> {
  const { data } = await client.post<Test>(`/tests/${testId}/reject`);
  return data;
}

// ── Tempo sync ─────────────────────────────────────────────────────

export interface TempoSyncResult {
  worklog_id: string;
  status: "synced" | "already_synced" | "skipped" | "error";
  detail?: string;
}

// ── RT Import ──────────────────────────────────────────────────────

export interface RTEvidenceEntry {
  filename: string;   // e.g. "screenshot_edr.png"
  data: string;       // base64-encoded image (PNG / JPG / GIF / WebP / BMP)
  caption?: string;   // optional description
}

export interface RTTechniqueEntry {
  mitre_id: string;
  result: "detected" | "not_detected" | "partially_detected";
  attack_success: AttackSuccessResult;
  platform?: string;
  notes?: string;
  evidence: RTEvidenceEntry[];  // required — at least 1 image
}

export interface RTImportPayload {
  name: string;
  date?: string;
  description?: string;
  operator?: string;
  techniques: RTTechniqueEntry[];
}

export interface RTImportResult {
  created: number;
  skipped: number;
  items: { mitre_id: string; test_name: string; result: string; attack_success: AttackSuccessResult; evidence_attached: number }[];
  warnings: { mitre_id: string; reason: string }[];
  engagement: string;
}

/** Confirm approval in a disputed test and notify the rejecting lead to discuss. */
export async function requestDiscussion(testId: string): Promise<{
  status: string;
  message: string;
  rejector_username: string;
  rejector_email: string | null;
  rejector_role: string;
}> {
  const { data } = await client.post(`/tests/${testId}/request-discussion`);
  return data;
}

/** Import results from a real Red Team engagement. */
export async function importRT(payload: RTImportPayload): Promise<RTImportResult> {
  const { data } = await client.post<RTImportResult>("/tests/import-rt", payload);
  return data;
}

/** Manually push this test's red team execution worklog to Tempo. */
export async function syncTestToTempo(
  testId: string,
): Promise<{ results: TempoSyncResult[] }> {
  const { data } = await client.post<{ results: TempoSyncResult[] }>(
    `/tests/${testId}/sync-tempo`,
  );
  return data;
}
