import { useState, useEffect, useCallback, useMemo } from 'react';
import { useTable } from '@/shared/components/table';
import {
  IAppointment,
  IAppointmentType,
  AppointmentSearchParams,
  mapBackendStatusToFront,
  mapBackendTypeToFront,
  BackendAppointmentType,
  BackendAppointmentStatus,
  CalendarEventDTO
} from '@/shared/types/appointment';
import { TableColumn } from '@/shared/types/common';
import { useAppointmentStore } from '@/shared/api/stores/hr-service/appointmentStore';

const formatDateForAPI = (date: Date): string => {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  return `${year}-${month}-${day}`;
};

export const DEFAULT_APPOINTMENT_HEAD: TableColumn[] = [
  { id: 'driverFullName', label: 'Chauffeur', type: 'text' },
  { id: 'appointmentType', label: 'Type', type: 'text' },
  { id: 'doctorName', label: 'Médecin', type: 'text' },
  { id: 'medicalCenter', label: 'Centre médical', type: 'text' },
  { id: 'appointmentStatus', label: 'Statut', type: 'status' },
  { id: 'appointmentDate', label: 'Date', type: 'date' },
  { id: 'timeSlot', label: 'Heure', type: 'text' },
  { id: '', label: 'Action' },
];

const dtoToFront = (dto: IAppointmentType): IAppointment => ({
  id: dto.id?.toString() ?? '',
  driverId: dto.driverId?.toString() ?? '',
  driverName: dto.driverFullName || `${dto.driverFirstName ?? ''} ${dto.driverLastName ?? ''}`.trim(),
  type: mapBackendTypeToFront[dto.appointmentType],
  otherType: dto.appointmentType === 'OTHER' ? dto.additionalDetails ?? '' : '',
  doctorName: dto.doctorName,
  medicalCenterName: dto.medicalCenter,
  date: dto.appointmentDate,
  time: dto.timeSlot ?? '',
  status: mapBackendStatusToFront[dto.appointmentStatus],
  comments: dto.additionalDetails,
  createdAt: dto.createdDate,
  updatedAt: dto.lastModifiedDate,
  driverFullName: dto.driverFullName,
  appointmentType: dto.appointmentType,
  medicalCenter: dto.medicalCenter,
  appointmentStatus: dto.appointmentStatus,
  appointmentDate: dto.appointmentDate,
  timeSlot: dto.timeSlot,
});

const calendarEventToFront = (dto: CalendarEventDTO): IAppointment => {
  let driverName = 'Chauffeur inconnu';

  if (dto.driverFullName) {
    driverName = dto.driverFullName;
  } else if (dto.driverFirstName || dto.driverLastName) {
    driverName = `${dto.driverFirstName ?? ''} ${dto.driverLastName ?? ''}`.trim();
  } else if (dto.driverId) {
    driverName = `Chauffeur ${dto.driverId}`;
  }

  return {
    id: dto.id?.toString() ?? '',
    driverId: dto.driverId?.toString() ?? '',
    driverName: driverName,
    type: mapBackendTypeToFront[dto.appointmentType],
    otherType: dto.appointmentType === BackendAppointmentType.OTHER ? dto.additionalDetails ?? '' : '',
    doctorName: dto.doctorName,
    medicalCenterName: dto.medicalCenter,
    date: dto.appointmentDate,
    time: dto.timeSlot ?? '',
    status: mapBackendStatusToFront[dto.appointmentStatus],
    comments: dto.additionalDetails ?? null,
    createdAt: dto.createdDate ?? new Date().toISOString(),
    updatedAt: dto.lastModifiedDate ?? new Date().toISOString(),
    driverFullName: dto.driverFullName ?? driverName,
    appointmentType: dto.appointmentType,
    medicalCenter: dto.medicalCenter,
    appointmentStatus: dto.appointmentStatus,
    appointmentDate: dto.appointmentDate,
    timeSlot: dto.timeSlot,
  };
};

