"use client";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { apiClient } from "@/lib/api/client";
import { ApiError, type ApiErrorBody } from "@/lib/api/types";
import { randomId } from "@/lib/random-id";

export interface ComparativoSkill {
  descricao_mudou: boolean;
  matcher_mudou: boolean;
  any_adicionadas: string[];
  any_removidas: string[];
  tags_adicionadas: string[];
  tags_removidas: string[];
  corpo_mudou: boolean;
  linhas_adicionadas: number;
  linhas_removidas: number;
  mudou_em: Array<"descricao" | "matcher" | "corpo">;
  resumo: string;
}

export interface InstalledSkill {
  name: string;
  description: string;
  version_id: string;
  source: "manual" | "catalog";
  /** True quando o catálogo publicou versão nova depois da cópia da org (só p/ source 'catalog'). */
  versao_nova_catalogo: boolean;
  /** Comparativo (o que mudou) entre a cópia da org e a versão nova do catálogo; null quando não há versão nova. */
  comparativo: ComparativoSkill | null;
  updated_at: string;
}
export interface CatalogSkill {
  name: string;
  description: string;
}
export interface SkillsState {
  installed: InstalledSkill[];
  catalog: CatalogSkill[];
  /**
   * Agentes cuja versão publicada escolheu as próprias skills (9107). Uma skill
   * instalada agora NÃO chega a eles — o aviso de instalação os nomeia.
   */
  agentes_com_lista_propria: Array<{ id: string; name: string; skill_names: string[] }>;
}

export interface SkillMatcher {
  /** Ausente = skill sem ativação por palavra (#4458): só entra pelo roteiro, que puxa pelo nome. */
  any_keywords?: string[];
  probe_keywords?: string[];
  any_tags?: string[];
}

/** Corpo completo de uma skill instalada, para o editor. */
export interface SkillComCorpo {
  name: string;
  description: string;
  body: string;
  matcher: SkillMatcher;
  version_id: string;
  updated_at?: string;
  /** Skill de pacote (.zip com arquivos): o texto é editável e o PUT herda manifesto + arquivos na versão nova (#2047). */
  tem_arquivos_do_pacote?: boolean;
  /** Paths do manifesto (`references/` e `assets/`) — a UI mostra como somente leitura. */
  arquivos_do_pacote?: string[];
}

export interface SalvarSkillBody {
  description: string;
  body: string;
  matcher: SkillMatcher;
}

const KEY = ["skills"];

export function useSkills(initial?: SkillsState) {
  return useQuery({
    queryKey: KEY,
    ...(initial !== undefined ? { initialData: initial } : {}),
    queryFn: () => apiClient.get<{ data: SkillsState }>("/api/v1/ai/skills").then((r) => r.data),
  });
}

/** GET do corpo/matcher de UMA skill instalada (abre o editor). */
export function useSkill(name: string | null) {
  return useQuery({
    queryKey: ["skills", "detail", name],
    enabled: name !== null,
    queryFn: () =>
      apiClient
        .get<{ data: SkillComCorpo }>(`/api/v1/ai/skills/${encodeURIComponent(name ?? "")}`)
        .then((r) => r.data),
  });
}

export interface SkillVersionResumo {
  id: string;
  created_at: string;
  forked_from_version_id: string | null;
  atual: boolean;
}

/** GET das versões da skill (histórico para rollback). */
export function useSkillVersions(name: string | null) {
  return useQuery({
    queryKey: ["skills", "versions", name],
    enabled: name !== null,
    queryFn: () =>
      apiClient
        .get<{ data: { versions: SkillVersionResumo[] } }>(
          `/api/v1/ai/skills/${encodeURIComponent(name ?? "")}/versions`,
        )
        .then((r) => r.data.versions),
  });
}

/** POST — restaura uma versão anterior (move o ponteiro). */
export function useRestaurarSkill() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: ({ name, versionId }: { name: string; versionId: string }) =>
      apiClient.post<{ data: { name: string; version_id: string } }>(
        `/api/v1/ai/skills/${encodeURIComponent(name)}/restore`,
        { version_id: versionId },
      ),
    onSuccess: () => {
      void qc.invalidateQueries({ queryKey: KEY });
      void qc.invalidateQueries({ queryKey: ["skills", "versions"] });
      void qc.invalidateQueries({ queryKey: ["skills", "detail"] });
    },
  });
}

/** PUT — salva uma versão NOVA do corpo e move o ponteiro da organização. */
export function useSalvarSkill() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: ({ name, body }: { name: string; body: SalvarSkillBody }) =>
      apiClient.put<{ data: { name: string; version_id: string } }>(
        `/api/v1/ai/skills/${encodeURIComponent(name)}`,
        body,
      ),
    onSuccess: () => void qc.invalidateQueries({ queryKey: KEY }),
  });
}

export function useInstallSkill() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: (name: string) =>
      apiClient.post<{ data: { version_id: string } }>(`/api/v1/ai/skills/${encodeURIComponent(name)}/install`, {}),
    onSuccess: () => void qc.invalidateQueries({ queryKey: KEY }),
  });
}

export function useUninstallSkill() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: (name: string) =>
      apiClient.delete<{ data: { name: string } }>(`/api/v1/ai/skills/${encodeURIComponent(name)}`),
    onSuccess: () => void qc.invalidateQueries({ queryKey: KEY }),
  });
}

/**
 * Upload multipart — `apiClient` sempre serializa o body como JSON, então este
 * mutation faz o fetch direto (mesmo tratamento de erro do apiClient: parseia
 * `{error}` e lança ApiError, pra `showApiError` funcionar igual nos outros hooks).
 */
export function useImportSkill() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: async (file: File) => {
      const form = new FormData();
      form.append("file", file);
      const res = await fetch("/api/v1/ai/skills/import", {
        method: "POST",
        headers: { "Idempotency-Key": randomId() },
        body: form,
        credentials: "same-origin",
      });
      const text = await res.text();
      const parsed = text ? JSON.parse(text) : null;
      if (!res.ok) {
        const errBody = parsed as ApiErrorBody | null;
        const e = errBody?.error;
        throw new ApiError(
          res.status,
          e?.code ?? "unknown_error",
          e?.details,
          e?.request_id ?? randomId(),
          e?.message,
        );
      }
      return parsed as { data: { name: string; version_id: string } };
    },
    onSuccess: () => void qc.invalidateQueries({ queryKey: KEY }),
  });
}
