'use client';

import { useState, useEffect, Dispatch, SetStateAction } from 'react';
import { Box, Checkbox, Stack, Theme, Typography } from '@mui/material';
import { styled } from '@mui/material/styles';
import { DaysOfWeek, WeekType } from '@/shared/types/passenger';
import ConditionalComponent from '../table/ConditionalComponent';
import CustomTooltip from '../tooltips/tooltip-custom';
import { PeriodOfDay } from '@/shared/types/ammendment-passenger';
import { DaySchedule, WeekSchedule } from './etablissement-jours-field';
import { DayCheckbox, DayLabel } from './style';

interface TransportScheduleFieldProps {
  index?: number;
  initialSchedules?: WeekSchedule[];
  otherSchedules?: WeekSchedule[][];
  onChange: (schedules: WeekSchedule[]) => void;
  isReadOnly: boolean;
  setSharedSchedules?: Dispatch<SetStateAction<WeekSchedule[]>>;
  mode?: string;
}

export const DAYS_CONFIG = [
  { key: DaysOfWeek.MONDAY, label: 'L', fullName: 'Lundi' },
  { key: DaysOfWeek.TUESDAY, label: 'M', fullName: 'Mardi' },
  { key: DaysOfWeek.WEDNESDAY, label: 'M', fullName: 'Mercredi' },
  { key: DaysOfWeek.THURSDAY, label: 'J', fullName: 'Jeudi' },
  { key: DaysOfWeek.FRIDAY, label: 'V', fullName: 'Vendredi' },
  { key: DaysOfWeek.SATURDAY, label: 'S', fullName: 'Samedi' },
  { key: DaysOfWeek.SUNDAY, label: 'D', fullName: 'Dimanche' },
];

export const PERIODS_CONFIG = [
  { key: PeriodOfDay.MORNING, label: 'M', fullName: 'Matin' },
  { key: PeriodOfDay.EVENING, label: 'S', fullName: 'Soir' },
];

export const WEEK_TYPES = [
  { key: WeekType.EVEN, label: 'Paire', fullName: 'Semaine Paire' },
  { key: WeekType.ODD, label: 'Impaire', fullName: 'Semaine Impaire' },
];

