import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import type {
  AssetComponentCreate,
  AssetCreate,
  AssetUpdate,
  CategoryCreate,
  CategoryUpdate,
  InvitationCreate,
  LocationCreate,
  LocationUpdate,
  TeamCreate,
  UserUpdate,
} from '@siop/shared';
import { api } from './client';

/** Hooks R1 — chaque appel passe par le client typé (règle d'or). */

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;
}

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

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

/** Options minimales (signalement) — accessibles à tout rôle authentifié. */
export function useAssetOptions() {
  return useQuery({
    queryKey: ['asset-options'],
    queryFn: async () => (await unwrap(await api.GET('/assets/options'))).options,
  });
}

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

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

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

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

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

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

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

export function useUpdateLocation(id: string) {
  const invalidate = useInvalidate('locations', 'partners');
  return useMutation({
    mutationFn: async (body: LocationUpdate) =>
      unwrap(await api.PATCH('/locations/{id}', { params: { path: { id } }, body })),
    onSuccess: invalidate,
  });
}

export function useCreateAsset() {
  const invalidate = useInvalidate('assets', 'locations');
  return useMutation({
    mutationFn: async (body: AssetCreate) => unwrap(await api.POST('/assets', { body })),
    onSuccess: invalidate,
  });
}

export function useUpdateAsset(id: string) {
  const invalidate = useInvalidate('assets');
  return useMutation({
    mutationFn: async (body: AssetUpdate) =>
      unwrap(await api.PATCH('/assets/{id}', { params: { path: { id } }, body })),
    onSuccess: invalidate,
  });
}

export function useAddComponent(assetId: string) {
  const invalidate = useInvalidate('assets');
  return useMutation({
    mutationFn: async (body: AssetComponentCreate) =>
      unwrap(
        await api.POST('/assets/{id}/components', {
          params: { path: { id: assetId } },
          body,
        }),
      ),
    onSuccess: invalidate,
  });
}

export function useRemoveComponent(assetId: string) {
  const invalidate = useInvalidate('assets');
  return useMutation({
    mutationFn: async (componentId: string) => {
      const res = await api.DELETE('/assets/{id}/components/{componentId}', {
        params: { path: { id: assetId, componentId } },
      });
      if (res.response.status >= 400) throw new Error('Suppression impossible');
    },
    onSuccess: invalidate,
  });
}

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

export function useUpdateCategory() {
  const invalidate = useInvalidate('categories');
  return useMutation({
    mutationFn: async ({ id, ...body }: CategoryUpdate & { id: string }) =>
      unwrap(await api.PATCH('/categories/{id}', { params: { path: { id } }, body })),
    onSuccess: invalidate,
  });
}

export function useCreateTeam() {
  const invalidate = useInvalidate('teams', 'users');
  return useMutation({
    mutationFn: async (body: TeamCreate) => unwrap(await api.POST('/teams', { body })),
    onSuccess: invalidate,
  });
}

export function useInviteUser() {
  const invalidate = useInvalidate('users');
  return useMutation({
    mutationFn: async (body: InvitationCreate) =>
      unwrap(await api.POST('/users/invitations', { body })),
    onSuccess: invalidate,
  });
}

export function useResendInvitation() {
  const invalidate = useInvalidate('users');
  return useMutation({
    mutationFn: async (userId: string) =>
      unwrap(
        await api.POST('/users/{id}/invitation', { params: { path: { id: userId } } }),
      ),
    onSuccess: invalidate,
  });
}

export function useUpdateUser() {
  const invalidate = useInvalidate('users', 'teams');
  return useMutation({
    mutationFn: async ({ id, ...body }: UserUpdate & { id: string }) =>
      unwrap(await api.PATCH('/users/{id}', { params: { path: { id } }, body })),
    onSuccess: invalidate,
  });
}
