/**
 * Cases domain hooks.
 *
 * Note on types: the FastAPI `/api/cases` endpoint doesn't declare a response
 * model, so openapi-typescript emits `unknown` for its payload. Until the
 * backend is annotated (see out-of-scope in the rewrite plan), we maintain a
 * small local type that matches what the running API returns today. Any drift
 * surfaces as a runtime TypeScript error the first time a property is touched.
 */

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { apiRequest } from "./client";
import type { CaseCreateInput, CaseUpdateInput } from "@/lib/schemas/case";
import type { PracticeArea, AppealSubtype } from "@/lib/practice-area";

/* CaseStatus + the status list/labels/phases are defined once in ./case-status
 * (single source of truth, UI-B1). Re-exported here so existing
 * `import { CaseStatus } from "@/lib/api/cases"` sites keep working. */
export type { CaseStatus } from "./case-status";
import type { CaseStatus } from "./case-status";

export type Case = {
  case_number: string;
  title: string;
  status: CaseStatus;
  subject?: string | null;
  expected_outcome?: string | null;
  created_at?: string;
  updated_at?: string;
  /** ISO timestamp; null when active */
  archived_at?: string | null;
  /* Multi-tenant axis — populated by backfill + server-side derive */
  practice_area?: PracticeArea;
  appeal_subtype?: AppealSubtype;
  /* Present when loaded with detail=true */
  document_count?: number;
  processing_count?: number;
  committee_type?: string | null;
  hearing_date?: string | null;
  appellants?: string[] | null;
  respondents?: string[] | null;
  property_address?: string | null;
  permit_number?: string | null;
  /* 'ערר' = regular appeal, 'בל"מ' = extension-of-time request */
  proceeding_type?: "ערר" | 'בל"מ';
};

export type CaseDocument = {
  id: string;
  case_id: string;
  doc_type: string;
  title: string;
  file_path: string;
  page_count: number | null;
  extraction_status: string;
  created_at: string;
  practice_area?: PracticeArea;
  appeal_subtype?: AppealSubtype;
  /** Free-form JSONB. Known keys: appraiser_side, is_post_hearing, references. */
  metadata?: Record<string, unknown>;
};

export type CaseDetail = Case & {
  documents?: CaseDocument[];
  blocks?: Array<{ code: string; status?: string; char_count?: number }>;
};

export type CasesScope = "active" | "archived" | "all";

export const casesKeys = {
  all: ["cases"] as const,
  list: (detail: boolean, scope: CasesScope = "active") =>
    [...casesKeys.all, "list", { detail, scope }] as const,
  detail: (caseNumber: string) =>
    [...casesKeys.all, "detail", caseNumber] as const,
};

export function useCases(detail = false, scope: CasesScope = "active") {
  return useQuery({
    queryKey: casesKeys.list(detail, scope),
    queryFn: ({ signal }) => {
      const params = new URLSearchParams();
      if (detail) params.set("detail", "true");
      if (scope === "archived") params.set("archived_only", "true");
      else if (scope === "all") params.set("include_archived", "true");
      const qs = params.toString();
      return apiRequest<Case[]>(`/api/cases${qs ? `?${qs}` : ""}`, { signal });
    },
  });
}

export type ArchiveResult = {
  status: string;
  case_number: string;
  archived_at?: string | null;
  paperclip?: {
    status: string;
    project_id?: string;
    archived_at?: string | null;
    message?: string;
    issues_cancelled?: Array<{ identifier: string; title: string }>;
  };
};

export function useArchiveCase(caseNumber: string | undefined) {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: () =>
      apiRequest<ArchiveResult>(`/api/cases/${caseNumber}/archive`, {
        method: "POST",
      }),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: casesKeys.all });
    },
  });
}

export function useRestoreCase(caseNumber: string | undefined) {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: () =>
      apiRequest<ArchiveResult>(`/api/cases/${caseNumber}/restore`, {
        method: "POST",
      }),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: casesKeys.all });
    },
  });
}

