'use client';

import React, { useState, useCallback, useMemo, useRef, useEffect } from 'react';
import { Box, Button, Typography, GlobalStyles, Select, MenuItem } from '@mui/material';
import FullCalendar from '@fullcalendar/react';
import timeGridPlugin from '@fullcalendar/timegrid';
import dayGridPlugin from '@fullcalendar/daygrid';
import interactionPlugin from '@fullcalendar/interaction';
import frLocale from '@fullcalendar/core/locales/fr';
import { IAppointment } from '@/shared/types/appointment';
import CustomDrawer from '@/shared/components/drawer/custom-drawer';
import { ScheduleToolbar } from '../components/schedule-toolbar';
import CustomTabs from '@/shared/components/tabs/tabs-custom';
import AppointmentTable from '../components/appointment-table';
import AppointmentForm from './appointment-new-view';
import { useAppointmentTabs } from '../hooks/use-appointment-tabs';
import { useAppointmentTable } from '../hooks/use-appointment-table';
import { TableType } from '@/shared/types/common';
import { formatEventForCalendar, renderEventContent } from '../components/calendar-helpers';
import {
  CalendarGlobalStyles,
  calendarStyles,
  drawerStyles,
  calendarHeaderStyles,
  mainContainerStyles
} from '../stytles';
import { DatesSetArg } from '@fullcalendar/core/index.js';
import { AddButton } from '@/shared/components/table/styles';
import ConditionalComponent from '@/shared/components/table/ConditionalComponent';
import CustomTooltip from '@/shared/components/tooltips/tooltip-custom';
import FontAwesome from '@/shared/components/fontawesome';
import { faSquarePlus } from '@fortawesome/free-solid-svg-icons';
import { Stack } from '@mui/system';
import { UnsavedChangesDialog } from '@/shared/components/dialog/UnsavedChangesDialog';
import { useAppointmentStore } from '@/shared/api/stores/hr-service/appointmentStore';

const DRAWER_WIDTH = 580;

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

interface CalendarHeaderProps {
  currentView: string;
  onViewChange: (view: string) => void;
  onAddNew: () => void;
  currentDate: Date;
}

const CalendarHeader = ({ currentView, onViewChange, onAddNew, currentDate }: CalendarHeaderProps) => {
  const formatDate = (date: Date) => {
    const dateObj = date instanceof Date ? date : new Date(date);
    
    if (currentView === 'timeGridDay') {
      return new Intl.DateTimeFormat('fr-FR', {
        weekday: 'long',
        day: 'numeric',
        month: 'long',
        year: 'numeric'
      }).format(dateObj);
    }
    
    return new Intl.DateTimeFormat('fr-FR', {
      month: 'long',
      year: 'numeric'
    }).format(dateObj);
  };

  return (
    <Box sx={calendarHeaderStyles.container}>
      <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
        <Select
          value={currentView}
          onChange={(e) => onViewChange(e.target.value as string)}
          size="small"
          sx={calendarHeaderStyles.select}
        >
          <MenuItem value="timeGridDay">Jour</MenuItem>
          <MenuItem value="timeGridWeek">Semaine</MenuItem>
          <MenuItem value="dayGridMonth">Mois</MenuItem>
        </Select>
      </Box>

      <Typography variant="h5" sx={calendarHeaderStyles.title}>
        {formatDate(currentDate)}
      </Typography>

      <CustomTooltip title={"Ajouter Un Nouveau rendez-vous"} arrow>
        <AddButton
          onClick={onAddNew}
          variant="contained"
          endIcon={<FontAwesome icon={faSquarePlus} width={18} />}
        >
          Nouveau rendez-vous
        </AddButton>
      </CustomTooltip>
    </Box>
  );
};