export function useAppointmentTable() {
  const [params, setParams] = useState<AppointmentSearchParams>({
    page: 0,
    size: 10,
    sortBy: 'id',
    sortDirection: 'desc',
  });

  const [filters, setFilters] = useState<Record<string, { value: string; condition: string }>>({});
  const [tableHead] = useState(DEFAULT_APPOINTMENT_HEAD);

  const table = useTable({ defaultOrderBy: 'id' });

  const {
    appointments,
    totalElements,
    loading,
    fetchAppointments,
    createAppointment,
    updateAppointment,
    calendarAppointments,
    calendarLoading,
    fetchAppointmentsByDay,
    fetchAppointmentsByWeek,
    fetchAppointmentsByMonth,
    clearCalendarAppointments,
  } = useAppointmentStore();

  useEffect(() => {
    fetchAppointments(params);
  }, [params, fetchAppointments]);

  const filteredData = useMemo(
    () => appointments.map(dtoToFront),
    [appointments]
  );

  const calendarData = useMemo(() => {
    return calendarAppointments.map(dto => calendarEventToFront(dto));
  }, [calendarAppointments]);

  const fetchCalendarData = useCallback(async (viewType: string, date: Date) => {
    const timestamp = new Date().toISOString();
    const dateStr = formatDateForAPI(date);

    try {
      switch (viewType) {
        case 'timeGridDay':
          await fetchAppointmentsByDay(dateStr);
          break;

        case 'timeGridWeek': {
          const startOfWeek = new Date(date);
          const day = startOfWeek.getDay();
          const diff = startOfWeek.getDate() - day + (day === 0 ? -6 : 1);
          startOfWeek.setDate(diff);
          const startDateStr = formatDateForAPI(startOfWeek);
          await fetchAppointmentsByWeek(startDateStr);
          break;
        }

        case 'dayGridMonth': {
          const year = date.getFullYear();
          const month = date.getMonth() + 1;
          await fetchAppointmentsByMonth(year, month);
          break;
        }

        default:
          console.warn('Type de vue non géré:', viewType);
      }
    } catch (error) {
      console.error(`[${timestamp}] fetchCalendarData ERROR:`, error);
    }
  }, [fetchAppointmentsByDay, fetchAppointmentsByWeek, fetchAppointmentsByMonth]);

  const handleFilterChange = useCallback((key: string, value: string, condition: string) => {
    setFilters(prev => ({
      ...prev,
      [key]: { value, condition }
    }));
  }, []);

  const handleResetFilters = useCallback(() => {
    setFilters({});
    setParams(prev => ({
      page: 0,
      size: prev.size,
      sortBy: prev.sortBy,
      sortDirection: prev.sortDirection,
    }));
  }, []);

  const customTable = {
    ...table,
    onSort: useCallback((id: string) => {
      const isAsc = params.sortBy === id && params.sortDirection === 'asc';
      const newDirection = isAsc ? 'desc' : 'asc';

      setParams(prev => ({
        ...prev,
        sortBy: id,
        sortDirection: newDirection,
        page: 0
      }));

      table.onSort(id);
    }, [params.sortBy, params.sortDirection, table])
  };

  const onPageChange = useCallback(
    (_: React.MouseEvent<HTMLButtonElement> | null, newPage: number) =>
      setParams(prev => ({ ...prev, page: newPage })),
    []
  );

  const onRowsPerPageChange = useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      const size = parseInt(e.target.value, 10);
      if (!isNaN(size) && size > 0) {
        setParams(prev => ({ ...prev, size, page: 0 }));
      }
    },
    []
  );

  useEffect(() => {
    const mapped: AppointmentSearchParams = {
      page: 0,
      size: params.size,
      sortBy: params.sortBy,
      sortDirection: params.sortDirection,
    };

    Object.entries(filters).forEach(([key, { value }]) => {
      if (!value || value.trim() === '') return;

      switch (key) {
        case 'driverFullName':
          mapped.driverName = value;
          break;
        case 'doctorName':
          mapped.doctorName = value;
          break;
        case 'medicalCenter':
          mapped.medicalCenter = value;
          break;
        case 'appointmentStatus':
          mapped.appointmentStatus = value as any;
          break;
        case 'appointmentType':
          mapped.appointmentType = value as any;
          break;
        case 'appointmentDate':
          mapped.appointmentDate = value as string | undefined;
          break;
        default:
          if (key in mapped && value !== undefined) {
            (mapped as any)[key] = value;
          }
          break;
      }
    });

    setParams(mapped);
  }, [filters, params.size, params.sortBy, params.sortDirection]);

  const notFound = !loading && filteredData.length === 0;

  const handleSave = useCallback(async (updatedAppointment: IAppointment) => {
    try {
      let success = false;

      if (!updatedAppointment.id || updatedAppointment.id === '') {
        success = await createAppointment(updatedAppointment);
      } else {
        const appointmentId = parseInt(updatedAppointment.id);
        if (!isNaN(appointmentId)) {
          success = await updateAppointment(appointmentId, updatedAppointment);
        }
      }

      if (success) {
        await fetchAppointments(params);
      }

      return success;
    } catch (error) {
      console.error('Erreur lors de la sauvegarde:', error);
      return false;
    }
  }, [createAppointment, updateAppointment, fetchAppointments, params]);

  return {
    table: customTable,
    filteredData,
    filters,
    tableHead,
    notFound,
    handleFilterChange,
    handleResetFilters,
    handleResetColumns: () => {},
    handleColumnsChange: () => {},
    handleSave,
    totalElements,
    loading,
    page: params.page ?? 0,
    rowsPerPage: params.size ?? 10,
    onPageChange,
    onRowsPerPageChange,
    sortBy: params.sortBy,
    sortDirection: params.sortDirection,
    calendarData,
    calendarLoading,
    fetchCalendarData,
  };
}