import React, { useCallback, useEffect, useMemo } from "react";
import {
  Box,
  Button,
  Card,
  CardActions,
  CardContent,
  Modal,
  ModalProps,
  SxProps,
  Typography,
} from "@mui/material";
import { useTranslation } from "react-i18next";
import { Check, Close } from "@mui/icons-material";
import { FormProvider, SubmitHandler, useForm } from "react-hook-form";
import {
  LeaveEntry,
  RecordLeaveInput,
  RecordTimeLeaveInput,
  RecordTimesheetInput,
  saveTimeLeave,
} from "@/app/api/timesheets/actions";
import dayjs, { Dayjs } from "dayjs";
import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
import { AssignedProject, ProjectWithTasks } from "@/app/api/projects";
import FullscreenModal from "../FullscreenModal";
import useIsMobile from "@/app/utils/useIsMobile";
import { HolidaysResult } from "@/app/api/holidays";
import {
  DAILY_NORMAL_MAX_HOURS,
  TIMESHEET_DAILY_MAX_HOURS,
  validateTimeLeaveRecord,
} from "@/app/api/timesheets/utils";
import ErrorAlert from "../ErrorAlert";
import { LeaveType } from "@/app/api/timesheets";
import DateHoursTable from "../DateHoursTable";
import mapValues from "lodash/mapValues";
import DateHoursList from "../DateHoursTable/DateHoursList";
import TimeLeaveInputTable from "./TimeLeaveInputTable";
import TimeLeaveMobileEntry from "./TimeLeaveMobileEntry";
import { Task } from "@/app/api/tasks";
import waitForCondition from "../utils/waitFor";

interface Props {
  isOpen: boolean;
  onClose: () => void;
  allProjects: ProjectWithTasks[];
  assignedProjects: AssignedProject[];
  timesheetRecords: RecordTimesheetInput;
  leaveRecords: RecordLeaveInput;
  companyHolidays: HolidaysResult[];
  fastEntryEnabled?: boolean;
  leaveTypes: LeaveType[];
  isFullTime: boolean;
  joinDate: Dayjs;
  miscTasks: Task[];
  isSaturdayWorker: boolean
}

const modalSx: SxProps = {
  position: "absolute",
  top: "50%",
  left: "50%",
  transform: "translate(-50%, -50%)",
  width: { xs: "calc(100% - 2rem)", sm: "90%" },
  maxHeight: "90%",
  maxWidth: 1400,
};

const DAYS_TO_SHOW = 10;

