/**
 * React Query Hooks - Availability
 * Hooks para gerenciamento de disponibilidade com cache inteligente
 * @version 1.0
 */

import {
  useQuery,
  useMutation,
  useQueryClient,
  UseQueryOptions,
} from "@tanstack/react-query";
import { availabilityService } from "../services";
import type {
  DoctorAvailability,
  CreateAvailabilityInput,
  UpdateAvailabilityInput,
} from "../services/availability/types";
import toast from "react-hot-toast";

// ============================================================================
// QUERY KEYS
// ============================================================================

export const availabilityKeys = {
  all: ["availability"] as const,
  lists: () => [...availabilityKeys.all, "list"] as const,
  list: (doctorId?: string) => [...availabilityKeys.lists(), doctorId] as const,
  details: () => [...availabilityKeys.all, "detail"] as const,
  detail: (id: string) => [...availabilityKeys.details(), id] as const,
  slots: (doctorId: string, date: string) =>
    [...availabilityKeys.all, "slots", doctorId, date] as const,
};

// ============================================================================
// QUERY HOOKS
// ============================================================================

/**
 * Hook para buscar disponibilidade de um médico
 */
export function useAvailability(
  doctorId: string | undefined,
  options?: Omit<UseQueryOptions<DoctorAvailability[]>, "queryKey" | "queryFn">
) {
  return useQuery({
    queryKey: availabilityKeys.list(doctorId),
    queryFn: async () => {
      if (!doctorId) throw new Error("Doctor ID é obrigatório");
      return await availabilityService.list({ doctor_id: doctorId });
    },
    enabled: !!doctorId,
    ...options,
  });
}

/**
 * Hook para buscar uma disponibilidade específica
 */
export function useAvailabilityById(id: string | undefined) {
  return useQuery({
    queryKey: availabilityKeys.detail(id!),
    queryFn: async () => {
      if (!id) throw new Error("ID é obrigatório");
      const items = await availabilityService.list();
      const found = items.find((item) => item.id === id);
      if (!found) throw new Error("Disponibilidade não encontrada");
      return found;
    },
    enabled: !!id,
  });
}

/**
 * Hook para buscar slots disponíveis de um médico em uma data
 */
export function useAvailableSlots(
  doctorId: string | undefined,
  date: string | undefined,
  options?: Omit<UseQueryOptions<string[]>, "queryKey" | "queryFn">
) {
  return useQuery({
    queryKey: availabilityKeys.slots(doctorId!, date!),
    queryFn: async () => {
      if (!doctorId || !date)
        throw new Error("Doctor ID e Data são obrigatórios");

      // Buscar disponibilidade do médico
      const availabilities = await availabilityService.list({
        doctor_id: doctorId,
      });

      // Buscar consultas do dia
      const { appointmentService } = await import("../services");
      const appointments = await appointmentService.list({
        doctor_id: doctorId,
        scheduled_at: `gte.${date}T00:00:00,lt.${date}T23:59:59`,
      });

      // Calcular slots livres (simplificado - usar lógica completa do AvailableSlotsPicker)
      const occupiedSlots = new Set(
        appointments.map((a) => a.scheduled_at.substring(11, 16))
      );

      const dayOfWeek = new Date(date).getDay();
      const dayAvailability = availabilities.filter(
        (av) => av.weekday === dayOfWeek
      );

      const freeSlots: string[] = [];
      dayAvailability.forEach((av) => {
        const start = parseInt(av.start_time.replace(":", ""));
        const end = parseInt(av.end_time.replace(":", ""));
        const slotMinutes = av.slot_minutes || 30;
        const increment = (slotMinutes / 60) * 100;

        for (let time = start; time < end; time += increment) {
          const hour = Math.floor(time / 100);
          const minute = time % 100;
          const timeStr = `${hour.toString().padStart(2, "0")}:${minute
            .toString()
            .padStart(2, "0")}`;

          if (!occupiedSlots.has(timeStr)) {
            freeSlots.push(timeStr);
          }
        }
      });

      return freeSlots.sort();
    },
    enabled: !!doctorId && !!date,
    staleTime: 2 * 60 * 1000, // 2 minutos - slots mudam frequentemente
    ...options,
  });
}