export default function AppointmentView() {
  const [state, setState] = useState({
    isDrawerOpen: false,
    currentDate: new Date(),
    currentView: 'dayGridMonth',
    zoomLevel: 60,
    lastCalendarDate: new Date(),
    lastCalendarView: 'dayGridMonth',
    hasCalendarData: false,
    isCalendarInitialized: false,
    lastFetchParams: null as { viewType: string; date: string } | null,
  });

  const calendarRef = useRef<any>(null);
  const fetchTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const isFirstMount = useRef(true);

  const {
    tabs,
    activeTab,
    handleTabClose,
    handleTabChange,
    handleTabAdd,
    handleEdit,
    handleView,
    handleCancel,
    setTabHasUnsavedChanges,
    showConfirmDialog,
    setShowConfirmDialog,
    handleConfirmDialogAction,
    updateTabContent,
  } = useAppointmentTabs();

  const {
    table,
    filteredData,
    calendarData,
    calendarLoading,
    fetchCalendarData,
    filters,
    tableHead,
    notFound,
    handleFilterChange,
    handleResetFilters,
    handleSave,
    totalElements,
    loading,
    page,
    rowsPerPage,
    onPageChange,
    onRowsPerPageChange,
    sortBy,
    sortDirection,
  } = useAppointmentTable();

  const { cancelAppointment } = useAppointmentStore();

  const updateState = useCallback((updates: Partial<typeof state>) => {
    setState(prev => ({ ...prev, ...updates }));
  }, []);

  const handleDrawerToggle = useCallback(() => {
    updateState({ isDrawerOpen: !state.isDrawerOpen });
    setTimeout(() => {
      const calendarApi = calendarRef.current?.getApi();
      if (calendarApi) {
        calendarApi.updateSize();
      }
    }, 300);
  }, [state.isDrawerOpen, updateState]);

  const handleDateChange = useCallback((date: Date) => {
    updateState({ currentDate: date });
  }, [updateState]);

  const handleViewChange = useCallback((view: string) => {
    const calendarApi = calendarRef.current?.getApi();
    if (calendarApi) {
      const currentDate = calendarApi.getDate();
      const dateStr = formatDateForAPI(currentDate);
      const newParams = { viewType: view, date: dateStr };
      
      const isSameCall = state.lastFetchParams && 
        state.lastFetchParams.viewType === newParams.viewType &&
        state.lastFetchParams.date === newParams.date;
      
      calendarApi.changeView(view);
      updateState({ 
        currentView: view,
        lastFetchParams: newParams,
      });
      
      if (!isSameCall) {
        if (fetchTimeoutRef.current) {
          clearTimeout(fetchTimeoutRef.current);
        }
        
        fetchTimeoutRef.current = setTimeout(() => {
          fetchCalendarData(view, currentDate);
        }, 150);
      }
    }
  }, [updateState, fetchCalendarData, state.lastFetchParams]);

  const handleZoomChange = useCallback((zoom: number) => {
    const baseHeight = 50;
    const slotHeight = Math.max(30, Math.floor((zoom / 100) * baseHeight));
    const eventHeight = Math.max(20, Math.floor(slotHeight * 0.8));
    const fontSize = zoom < 40 ? 9 : zoom < 60 ? 11 : 12;
    const eventSpacing = Math.max(1, Math.floor(zoom / 30));

    if (calendarRef.current?.getApi()) {
      const calendarApi = calendarRef.current.getApi();
      const calendarEl = calendarApi.el;

      if (calendarEl) {
        calendarEl.style.setProperty('--fc-slot-height', `${slotHeight}px`);
        calendarEl.style.setProperty('--fc-daygrid-event-height', `${eventHeight}px`);
        calendarEl.style.setProperty('--event-font-size', `${fontSize}px`);
        calendarEl.style.setProperty('--event-spacing', `${eventSpacing}px`);

        calendarApi.updateSize();
      }
    }

    updateState({ zoomLevel: zoom });
  }, [updateState]);

  const handleNavigate = useCallback((direction: 'prev' | 'next') => {
    const calendarApi = calendarRef.current?.getApi();
    if (calendarApi) {
      if (direction === 'prev') {
        calendarApi.prev();
      } else {
        calendarApi.next();
      }
      const currentDate = calendarApi.getDate();
      const currentView = calendarApi.view.type;
      const dateStr = formatDateForAPI(currentDate);
      const newParams = { viewType: currentView, date: dateStr };
      
      updateState({ 
        currentDate: currentDate,
        lastFetchParams: newParams,
      });
    }
  }, [updateState]);

  const handleViewWithSavePosition = useCallback((appointment: IAppointment) => {
    const calendarApi = calendarRef.current?.getApi();
    if (calendarApi) {
      updateState({
        lastCalendarDate: calendarApi.getDate(),
        lastCalendarView: calendarApi.view.type
      });
    }
    
    handleView(appointment);
  }, [handleView, updateState]);

  const handleDatesSet = useCallback((arg: DatesSetArg) => {
    const calendarApi = calendarRef.current?.getApi();
    if (calendarApi) {
      const currentDate = calendarApi.getDate();
      const dateStr = formatDateForAPI(currentDate);
      const newParams = { viewType: arg.view.type, date: dateStr };
      
      const isSameCall = state.lastFetchParams && 
        state.lastFetchParams.viewType === newParams.viewType &&
        state.lastFetchParams.date === newParams.date;

      updateState({
        currentDate: currentDate,
        currentView: arg.view.type,
        hasCalendarData: true,
        isCalendarInitialized: true,
        lastFetchParams: newParams,
      });

      if (!isSameCall) {
        if (fetchTimeoutRef.current) {
          clearTimeout(fetchTimeoutRef.current);
        }
        
        fetchTimeoutRef.current = setTimeout(() => {
          fetchCalendarData(arg.view.type, currentDate);
        }, 100);
      }
    }
  }, [updateState, fetchCalendarData, state.lastFetchParams, fetchTimeoutRef]);

  const events = useMemo(() => {
    const formattedEvents = calendarData.map(appointment => {
      const event = formatEventForCalendar(appointment);
      return event;
    });
    
    return formattedEvents;
  }, [calendarData]);

  useEffect(() => {
    if (isFirstMount.current) {
      isFirstMount.current = false;
    }
  }, []);

  useEffect(() => {
    if (
      activeTab === 'list' && 
      state.lastCalendarDate && 
      state.hasCalendarData && 
      state.isCalendarInitialized &&
      state.lastCalendarView !== state.currentView
    ) {
      const calendarApi = calendarRef.current?.getApi();
      if (calendarApi) {
        calendarApi.gotoDate(state.lastCalendarDate);
        calendarApi.changeView(state.lastCalendarView);
        updateState({ 
          currentView: state.lastCalendarView,
          currentDate: state.lastCalendarDate 
        });
      }
    }
  }, [activeTab]);

  useEffect(() => {
    return () => {
      if (fetchTimeoutRef.current) {
        clearTimeout(fetchTimeoutRef.current);
      }
    };
  }, []);

  useEffect(() => {
    if (activeTab === 'list' && state.lastCalendarDate && state.hasCalendarData) {
      const calendarApi = calendarRef.current?.getApi();
      if (calendarApi) {
        calendarApi.gotoDate(state.lastCalendarDate);
        if (state.lastCalendarView !== state.currentView) {
          calendarApi.changeView(state.lastCalendarView);
          updateState({ 
            currentView: state.lastCalendarView,
            currentDate: state.lastCalendarDate 
          });
        }
        fetchCalendarData(state.lastCalendarView, state.lastCalendarDate);
      }
    }
  }, [activeTab, state.lastCalendarDate, state.lastCalendarView, state.hasCalendarData, fetchCalendarData, updateState]);

  const handleCancelAppointment = useCallback(async (appointment: IAppointment) => {
    try {
      const appointmentId = parseInt(appointment.id);
      if (isNaN(appointmentId)) {
        console.error('ID de rendez-vous invalide:', appointment.id);
        return;
      }

      const success = await cancelAppointment(appointmentId);
      
      if (success) {
        if (activeTab === 'list') {
          const calendarApi = calendarRef.current?.getApi();
          if (calendarApi) {
            const currentDate = calendarApi.getDate();
            const currentView = calendarApi.view.type;
            fetchCalendarData(currentView, currentDate);
          }
        }
      }
    } catch (error) {
      console.error('Erreur lors de l\'annulation du rendez-vous:', error);
    }
  }, [cancelAppointment, activeTab, fetchCalendarData]);

  const showTabs = useMemo(() =>
    tabs.length > 1 || activeTab !== 'list',
    [tabs.length, activeTab]
  );

  useEffect(() => {
    handleZoomChange(state.zoomLevel);
  }, [handleZoomChange, state.zoomLevel]);

  return (
    <Box sx={mainContainerStyles.root(state.isDrawerOpen, DRAWER_WIDTH)}>
      <GlobalStyles styles={CalendarGlobalStyles} />
      <ConditionalComponent isValid={activeTab === 'list'}
        defaultComponent={
          <Stack direction="row" justifyContent="flex-end" spacing={{ xs: 0.5, sm: 1 }}>
            <CustomTooltip title={"Ajouter Un Nouveau rendez-vous"} arrow>
              <AddButton
                onClick={handleTabAdd}
                variant="contained"
                endIcon={<FontAwesome icon={faSquarePlus} width={18} />}
              >
                Nouveau rendez-vous
              </AddButton>
            </CustomTooltip>
          </Stack>
        }
      >
        <ScheduleToolbar
          date={state.currentDate}
          currentView={state.currentView}
          zoom={state.zoomLevel}
          onViewChange={handleViewChange}
          onDateChange={handleDateChange}
          onZoomChange={handleZoomChange}
          onFilters={handleFilterChange}
          onResetFilters={handleResetFilters}
          onDrawerToggle={handleDrawerToggle}
          onNavigate={handleNavigate}
          tableHead={tableHead}
        />
      </ConditionalComponent>

      <CustomTabs
        type={TableType.Appointment}
        tabs={tabs}
        activeTab={activeTab}
        handleTabChange={handleTabChange}
        handleTabClose={handleTabClose}
      />
      <ConditionalComponent isValid={activeTab === 'list'} defaultComponent={
        <AppointmentForm
          key={activeTab}
          appointment={tabs.find(tab => tab.id === activeTab)?.content as IAppointment}
          mode={tabs.find(tab => tab.id === activeTab)?.mode || 'view'}
          onSave={handleSave}
          onClose={(forceClose) => handleCancel(activeTab, forceClose)}
          onEdit={handleEdit}
          updateTabContent={updateTabContent}
          tabId={activeTab}
        />
      }>
        <Box sx={calendarStyles.container}>
          <Box sx={calendarStyles.calendarWrapper}>
            <CalendarHeader
              currentView={state.currentView}
              onViewChange={handleViewChange}
              onAddNew={handleTabAdd}
              currentDate={state.currentDate}
            />

            <Box sx={calendarStyles.content}>
              <FullCalendar
                ref={calendarRef}
                plugins={[timeGridPlugin, dayGridPlugin, interactionPlugin]}
                initialView={state.currentView}
                headerToolbar={false}
                locale={frLocale}
                events={events.map(event => ({
                  ...event,
                  end: event.end ?? undefined
                }))}
                eventClick={({ event }) => handleViewWithSavePosition(event.extendedProps.appointment)}
                initialDate={state.currentDate}
                height="100%"
                handleWindowResize={false}
                stickyHeaderDates={true}
                slotDuration="00:30:00"
                slotLabelInterval="01:00"
                nowIndicator
                firstDay={1}
                allDaySlot={false}
                slotMinTime="08:00:00"
                slotMaxTime="20:00:00"
                scrollTime="08:00:00"
                datesSet={handleDatesSet}
                dayHeaderFormat={{
                  weekday: 'short',
                }}
                slotLabelFormat={{
                  hour: '2-digit',
                  minute: '2-digit',
                  hour12: false
                }}
                eventContent={renderEventContent}
                dayCellClassNames="calendar-day-cell"
                dayHeaderClassNames="calendar-header-cell"
                viewClassNames="calendar-view"
                viewDidMount={() => {
                  handleZoomChange(state.zoomLevel);
                }}
                slotEventOverlap={false}
                eventMaxStack={3}
                eventMinHeight={20}
                eventShortHeight={20}
                eventTimeFormat={{
                  hour: '2-digit',
                  minute: '2-digit',
                  hour12: false
                }}
                views={{
                  timeGridDay: {
                    eventTimeFormat: {
                      hour: '2-digit',
                      minute: '2-digit',
                      hour12: false
                    }
                  },
                  timeGridWeek: {
                    eventTimeFormat: {
                      hour: '2-digit',
                      minute: '2-digit',
                      hour12: false
                    }
                  },
                  dayGridMonth: {
                    eventTimeFormat: {
                      hour: '2-digit',
                      minute: '2-digit',
                      hour12: false
                    },
                    displayEventTime: true,
                    displayEventEnd: false
                  }
                }}
              />
            </Box>
          </Box>
        </Box>
      </ConditionalComponent>

      <CustomDrawer
        open={state.isDrawerOpen}
        onClose={handleDrawerToggle}
        drawerWidth={DRAWER_WIDTH}
      >
        <Box sx={drawerStyles.content}>
          <Typography variant="h5" sx={drawerStyles.title}>
            Liste des rendez-vous
          </Typography>

          <AppointmentTable
            filteredData={filteredData}
            table={table}
            handleView={handleView}
            tableHead={tableHead}
            notFound={notFound}
            filters={filters}
            onFilterChange={handleFilterChange}
            handleEdit={handleEdit}
            handleCancel={handleCancelAppointment}
            count={totalElements}
            page={page}
            rowsPerPage={rowsPerPage}
            onPageChange={onPageChange}
            onRowsPerPageChange={onRowsPerPageChange}
            sortBy={sortBy ?? ''}
            sortDirection={(sortDirection ?? 'asc') as 'asc' | 'desc'}
            loading={loading}
          />
        </Box>
      </CustomDrawer>
      <UnsavedChangesDialog
        open={showConfirmDialog}
        onClose={() => setShowConfirmDialog(false)}
        onConfirm={handleConfirmDialogAction}
        onCancel={() => setShowConfirmDialog(false)}
      />
    </Box>
  );
}