const TimeLeaveModal: React.FC<Props> = ({
  isOpen,
  onClose,
  allProjects,
  assignedProjects,
  timesheetRecords,
  leaveRecords,
  companyHolidays,
  fastEntryEnabled,
  leaveTypes,
  isFullTime,
  joinDate,
  miscTasks,
  isSaturdayWorker,
}) => {
  const { t } = useTranslation("home");

  const defaultValues = useMemo(() => {
    const today = dayjs();
    return Array(DAYS_TO_SHOW)
      .fill(undefined)
      .reduce<RecordTimeLeaveInput>((acc, _, index) => {
        const date = today.subtract(index, "day").format(INPUT_DATE_FORMAT);
        const defaultTimesheets = timesheetRecords[date] ?? [];
        const defaultLeaveRecords = leaveRecords[date] ?? [];

        return {
          ...acc,
          [date]: [
            ...defaultTimesheets.map((t) => ({
              type: "timeEntry" as const,
              ...t,
            })),
            ...defaultLeaveRecords.map((l) => ({
              type: "leaveEntry" as const,
              ...l,
            })),
          ],
        };
      }, {});
  }, [leaveRecords, timesheetRecords]);

  const formProps = useForm<RecordTimeLeaveInput>({ defaultValues });
  useEffect(() => {
    formProps.reset(defaultValues);
  }, [defaultValues, formProps]);

  const onSubmit = useCallback<SubmitHandler<RecordTimeLeaveInput>>(
    async (data) => {
      const errors = validateTimeLeaveRecord(
        data,
        companyHolidays,
        isFullTime,
        joinDate,
      );
      if (errors) {
        Object.keys(errors).forEach((date) =>
          formProps.setError(date, {
            message: errors[date],
          }),
        );
        return;
      }
      const savedRecords = await saveTimeLeave(data);

      const today = dayjs();
      const newFormValues = Array(DAYS_TO_SHOW)
        .fill(undefined)
        .reduce<RecordTimeLeaveInput>((acc, _, index) => {
          const date = today.subtract(index, "day").format(INPUT_DATE_FORMAT);
          return {
            ...acc,
            [date]: savedRecords[date] ?? [],
          };
        }, {});

      formProps.reset(newFormValues);
      onClose();
    },
    [companyHolidays, isFullTime, joinDate, formProps, onClose],
  );

  const onCancel = useCallback(() => {
    formProps.reset(defaultValues);
    onClose();
  }, [defaultValues, formProps, onClose]);

  const onModalClose = useCallback<NonNullable<ModalProps["onClose"]>>(
    (_, reason) => {
      if (reason !== "backdropClick") {
        onClose();
      }
    },
    [onClose],
  );

  const errorComponent = (
    <ErrorAlert
      errors={Object.keys(formProps.formState.errors).map((date) => {
        const error = formProps.formState.errors[date]?.message;
        return error
          ? `${date}: ${t(error, {
              TIMESHEET_DAILY_MAX_HOURS,
              DAILY_NORMAL_MAX_HOURS,
            })}`
          : undefined;
      })}
    />
  );

  const currentValue = formProps.watch();
  const currentDays = Object.keys(currentValue);
  const currentTimeEntries: RecordTimesheetInput = mapValues(
    currentValue,
    (timeLeaveEntries) =>
      timeLeaveEntries.filter((entry) => entry.type === "timeEntry"),
  );
  const currentLeaveEntries: RecordLeaveInput = mapValues(
    currentValue,
    (timeLeaveEntries) =>
      timeLeaveEntries.filter(
        (entry): entry is LeaveEntry & { type: "leaveEntry" } =>
          entry.type === "leaveEntry",
      ),
  );

  const matches = useIsMobile();

  return (
    <FormProvider {...formProps}>
      {!matches ? (
        // Desktop version
        <Modal open={isOpen} onClose={onModalClose}>
          <Card sx={modalSx}>
            <CardContent
              component="form"
              onSubmit={formProps.handleSubmit(onSubmit)}
            >
              <Typography variant="overline" display="block" marginBlockEnd={1}>
                {t("Timesheet Input")}
              </Typography>
              <Box
                sx={{
                  marginInline: -3,
                  marginBlock: 4,
                }}
              >
                <DateHoursTable
                  companyHolidays={companyHolidays}
                  days={currentDays}
                  leaveEntries={currentLeaveEntries}
                  timesheetEntries={currentTimeEntries}
                  EntryTableComponent={TimeLeaveInputTable}
                  entryTableProps={{
                    assignedProjects,
                    allProjects,
                    fastEntryEnabled,
                    leaveTypes,
                    miscTasks,
                  }}
                  isSaturdayWorker={isSaturdayWorker}
                />
              </Box>
              {errorComponent}
              <CardActions sx={{ justifyContent: "flex-end" }}>
                <Button
                  variant="outlined"
                  startIcon={<Close />}
                  onClick={onCancel}
                >
                  {t("Cancel")}
                </Button>
                <Button
                  variant="contained"
                  startIcon={<Check />}
                  onClick={async () => {
                    await waitForCondition(async () => {
                      return !Object.values(formProps.formState.errors).some(
                        (err) => err?.type === "custom",
                      );
                    });
                    formProps.clearErrors();
                    formProps.handleSubmit(onSubmit)();
                  }}
                >
                  {t("Save")}
                </Button>
              </CardActions>
            </CardContent>
          </Card>
        </Modal>
      ) : (
        // Mobile version
        <FullscreenModal
          open={isOpen}
          onClose={onModalClose}
          closeModal={onCancel}
        >
          <Box
            display="flex"
            flexDirection="column"
            gap={2}
            height="100%"
            component="form"
            onSubmit={formProps.handleSubmit(onSubmit)}
          >
            <Typography variant="h6" padding={2} flex="none">
              {t("Timesheet Input")}
            </Typography>
            <DateHoursList
              days={currentDays}
              companyHolidays={companyHolidays}
              leaveEntries={currentLeaveEntries}
              timesheetEntries={currentTimeEntries}
              EntryComponent={TimeLeaveMobileEntry}
              entryComponentProps={{
                allProjects,
                assignedProjects,
                companyHolidays,
                fastEntryEnabled,
                leaveTypes,
                miscTasks,
              }}
              errorComponent={errorComponent}
              onSubmit={() => {
                formProps.clearErrors();
              }}
            />
          </Box>
        </FullscreenModal>
      )}
    </FormProvider>
  );
};

export default TimeLeaveModal;
