import { TimeEntry } from "@/app/api/timesheets/actions";
import { Check, Delete } from "@mui/icons-material";
import {
  Box,
  Button,
  FormControl,
  InputLabel,
  Modal,
  ModalProps,
  Paper,
  SxProps,
  TextField,
} from "@mui/material";
import React, { useCallback, useEffect, useMemo } from "react";
import { Controller, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import ProjectSelect from "./ProjectSelect";
import { AssignedProject, ProjectWithTasks } from "@/app/api/projects";
import TaskGroupSelect from "./TaskGroupSelect";
import TaskSelect from "./TaskSelect";
import { TaskGroup } from "@/app/api/tasks";
import uniqBy from "lodash/uniqBy";

export interface Props extends Omit<ModalProps, "children"> {
  onSave: (leaveEntry: TimeEntry) => void;
  onDelete?: () => void;
  defaultValues?: Partial<TimeEntry>;
  allProjects: ProjectWithTasks[];
  assignedProjects: AssignedProject[];
}

const modalSx: SxProps = {
  position: "absolute",
  top: "50%",
  left: "50%",
  transform: "translate(-50%, -50%)",
  width: "90%",
  maxHeight: "90%",
  padding: 3,
  display: "flex",
  flexDirection: "column",
  gap: 2,
};
const TimesheetEditModal: React.FC<Props> = ({
  onSave,
  onDelete,
  open,
  onClose,
  defaultValues,
  allProjects,
  assignedProjects,
}) => {
  const { t } = useTranslation("home");

  const taskGroupsByProject = useMemo(() => {
    return allProjects.reduce<{
      [projectId: AssignedProject["id"]]: {
        value: TaskGroup["id"];
        label: string;
      }[];
    }>((acc, project) => {
      return {
        ...acc,
        [project.id]: uniqBy(
          project.tasks.map((t) => ({
            value: t.taskGroup.id,
            label: t.taskGroup.name,
          })),
          "value",
        ),
      };
    }, {});
  }, [allProjects]);

  const {
    register,
    control,
    reset,
    getValues,
    setValue,
    trigger,
    formState,
    watch,
  } = useForm<TimeEntry>();

  useEffect(() => {
    reset(defaultValues ?? { id: Date.now() });
  }, [defaultValues, reset]);

  const saveHandler = useCallback(async () => {
    const valid = await trigger();
    if (valid) {
      onSave(getValues());
      reset();
    }
  }, [getValues, onSave, reset, trigger]);

  const closeHandler = useCallback<NonNullable<ModalProps["onClose"]>>(
    (...args) => {
      onClose?.(...args);
      reset();
    },
    [onClose, reset],
  );

  const projectId = watch("projectId");
  const taskGroupId = watch("taskGroupId");
  const otHours = watch("otHours");

  return (
    <Modal open={open} onClose={closeHandler}>
      <Paper sx={modalSx}>
        <FormControl fullWidth>
          <InputLabel shrink>{t("Project Code and Name")}</InputLabel>
          <Controller
            control={control}
            name="projectId"
            render={({ field }) => (
              <ProjectSelect
                allProjects={allProjects}
                assignedProjects={assignedProjects}
                value={field.value}
                onProjectSelect={(newId) => {
                  field.onChange(newId ?? null);
                  const firstTaskGroup = (
                    typeof newId === "number" ? taskGroupsByProject[newId] : []
                  )[0];

                  setValue("taskGroupId", firstTaskGroup?.value);
                  setValue("taskId", undefined);
                }}
              />
            )}
            rules={{ deps: ["taskGroupId", "taskId"] }}
          />
        </FormControl>
        <FormControl fullWidth>
          <InputLabel shrink>{t("Stage")}</InputLabel>
          <Controller
            control={control}
            name="taskGroupId"
            render={({ field }) => (
              <TaskGroupSelect
                error={Boolean(formState.errors.taskGroupId)}
                projectId={projectId}
                taskGroupsByProject={taskGroupsByProject}
                value={field.value}
                onTaskGroupSelect={(newId) => {
                  field.onChange(newId ?? null);
                }}
              />
            )}
            rules={{
              validate: (id) => {
                if (!projectId) {
                  return !id;
                }
                const taskGroups = taskGroupsByProject[projectId];
                return taskGroups.some((tg) => tg.value === id);
              },
              deps: ["taskId"],
            }}
          />
        </FormControl>
        <FormControl fullWidth>
          <InputLabel shrink>{t("Task")}</InputLabel>
          <Controller
            control={control}
            name="taskId"
            render={({ field }) => (
              <TaskSelect
                error={Boolean(formState.errors.taskId)}
                projectId={projectId}
                taskGroupId={taskGroupId}
                allProjects={allProjects}
                value={field.value}
                onTaskSelect={(newId) => {
                  field.onChange(newId ?? null);
                }}
              />
            )}
            rules={{
              validate: (id) => {
                if (!projectId) {
                  return !id;
                }
                const projectTasks = allProjects.find((p) => p.id === projectId)
                  ?.tasks;
                return Boolean(projectTasks?.some((task) => task.id === id));
              },
            }}
          />
        </FormControl>
        <TextField
          type="number"
          label={t("Hours")}
          fullWidth
          {...register("inputHours", {
            valueAsNumber: true,
            validate: (value) => Boolean(value || otHours),
          })}
          error={Boolean(formState.errors.inputHours)}
        />
        <TextField
          type="number"
          label={t("Other Hours")}
          fullWidth
          {...register("otHours", {
            valueAsNumber: true,
          })}
          error={Boolean(formState.errors.otHours)}
        />
        <TextField
          label={t("Remark")}
          fullWidth
          multiline
          rows={2}
          error={Boolean(formState.errors.remark)}
          {...register("remark", {
            validate: (value) => Boolean(projectId || value),
          })}
        />
        <Box display="flex" justifyContent="flex-end" gap={1}>
          {onDelete && (
            <Button
              variant="outlined"
              startIcon={<Delete />}
              color="error"
              onClick={onDelete}
            >
              {t("Delete")}
            </Button>
          )}
          <Button
            variant="contained"
            startIcon={<Check />}
            onClick={saveHandler}
          >
            {t("Save")}
          </Button>
        </Box>
      </Paper>
    </Modal>
  );
};

export default TimesheetEditModal;