// ============================================================================
// MUTATION HOOKS
// ============================================================================

/**
 * Hook para criar nova disponibilidade
 */
export function useCreateAvailability() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (data: CreateAvailabilityInput) => {
      return await availabilityService.create(data);
    },
    onSuccess: (data) => {
      // Invalidar listas de disponibilidade
      queryClient.invalidateQueries({ queryKey: availabilityKeys.lists() });

      if (data?.doctor_id) {
        queryClient.invalidateQueries({
          queryKey: availabilityKeys.list(data.doctor_id),
        });
      }

      toast.success("Disponibilidade criada com sucesso!");
    },
    onError: (error: Error) => {
      toast.error(`Erro ao criar disponibilidade: ${error.message}`);
    },
  });
}

/**
 * Hook para atualizar disponibilidade
 */
export function useUpdateAvailability() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (data: UpdateAvailabilityInput & { id: string }) => {
      return await availabilityService.update(data.id, data);
    },
    onMutate: async (variables) => {
      // Optimistic update
      await queryClient.cancelQueries({
        queryKey: availabilityKeys.detail(variables.id),
      });

      const previousAvailability = queryClient.getQueryData<DoctorAvailability>(
        availabilityKeys.detail(variables.id)
      );

      return { previousAvailability };
    },
    onSuccess: (data, variables) => {
      queryClient.invalidateQueries({ queryKey: availabilityKeys.lists() });
      queryClient.invalidateQueries({
        queryKey: availabilityKeys.detail(variables.id),
      });

      if (data?.doctor_id) {
        queryClient.invalidateQueries({
          queryKey: availabilityKeys.list(data.doctor_id),
        });
      }

      toast.success("Disponibilidade atualizada com sucesso!");
    },
    onError: (error: Error, variables, context) => {
      if (context?.previousAvailability) {
        queryClient.setQueryData(
          availabilityKeys.detail(variables.id),
          context.previousAvailability
        );
      }
      toast.error(`Erro ao atualizar: ${error.message}`);
    },
  });
}

/**
 * Hook para deletar disponibilidade
 */
export function useDeleteAvailability() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({ id }: { id: string; doctorId: string }) => {
      return await availabilityService.delete(id);
    },
    onSuccess: (_, variables) => {
      queryClient.invalidateQueries({ queryKey: availabilityKeys.lists() });
      queryClient.invalidateQueries({
        queryKey: availabilityKeys.list(variables.doctorId),
      });

      toast.success("Disponibilidade removida com sucesso");
    },
    onError: (error: Error) => {
      toast.error(`Erro ao remover: ${error.message}`);
    },
  });
}

// ============================================================================
// UTILITY HOOKS
// ============================================================================

/**
 * Hook para prefetch de disponibilidade (otimização)
 */
export function usePrefetchAvailability() {
  const queryClient = useQueryClient();

  return (doctorId: string) => {
    queryClient.prefetchQuery({
      queryKey: availabilityKeys.list(doctorId),
      queryFn: async () => {
        return await availabilityService.list({ doctor_id: doctorId });
      },
    });
  };
}

/**
 * Hook para prefetch de slots disponíveis (navegação de calendário)
 */
export function usePrefetchAvailableSlots() {
  const queryClient = useQueryClient();

  return (doctorId: string, date: string) => {
    queryClient.prefetchQuery({
      queryKey: availabilityKeys.slots(doctorId, date),
      queryFn: async () => {
        await availabilityService.list({ doctor_id: doctorId });
        // Lógica simplificada - ver hook useAvailableSlots para implementação completa
        return [];
      },
    });
  };
}
