import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import type {
  AssigneesUpdate,
  ChecklistPatch,
  MeterReadingCreate,
  PreventiveGenerate,
  ReportUpsert,
  RequestApprove,
  RequestCreate,
  RequestReject,
  TaskTemplateCreate,
  TaskTemplateUpdate,
  TransitionRequest,
  WorkOrderCreate,
} from '@siop/shared';
import { api } from './client';

/** Hooks R2 — client typé, invalidations ciblées. */

async function unwrap<T>(res: { data?: T; error?: unknown; response: Response }): Promise<T> {
  if (res.error || res.data === undefined) {
    const message =
      (res.error as { message?: string } | undefined)?.message ??
      `Le serveur a répondu ${res.response.status}`;
    throw new Error(Array.isArray(message) ? message.join(' — ') : message);
  }
  return res.data;
}

function useInvalidate(...keys: string[]) {
  const queryClient = useQueryClient();
  return () =>
    Promise.all(keys.map((key) => queryClient.invalidateQueries({ queryKey: [key] })));
}

// ————— Ordres de travail —————

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

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

export function useCreateWorkOrder() {
  const invalidate = useInvalidate('work-orders');
  return useMutation({
    mutationFn: async (body: WorkOrderCreate) =>
      unwrap(await api.POST('/work-orders', { body })),
    onSuccess: invalidate,
  });
}

export function useTransitionWorkOrder(id: string) {
  const invalidate = useInvalidate('work-orders', 'requests', 'preventive-status');
  return useMutation({
    mutationFn: async (body: TransitionRequest) =>
      unwrap(await api.POST('/work-orders/{id}/transition', { params: { path: { id } }, body })),
    onSuccess: invalidate,
  });
}

export function useCommentWorkOrder(id: string) {
  const invalidate = useInvalidate('work-orders');
  return useMutation({
    mutationFn: async (message: string) =>
      unwrap(
        await api.POST('/work-orders/{id}/comments', {
          params: { path: { id } },
          body: { message },
        }),
      ),
    onSuccess: invalidate,
  });
}

export function useSetAssignees(id: string) {
  const invalidate = useInvalidate('work-orders');
  return useMutation({
    mutationFn: async (body: AssigneesUpdate) =>
      unwrap(await api.PUT('/work-orders/{id}/assignees', { params: { path: { id } }, body })),
    onSuccess: invalidate,
  });
}

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

export function usePatchChecklist(id: string) {
  const invalidate = useInvalidate('work-orders');
  return useMutation({
    mutationFn: async ({ itemId, ...body }: ChecklistPatch & { itemId: string }) =>
      unwrap(
        await api.PATCH('/work-orders/{id}/checklist/{itemId}', {
          params: { path: { id, itemId } },
          body,
        }),
      ),
    onSuccess: invalidate,
  });
}

// ————— Demandes —————

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

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

export function useApproveRequest() {
  const invalidate = useInvalidate('requests', 'work-orders');
  return useMutation({
    mutationFn: async ({ id, ...body }: RequestApprove & { id: string }) =>
      unwrap(await api.POST('/requests/{id}/approve', { params: { path: { id } }, body })),
    onSuccess: invalidate,
  });
}

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

// ————— Référentiels du bilan —————

export function useReferenceValues() {
  return useQuery({
    queryKey: ['reference-values'],
    staleTime: 5 * 60_000,
    queryFn: async () =>
      (await unwrap(await api.GET('/reference-values'))).referenceValues,
  });
}

// ————— Préventif —————

export function useTaskTemplates() {
  return useQuery({
    queryKey: ['task-templates'],
    queryFn: async () => (await unwrap(await api.GET('/preventive/templates'))).templates,
  });
}

export function useCreateTaskTemplate() {
  const invalidate = useInvalidate('task-templates');
  return useMutation({
    mutationFn: async (body: TaskTemplateCreate) =>
      unwrap(await api.POST('/preventive/templates', { body })),
    onSuccess: invalidate,
  });
}

export function useUpdateTaskTemplate() {
  const invalidate = useInvalidate('task-templates');
  return useMutation({
    mutationFn: async ({ id, ...body }: TaskTemplateUpdate & { id: string }) =>
      unwrap(
        await api.PATCH('/preventive/templates/{id}', { params: { path: { id } }, body }),
      ),
    onSuccess: invalidate,
  });
}

export function usePreventiveStatus(enabled = true) {
  return useQuery({
    queryKey: ['preventive-status'],
    enabled,
    queryFn: async () => unwrap(await api.GET('/preventive/status')),
  });
}

export function useGeneratePreventive() {
  const invalidate = useInvalidate('preventive-status', 'work-orders');
  return useMutation({
    mutationFn: async (body: PreventiveGenerate) =>
      unwrap(await api.POST('/preventive/generate', { body })),
    onSuccess: invalidate,
  });
}

// ————— Compteurs —————

export function useMeters(assetId: string | undefined) {
  return useQuery({
    queryKey: ['meters', assetId],
    enabled: !!assetId,
    queryFn: async () =>
      (await unwrap(await api.GET('/assets/{id}/meters', { params: { path: { id: assetId! } } })))
        .meters,
  });
}

export function useAddMeterReading(assetId: string) {
  const invalidate = useInvalidate('meters');
  return useMutation({
    mutationFn: async (body: MeterReadingCreate) =>
      unwrap(
        await api.POST('/assets/{id}/meter-readings', {
          params: { path: { id: assetId } },
          body,
        }),
      ),
    onSuccess: invalidate,
  });
}
