import { useState, useEffect } from "react";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { format, startOfMonth, endOfMonth, eachDayOfInterval, isBefore, startOfDay, addMonths, subMonths, getDay } from "date-fns";
import { ptBR } from "date-fns/locale";
import { availabilityService, appointmentService } from "../../services";
import type { DoctorAvailability, DoctorException } from "../../services";

interface CalendarPickerProps {
  doctorId: string;
  selectedDate?: string;
  onSelectDate: (date: string) => void;
}

interface DayStatus {
  date: Date;
  available: boolean; // Tem horários disponíveis
  hasAvailability: boolean; // Médico trabalha neste dia da semana
  hasBlockException: boolean; // Dia bloqueado por exceção
  isPast: boolean; // Data já passou
}

export function CalendarPicker({ doctorId, selectedDate, onSelectDate }: CalendarPickerProps) {
  const [currentMonth, setCurrentMonth] = useState(new Date());
  const [availabilities, setAvailabilities] = useState<DoctorAvailability[]>([]);
  const [exceptions, setExceptions] = useState<DoctorException[]>([]);
  const [loading, setLoading] = useState(false);
  const [availableSlots, setAvailableSlots] = useState<Record<string, boolean>>({});

  // Carregar disponibilidades e exceções do médico
  useEffect(() => {
    if (!doctorId) return;
    
    const loadData = async () => {
      setLoading(true);
      try {
        const [availData, exceptData] = await Promise.all([
          availabilityService.list({ doctor_id: doctorId, active: true }),
          availabilityService.listExceptions({ doctor_id: doctorId }),
        ]);
        
        setAvailabilities(Array.isArray(availData) ? availData : []);
        setExceptions(Array.isArray(exceptData) ? exceptData : []);
      } catch (error) {
        console.error("Erro ao carregar dados do calendário:", error);
      } finally {
        setLoading(false);
      }
    };

    loadData();
  }, [doctorId, currentMonth]);

  // Calcular disponibilidade de slots localmente (sem chamar Edge Function)
  useEffect(() => {
    if (!doctorId || availabilities.length === 0) return;

    const checkAvailableSlots = async () => {
      const start = startOfMonth(currentMonth);
      const end = endOfMonth(currentMonth);
      const days = eachDayOfInterval({ start, end });

      const slotsMap: Record<string, boolean> = {};

      // Verificar apenas dias futuros que têm configuração de disponibilidade
      const today = startOfDay(new Date());
      const daysToCheck = days.filter((day) => {
        const dayOfWeek = getDay(day); // 0-6
        const hasConfig = availabilities.some((a) => a.weekday === dayOfWeek);
        return !isBefore(day, today) && hasConfig;
      });

      // Buscar todos os agendamentos do médico uma vez só
      let allAppointments: Array<{ scheduled_at: string; status: string }> = [];
      try {
        const appointments = await appointmentService.list({ doctor_id: doctorId });
        allAppointments = Array.isArray(appointments) ? appointments : [];
      } catch (error) {
        console.error("[CalendarPicker] Erro ao buscar agendamentos:", error);
      }

      // Calcular slots para cada dia
      for (const day of daysToCheck) {
        try {
          const dateStr = format(day, "yyyy-MM-dd");
          const dayOfWeek = getDay(day);

          // Filtra disponibilidades para o dia da semana
          const dayAvailability = availabilities.filter(
            (avail) => avail.weekday === dayOfWeek && avail.active
          );

          if (dayAvailability.length === 0) {
            slotsMap[dateStr] = false;
            continue;
          }

          // Verifica se há exceção de bloqueio
          const hasBlockException = exceptions.some(
            (exc) => exc.date === dateStr && exc.kind === "bloqueio"
          );

          if (hasBlockException) {
            slotsMap[dateStr] = false;
            continue;
          }

          // Gera todos os slots possíveis
          const allSlots: string[] = [];
          for (const avail of dayAvailability) {
            const startTime = avail.start_time;
            const endTime = avail.end_time;
            const slotMinutes = avail.slot_minutes || 30;

            const [startHour, startMin] = startTime.split(":").map(Number);
            const [endHour, endMin] = endTime.split(":").map(Number);

            let currentMinutes = startHour * 60 + startMin;
            const endMinutes = endHour * 60 + endMin;

            while (currentMinutes < endMinutes) {
              const hours = Math.floor(currentMinutes / 60);
              const minutes = currentMinutes % 60;
              const timeStr = `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
              allSlots.push(timeStr);
              currentMinutes += slotMinutes;
            }
          }

          // Filtra agendamentos já ocupados para esta data
          const bookedSlots = allAppointments
            .filter((apt) => {
              if (!apt.scheduled_at) return false;
              const aptDate = new Date(apt.scheduled_at);
              return (
                format(aptDate, "yyyy-MM-dd") === dateStr &&
                apt.status !== "cancelled" &&
                apt.status !== "no_show"
              );
            })
            .map((apt) => {
              const aptDate = new Date(apt.scheduled_at);
              return format(aptDate, "HH:mm");
            });

          // Verifica se há pelo menos um slot disponível
          const availableSlots = allSlots.filter((slot) => !bookedSlots.includes(slot));
          slotsMap[dateStr] = availableSlots.length > 0;

        } catch (error) {
          console.error(`[CalendarPicker] Erro ao verificar slots para ${format(day, "yyyy-MM-dd")}:`, error);
          slotsMap[format(day, "yyyy-MM-dd")] = false;
        }
      }

      setAvailableSlots(slotsMap);
    };

    checkAvailableSlots();
  }, [doctorId, currentMonth, availabilities, exceptions]);

  const getDayStatus = (date: Date): DayStatus => {
    const today = startOfDay(new Date());
    const isPast = isBefore(date, today);
    const dayOfWeek = getDay(date); // 0-6 (domingo-sábado)
    const dateStr = format(date, "yyyy-MM-dd");

    // Verifica se há exceção de bloqueio para este dia
    const hasBlockException = exceptions.some(
      (exc) => exc.date === dateStr && exc.kind === "bloqueio"
    );

    // Verifica se médico trabalha neste dia da semana
    const hasAvailability = availabilities.some((a) => a.weekday === dayOfWeek);

    // Verifica se há slots disponíveis (baseado na verificação assíncrona)
    const available = availableSlots[dateStr] === true;

    return {
      date,
      available,
      hasAvailability,
      hasBlockException,
      isPast,
    };
  };

  const getDayClasses = (status: DayStatus, isSelected: boolean): string => {
    const base = "w-10 h-10 rounded-full flex items-center justify-center text-sm font-medium transition-colors";

    if (isSelected) {
      return `${base} bg-blue-600 text-white ring-2 ring-blue-400`;
    }

    if (status.isPast) {
      return `${base} bg-gray-100 text-gray-400 cursor-not-allowed`;
    }

    if (status.hasBlockException) {
      return `${base} bg-red-100 text-red-700 cursor-not-allowed`;
    }

    if (status.available) {
      return `${base} bg-blue-100 text-blue-700 hover:bg-blue-200 cursor-pointer`;
    }

    if (status.hasAvailability) {
      return `${base} bg-gray-50 text-gray-600 hover:bg-gray-100 cursor-pointer`;
    }

    return `${base} bg-white text-gray-400 cursor-not-allowed`;
  };

  const handlePrevMonth = () => {
    setCurrentMonth(subMonths(currentMonth, 1));
  };

  const handleNextMonth = () => {
    setCurrentMonth(addMonths(currentMonth, 1));
  };

  const handleDayClick = (date: Date, status: DayStatus) => {
    if (status.isPast || status.hasBlockException) return;
    if (!status.hasAvailability && !status.available) return;

    const dateStr = format(date, "yyyy-MM-dd");
    onSelectDate(dateStr);
  };

  const renderCalendar = () => {
    const start = startOfMonth(currentMonth);
    const end = endOfMonth(currentMonth);
    const days = eachDayOfInterval({ start, end });

    // Preencher dias do início (para alinhar o primeiro dia da semana)
    const startDayOfWeek = getDay(start);
    const emptyDays = Array(startDayOfWeek).fill(null);

    const allDays = [...emptyDays, ...days];

    return (
      <div className="grid grid-cols-7 gap-1">
        {/* Cabeçalho dos dias da semana */}
        {["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"].map((day) => (
          <div key={day} className="text-center text-xs font-semibold text-gray-600 py-2">
            {day}
          </div>
        ))}

        {/* Dias do mês */}
        {allDays.map((day, index) => {
          if (!day) {
            return <div key={`empty-${index}`} className="w-10 h-10" />;
          }

          const status = getDayStatus(day);
          const isSelected = selectedDate === format(day, "yyyy-MM-dd");
          const classes = getDayClasses(status, isSelected);

          return (
            <div key={format(day, "yyyy-MM-dd")} className="flex justify-center">
              <button
                type="button"
                onClick={() => handleDayClick(day, status)}
                disabled={status.isPast || status.hasBlockException || (!status.hasAvailability && !status.available)}
                className={classes}
                title={
                  status.isPast
                    ? "Data passada"
                    : status.hasBlockException
                    ? "Dia bloqueado"
                    : status.available
                    ? "Horários disponíveis"
                    : status.hasAvailability
                    ? "Verificando disponibilidade..."
                    : "Médico não trabalha neste dia"
                }
              >
                {format(day, "d")}
              </button>
            </div>
          );
        })}
      </div>
    );
  };

  return (
    <div className="bg-white rounded-lg border border-gray-200 p-4">
      {/* Navegação do mês */}
      <div className="flex items-center justify-between mb-4">
        <button
          type="button"
          onClick={handlePrevMonth}
          className="p-2 hover:bg-gray-100 rounded-full transition-colors"
        >
          <ChevronLeft className="w-5 h-5 text-gray-600" />
        </button>

        <h3 className="text-lg font-semibold text-gray-800 capitalize">
          {format(currentMonth, "MMMM yyyy", { locale: ptBR })}
        </h3>

        <button
          type="button"
          onClick={handleNextMonth}
          className="p-2 hover:bg-gray-100 rounded-full transition-colors"
        >
          <ChevronRight className="w-5 h-5 text-gray-600" />
        </button>
      </div>

      {loading ? (
        <div className="flex justify-center items-center py-10">
          <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
        </div>
      ) : (
        <>
          {renderCalendar()}

          {/* Legenda */}
          <div className="mt-4 pt-4 border-t border-gray-200 grid grid-cols-2 gap-2 text-xs">
            <div className="flex items-center gap-2">
              <div className="w-4 h-4 rounded bg-blue-100"></div>
              <span className="text-gray-600">Disponível</span>
            </div>
            <div className="flex items-center gap-2">
              <div className="w-4 h-4 rounded bg-red-100"></div>
              <span className="text-gray-600">Bloqueado</span>
            </div>
            <div className="flex items-center gap-2">
              <div className="w-4 h-4 rounded bg-gray-100"></div>
              <span className="text-gray-600">Data passada</span>
            </div>
            <div className="flex items-center gap-2">
              <div className="w-4 h-4 rounded bg-gray-50"></div>
              <span className="text-gray-600">Sem horários</span>
            </div>
          </div>
        </>
      )}
    </div>
  );
}
