import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import type {
  ChecklistState,
  ReportUpsert,
  RequestApprove,
  RequestCreate,
  RequestReject,
  WorkOrderStatus,
} from '@siop/shared';
import { api, API_URL, unwrap } from './client';
import { lireJeton } from './jeton';

/** Hooks R4.2 — mêmes opérations que le web (contrat unique). Les écritures
 *  restent EN LIGNE dans cette release ; la mise en file arrive en R4.3 (D1). */

export function useWorkOrders() {
  return useQuery({
    queryKey: ['work-orders'],
    queryFn: async () => (await unwrap(await api.GET('/work-orders'))).workOrders,
  });
}

export function useWorkOrder(id: string) {
  return useQuery({
    queryKey: ['work-orders', id],
    queryFn: async () =>
      unwrap(await api.GET('/work-orders/{id}', { params: { path: { id } } })),
  });
}

export function useLocations() {
  return useQuery({
    queryKey: ['locations'],
    queryFn: async () => (await unwrap(await api.GET('/locations'))).locations,
  });
}

export function useAssets(opts?: { enabled?: boolean }) {
  return useQuery({
    queryKey: ['assets'],
    enabled: opts?.enabled ?? true,
    queryFn: async () => (await unwrap(await api.GET('/assets'))).assets,
  });
}

export function useAsset(id: string) {
  return useQuery({
    queryKey: ['assets', id],
    queryFn: async () => unwrap(await api.GET('/assets/{id}', { params: { path: { id } } })),
  });
}

export function useDocumentsOT(workOrderId: string) {
  return useQuery({
    queryKey: ['documents', workOrderId],
    queryFn: async () =>
      (
        await unwrap(
          await api.GET('/documents', { params: { query: { workOrderId } } }),
        )
      ).documents,
  });
}

export function useReferenceValues(opts?: { enabled?: boolean }) {
  return useQuery({
    queryKey: ['reference-values'],
    enabled: opts?.enabled ?? true,
    staleTime: 3600_000, // référentiels administrables : stables en journée
    queryFn: async () => (await unwrap(await api.GET('/reference-values'))).referenceValues,
  });
}

// ————— Demandes (mobile ouvert à tous les rôles) —————
// Même endpoint pour tous : l'API scope déjà « les siennes » (Demandeur) ou
// « toutes » (viewOther, ADR-003) — rien à filtrer côté app.

export function useRequests() {
  return useQuery({
    queryKey: ['requests'],
    queryFn: async () => (await unwrap(await api.GET('/requests'))).requests,
  });
}

/** Options minimales (signalement) — accessibles à tout rôle authentifié,
 *  y compris Demandeur qui n'a pas ASSETS.view (même trou corrigé qu'au web). */
export function useAssetOptions() {
  return useQuery({
    queryKey: ['asset-options'],
    queryFn: async () => (await unwrap(await api.GET('/assets/options'))).options,
  });
}

function useInvalideRequests() {
  const queryClient = useQueryClient();
  return () => queryClient.invalidateQueries({ queryKey: ['requests'] });
}

export function useCreateRequest() {
  const invalide = useInvalideRequests();
  return useMutation({
    mutationFn: async (body: RequestCreate) => unwrap(await api.POST('/requests', { body })),
    onSuccess: invalide,
  });
}

export function useApproveRequest() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: async ({ id, ...body }: RequestApprove & { id: string }) =>
      unwrap(await api.POST('/requests/{id}/approve', { params: { path: { id } }, body })),
    onSuccess: () =>
      Promise.all([
        queryClient.invalidateQueries({ queryKey: ['requests'] }),
        queryClient.invalidateQueries({ queryKey: ['work-orders'] }),
      ]),
  });
}

export function useRejectRequest() {
  const invalide = useInvalideRequests();
  return useMutation({
    mutationFn: async ({ id, ...body }: RequestReject & { id: string }) =>
      unwrap(await api.POST('/requests/{id}/reject', { params: { path: { id } }, body })),
    onSuccess: invalide,
  });
}

function useInvalideOT(id: string) {
  const queryClient = useQueryClient();
  return () =>
    Promise.all([
      queryClient.invalidateQueries({ queryKey: ['work-orders', id] }),
      queryClient.invalidateQueries({ queryKey: ['work-orders'] }),
    ]);
}

export function useTransition(id: string) {
  const invalide = useInvalideOT(id);
  return useMutation({
    mutationFn: async (input: { to: WorkOrderStatus; comment?: string }) =>
      unwrap(
        await api.POST('/work-orders/{id}/transition', {
          params: { path: { id } },
          body: input,
        }),
      ),
    onSuccess: invalide,
  });
}

export function useCocheChecklist(otId: string) {
  const invalide = useInvalideOT(otId);
  return useMutation({
    mutationFn: async (input: { itemId: string; state: ChecklistState }) =>
      unwrap(
        await api.PATCH('/work-orders/{id}/checklist/{itemId}', {
          params: { path: { id: otId, itemId: input.itemId } },
          body: { state: input.state },
        }),
      ),
    onSuccess: invalide,
  });
}

/** Suggestion R5 (D1) : l'IA est un service SERVEUR — la suggestion demande le
 *  réseau, la clôture en file R4 fonctionne sans elle. */
export function useSuggestionBilan() {
  return useMutation({
    mutationFn: async (description: string) =>
      unwrap(await api.POST('/assistant/suggest-bilan', { body: { description } })),
  });
}

/** Dictée (R5 D5, opt-in) : multipart hors client typé, même raison que la
 *  photo (D5) — le fichier natif {uri, name, type} ne passe pas par `api.*`.
 *  L'audio ne transite qu'une fois ; rien n'est stocké côté app après. */
export function useTranscription() {
  return useMutation({
    mutationFn: async (fichier: { uri: string; nom: string; mime: string }) => {
      const form = new FormData();
      form.append('file', {
        uri: fichier.uri,
        name: fichier.nom,
        type: fichier.mime,
      } as unknown as Blob);
      const jeton = await lireJeton();
      const res = await fetch(`${API_URL}/assistant/transcribe`, {
        method: 'POST',
        headers: jeton ? { Authorization: `Bearer ${jeton}` } : undefined,
        body: form,
      });
      if (!res.ok) {
        const corps = (await res.json().catch(() => null)) as { message?: string } | null;
        throw new Error(corps?.message ?? `Dictée indisponible (${res.status})`);
      }
      return (await res.json()) as { text: string };
    },
  });
}

export function useBilan(otId: string) {
  const invalide = useInvalideOT(otId);
  return useMutation({
    mutationFn: async (body: ReportUpsert) =>
      unwrap(
        await api.PUT('/work-orders/{id}/report', { params: { path: { id: otId } }, body }),
      ),
    onSuccess: invalide,
  });
}