export function useCase(caseNumber: string | undefined) {
  return useQuery({
    queryKey: casesKeys.detail(caseNumber ?? ""),
    queryFn: ({ signal }) =>
      apiRequest<CaseDetail>(`/api/cases/${caseNumber}/details`, { signal }),
    enabled: Boolean(caseNumber),
    /* Replaces the old 5s polling from vanilla index.html */
    staleTime: 5_000,
    refetchInterval: 5_000,
  });
}

export type WorkflowStatus = {
  case_number?: string;
  status?: CaseStatus | string;
  current_step?: string;
  steps?: Array<{
    key: string;
    label?: string;
    status: "done" | "current" | "pending" | string;
  }>;
  /* FastAPI returns free-form JSON; keep it permissive */
  [key: string]: unknown;
};

export function useCreateCase() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: (input: CaseCreateInput) =>
      apiRequest<{ case_number?: string; message?: string; [k: string]: unknown }>(
        `/api/cases/create`,
        { method: "POST", body: input },
      ),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: casesKeys.all });
    },
  });
}

export function useUpdateCase(caseNumber: string | undefined) {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: (input: CaseUpdateInput) =>
      apiRequest<CaseDetail>(`/api/cases/${caseNumber}`, {
        method: "PUT",
        body: input,
      }),
    onSuccess: (data) => {
      /* Patch cached detail, then invalidate only the LIST queries — not
       * casesKeys.all, which would also invalidate the detail we just patched
       * and throw away the optimistic merge. */
      if (caseNumber) {
        qc.setQueryData<CaseDetail | undefined>(
          casesKeys.detail(caseNumber),
          (prev) => (prev ? { ...prev, ...data } : prev),
        );
      }
      qc.invalidateQueries({ queryKey: [...casesKeys.all, "list"] });
    },
  });
}

export type GitSyncStatus = {
  synced: boolean;
  has_remote: boolean;
  remote_url?: string | null;
  dirty_files: number;
  commits_ahead: number;
  last_commit_time?: string | null;
  last_commit_msg?: string | null;
  error?: string;
};

export function useGitStatus(caseNumber: string | undefined) {
  return useQuery({
    queryKey: [...casesKeys.all, "git-status", caseNumber ?? ""] as const,
    queryFn: ({ signal }) =>
      apiRequest<GitSyncStatus>(`/api/cases/${caseNumber}/git-status`, { signal }),
    enabled: Boolean(caseNumber),
    staleTime: 30_000,
    refetchInterval: 60_000,
  });
}

export type CreateGiteaRepoResult = {
  repo_url: string;
  clone_url: string;
  pushed: boolean;
};

export function useCreateGiteaRepo(caseNumber: string | undefined) {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: (input: { title: string; description?: string }) =>
      apiRequest<CreateGiteaRepoResult>(`/api/integrations/gitea/create-repo`, {
        method: "POST",
        body: {
          case_number: caseNumber,
          title: input.title,
          description: input.description ?? "",
        },
      }),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: [...casesKeys.all, "git-status", caseNumber ?? ""] });
    },
  });
}

export type StartWorkflowResult = {
  case_number: string;
  status: string;
  issue_id: string;
  issue_identifier: string;
  project_url: string;
  wakeup: Record<string, unknown>;
};

export function useStartWorkflow(caseNumber: string | undefined) {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: () =>
      apiRequest<StartWorkflowResult>(
        `/api/cases/${caseNumber}/start-workflow`,
        { method: "POST" },
      ),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: casesKeys.all });
      if (caseNumber) {
        qc.invalidateQueries({ queryKey: casesKeys.detail(caseNumber) });
      }
    },
  });
}

export function useWorkflowStatus(caseNumber: string | undefined) {
  return useQuery({
    queryKey: [...casesKeys.all, "workflow", caseNumber ?? ""] as const,
    queryFn: ({ signal }) =>
      apiRequest<WorkflowStatus>(`/api/cases/${caseNumber}/status`, { signal }),
    enabled: Boolean(caseNumber),
    staleTime: 5_000,
    refetchInterval: 5_000,
  });
}