export default function TransportScheduleField({
  initialSchedules = [],
  otherSchedules = [],
  onChange,
  isReadOnly,
  setSharedSchedules,
  mode,
  index,
}: TransportScheduleFieldProps) {
  const [schedules, setSchedules] = useState<WeekSchedule[]>(initialSchedules);
  const [evenWeekId, setEvenWeekId] = useState<string>('');
  const [oddWeekId, setOddWeekId] = useState<string>('');
  useEffect(() => {
    setSchedules(initialSchedules);
  }, [initialSchedules]);

  const isPeriodSelectedInOtherSchedules = (
    weekType: WeekType,
    dayOfWeek: DaysOfWeek,
    periodOfDay: PeriodOfDay
  ): boolean => {
    if (!otherSchedules || !Array.isArray(otherSchedules) || otherSchedules.length === 0) {
      return false;
    }

    return otherSchedules.some((otherScheduleList) => {
      if (!otherScheduleList || !Array.isArray(otherScheduleList)) {
        return false;
      }

      return otherScheduleList.some((daySchedule) => {
        if (!daySchedule || !daySchedule.schedules || !Array.isArray(daySchedule.schedules)) {
          return false;
        }

        return (
          daySchedule.weekType === weekType &&
          daySchedule.schedules.some((schedule) => {
            if (!schedule) {
              return false;
            }
            return schedule.dayOfWeek === dayOfWeek && schedule.periodOfDay === periodOfDay;
          })
        );
      });
    });
  };

  const isPeriodSelected = (
    weekType: WeekType,
    dayOfWeek: DaysOfWeek,
    periodOfDay: PeriodOfDay
  ): boolean => {
    if (!schedules || !Array.isArray(schedules)) {
      return false;
    }

    return schedules.some((daySchedule) => {
      if (!daySchedule || !daySchedule.schedules || !Array.isArray(daySchedule.schedules)) {
        return false;
      }

      return (
        daySchedule.weekType === weekType &&
        daySchedule.schedules.some((schedule) => {
          if (!schedule) {
            return false;
          }
          return schedule.dayOfWeek === dayOfWeek && schedule.periodOfDay === periodOfDay;
        })
      );
    });
  };

  const getOppositeWeekType = (weekType: WeekType): WeekType => {
    return weekType === WeekType.EVEN ? WeekType.ODD : WeekType.EVEN;
  };

  useEffect(() => {
    if (mode && mode === 'edit' && schedules.length > 0) {
      const oddIndex = schedules[0]?.weekType === WeekType.ODD ? 0 : 1;
      const evenIndex = schedules[0]?.weekType === WeekType.EVEN ? 0 : 1;
      setEvenWeekId(schedules[evenIndex]?.id);
      setOddWeekId(schedules[oddIndex]?.id);
    }
  }, []);

  const handlePeriodChange = (
    weekType: WeekType,
    dayOfWeek: DaysOfWeek,
    periodOfDay: PeriodOfDay
  ) => {
    const isCurrentlySelected = isPeriodSelected(weekType, dayOfWeek, periodOfDay);
    const isSelectedInOther = isPeriodSelectedInOtherSchedules(weekType, dayOfWeek, periodOfDay);

    if (!isCurrentlySelected && isSelectedInOther) {
      return;
    }

    let newSchedules: WeekSchedule[] = [...schedules];

    if (isCurrentlySelected) {
      newSchedules = newSchedules.map((daySchedule) => {
        if (daySchedule.weekType === weekType) {
          return {
            ...daySchedule,
            schedules: daySchedule.schedules.filter(
              (schedule) =>
                !(schedule.dayOfWeek === dayOfWeek && schedule.periodOfDay === periodOfDay)
            ),
          };
        }
        return daySchedule;
      });
      newSchedules = newSchedules.filter((daySchedule) => daySchedule.schedules.length > 0);
    } else {
      const oppositeWeek = getOppositeWeekType(weekType);
      const relatedPeriods = [PeriodOfDay.MORNING, PeriodOfDay.EVENING];

      relatedPeriods.forEach((period) => {
        const takenCurrent = isPeriodSelectedInOtherSchedules(weekType, dayOfWeek, period);
        const takenOpposite = isPeriodSelectedInOtherSchedules(oppositeWeek, dayOfWeek, period);

        if (!takenCurrent) {
          let existingDaySchedule = newSchedules.find((ds) => ds.weekType === weekType);
          if (existingDaySchedule) {
            const alreadySelected = existingDaySchedule.schedules.some(
              (s) => s.dayOfWeek === dayOfWeek && s.periodOfDay === period
            );
            if (!alreadySelected) {
              existingDaySchedule.schedules.push({ id: '', dayOfWeek, periodOfDay: period });
            }
          } else {
            newSchedules.push({
              id: '',
              weekType,
              schedules: [{ id: '', dayOfWeek, periodOfDay: period }],
            });
          }
        }

        if (!takenOpposite) {
          let existingOpposite = newSchedules.find((ds) => ds.weekType === oppositeWeek);
          if (existingOpposite) {
            const alreadySelectedOpposite = existingOpposite.schedules.some(
              (s) => s.dayOfWeek === dayOfWeek && s.periodOfDay === period
            );
            if (!alreadySelectedOpposite) {
              existingOpposite.schedules.push({ id: '', dayOfWeek, periodOfDay: period });
            }
          } else {
            newSchedules.push({
              id: '',
              weekType: oppositeWeek,
              schedules: [{ id: '', dayOfWeek, periodOfDay: period }],
            });
          }
        }
      });
    }

    const containsEven: boolean =
      newSchedules[0]?.weekType === WeekType.EVEN || newSchedules[1]?.weekType === WeekType.EVEN;
    const containsOdd: boolean =
      newSchedules[0]?.weekType === WeekType.ODD || newSchedules[1]?.weekType === WeekType.ODD;

    if (containsEven && evenWeekId) {
      const evenIndex = newSchedules[0]?.weekType === WeekType.EVEN ? 0 : 1;
      newSchedules[evenIndex].id = evenWeekId;
    }
    if (containsOdd && oddWeekId) {
      const oddIndex = newSchedules[0]?.weekType === WeekType.ODD ? 0 : 1;
      newSchedules[oddIndex].id = oddWeekId;
    }
    if (evenWeekId && oddWeekId && newSchedules.length === 0) {
      newSchedules.push(
        { id: evenWeekId, weekType: WeekType.EVEN, schedules: [] },
        { id: oddWeekId, weekType: WeekType.ODD, schedules: [] }
      );
    }
    if (evenWeekId && oddWeekId && newSchedules.length === 1) {
      const currentWeekType: WeekType = newSchedules[0].weekType;
      newSchedules.push({
        id: currentWeekType === WeekType.EVEN ? oddWeekId : evenWeekId,
        weekType: currentWeekType === WeekType.EVEN ? WeekType.ODD : WeekType.EVEN,
        schedules: [],
      });
    }

    setSchedules(newSchedules);
    onChange(newSchedules);
  };

  const handleSelectAllWeek = (weekType: WeekType, checked: boolean) => {
    let newSchedules = [...schedules];

    if (checked) {
      const schedulesToAdd: DaySchedule[] = [];

      DAYS_CONFIG.forEach((day) => {
        if (day.key === DaysOfWeek.SATURDAY || day.key === DaysOfWeek.SUNDAY) {
          return;
        }
        PERIODS_CONFIG.forEach((period) => {
          if (!isPeriodSelectedInOtherSchedules(weekType, day.key, period.key)) {
            schedulesToAdd.push({
              id: '',
              dayOfWeek: day.key,
              periodOfDay: period.key,
            });
          }
        });
      });

      if (schedulesToAdd.length > 0) {
        const existingDaySchedule = newSchedules.find((ds) => ds.weekType === weekType);

        if (existingDaySchedule) {
          existingDaySchedule.schedules = schedulesToAdd;
        } else {
          newSchedules.push({
            id: '',
            weekType,
            schedules: schedulesToAdd,
          });
        }
      }
    } else {
      newSchedules = newSchedules.filter((daySchedule) => daySchedule.weekType !== weekType);
    }
    const containsEven: boolean =
      newSchedules[0]?.weekType === WeekType.EVEN || newSchedules[1]?.weekType === WeekType.EVEN;
    const containsOdd: boolean =
      newSchedules[0]?.weekType === WeekType.ODD || newSchedules[1]?.weekType === WeekType.ODD;

    if (containsEven && evenWeekId) {
      const evenIndex = newSchedules[0]?.weekType === WeekType.EVEN ? 0 : 1;
      newSchedules[evenIndex].id = evenWeekId;
    }
    if (containsOdd && oddWeekId) {
      const oddIndex = newSchedules[0]?.weekType === WeekType.ODD ? 0 : 1;
      newSchedules[oddIndex].id = oddWeekId;
    }
    if (evenWeekId && oddWeekId && newSchedules.length === 0) {
      const emptyEvenWeek: WeekSchedule = {
        id: evenWeekId,
        weekType: WeekType.EVEN,
        schedules: [],
      };
      const emptyOddWeek: WeekSchedule = {
        id: oddWeekId,
        weekType: WeekType.ODD,
        schedules: [],
      };
      newSchedules.push(emptyEvenWeek);
      newSchedules.push(emptyOddWeek);
    }
    if (evenWeekId && oddWeekId && newSchedules.length === 1) {
      const currentWeekType: WeekType = newSchedules[0].weekType;
      if (currentWeekType === WeekType.EVEN) {
        const emptyOddWeek_: WeekSchedule = {
          id: oddWeekId,
          weekType: WeekType.ODD,
          schedules: [],
        };
        newSchedules.push(emptyOddWeek_);
      } else {
        const emptyEvenWeek_: WeekSchedule = {
          id: oddWeekId,
          weekType: WeekType.EVEN,
          schedules: [],
        };
        newSchedules.push(emptyEvenWeek_);
      }
    }
    setSchedules(newSchedules);
    onChange(newSchedules);
  };

  const isAllWeekSelected = (weekType: WeekType): boolean => {
    const availableSlots = DAYS_CONFIG.reduce((count, day) => {
      if (day.key === DaysOfWeek.SATURDAY || day.key === DaysOfWeek.SUNDAY) {
        return count;
      }
      return (
        count +
        PERIODS_CONFIG.reduce((periodCount, period) => {
          return (
            periodCount + (isPeriodSelectedInOtherSchedules(weekType, day.key, period.key) ? 0 : 1)
          );
        }, 0)
      );
    }, 0);

    const selectedSlots = schedules
      .filter((ds) => ds && ds.weekType === weekType)
      .reduce((count, ds) => {
        const nonWeekendCount = (ds.schedules || []).filter(
          (s) => s && s.dayOfWeek !== DaysOfWeek.SATURDAY && s.dayOfWeek !== DaysOfWeek.SUNDAY
        ).length;
        return count + nonWeekendCount;
      }, 0);

    return availableSlots > 0 && selectedSlots === availableSlots;
  };

  const canSelectAllWeek = (weekType: WeekType): boolean => {
    return DAYS_CONFIG.some((day) =>
      PERIODS_CONFIG.some(
        (period) => !isPeriodSelectedInOtherSchedules(weekType, day.key, period.key)
      )
    );
  };

  const renderDayPeriod = (weekType: WeekType, dayOfWeek: DaysOfWeek) => {
    const dayConfig = DAYS_CONFIG.find((d) => d.key === dayOfWeek);
    if (!dayConfig) return null;

    return (
      <Stack direction="row" spacing={0.3} alignItems="center">
        {PERIODS_CONFIG.map((period) => {
          const isSelected = isPeriodSelected(weekType, dayOfWeek, period.key);
          const isDisabledByOther = isPeriodSelectedInOtherSchedules(
            weekType,
            dayOfWeek,
            period.key
          );
          const isDisabled = isReadOnly || (!isSelected && isDisabledByOther);

          const checkbox = (
            <Box sx={{ position: 'relative' }}>
              <DayCheckbox
                disabled={isDisabled}
                checked={isSelected}
                onChange={() => handlePeriodChange(weekType, dayOfWeek, period.key)}
                size="small"
              />
              <DayLabel
                sx={{
                  color: isSelected
                    ? (theme: Theme) => theme.palette.primary.contrastText
                    : 'inherit',
                }}
              >
                {`${dayConfig.label}${period.label}`}
              </DayLabel>
            </Box>
          );

          return (
            <ConditionalComponent
              key={period.key}
              isValid={isDisabledByOther && !isReadOnly}
              defaultComponent={checkbox}
            >
              <CustomTooltip
                arrow
                colorSchema="warning"
                title="Cette période est déjà sélectionnée dans un autre établissement"
              >
                {checkbox}
              </CustomTooltip>
            </ConditionalComponent>
          );
        })}
      </Stack>
    );
  };


  useEffect(() => {
    if (index !== undefined && index === 0 && setSharedSchedules) {
      setSharedSchedules(schedules);
    }
  }, [schedules]);

  return (
    <Stack spacing={1.5}>
      {WEEK_TYPES.map((weekType) => (
        <Box key={weekType.key}>
          <Stack direction="row" alignItems="center" spacing={1}>
            <Stack direction="row" alignItems="center" spacing={0.5}>
              <ConditionalComponent
                isValid={!(canSelectAllWeek(weekType.key) || isReadOnly)}
                defaultComponent={
                  <Checkbox
                    sx={{ p: 0 }}
                    disabled={isReadOnly}
                    checked={isAllWeekSelected(weekType.key)}
                    onChange={(e) => handleSelectAllWeek(weekType.key, e.target.checked)}
                    size="small"
                  />
                }
              >
                <CustomTooltip
                  arrow
                  colorSchema="warning"
                  title="Certaines périodes sont déjà sélectionnées dans d'autres établissements"
                >
                  <span>
                    <Checkbox
                      sx={{ p: 0 }}
                      disabled={true}
                      checked={isAllWeekSelected(weekType.key)}
                      size="small"
                    />
                  </span>
                </CustomTooltip>
              </ConditionalComponent>
              <Typography sx={{ fontSize: '10px', minWidth: 40, textAlign: 'left' }}>
                {weekType.label}
              </Typography>
            </Stack>
            <Stack direction="row" spacing={1} justifyContent="space-between" flexGrow={1}>
              {DAYS_CONFIG.map((day) => (
                <Box key={`${weekType.key}-${day.key}`}>
                  {renderDayPeriod(weekType.key, day.key)}
                </Box>
              ))}
            </Stack>
          </Stack>
        </Box>
      ))}
    </Stack>
  );
}
