"use client";

import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent";
import Grid from "@mui/material/Grid";
import Typography from "@mui/material/Typography";
import { useTranslation } from "react-i18next";
import TransferList from "../TransferList";
import Button from "@mui/material/Button";
import React, { SyntheticEvent, useCallback, useMemo, useState } from "react";
import CardActions from "@mui/material/CardActions";
import RestartAlt from "@mui/icons-material/RestartAlt";
import FormControl from "@mui/material/FormControl";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
import InputLabel from "@mui/material/InputLabel";
import { Task, TaskTemplate } from "@/app/api/tasks";
import { useFormContext } from "react-hook-form";
import { CreateProjectInputs, ManhourAllocation } from "@/app/api/projects/actions";
import isNumber from "lodash/isNumber";
import intersectionWith from "lodash/intersectionWith";
import { difference } from "lodash";
import { Autocomplete, TextField } from "@mui/material";

interface Props {
  allTasks: Task[];
  taskTemplates: TaskTemplate[];
  isActive: boolean;
}

const TaskSetup: React.FC<Props> = ({
  allTasks: tasks,
  taskTemplates,
  isActive,
}) => {
  const { t } = useTranslation();
  const { setValue, watch, clearErrors, setError, formState: { defaultValues } } = useFormContext<CreateProjectInputs>();
  const currentTaskGroups = watch("taskGroups");
  const currentTaskIds = Object.values(currentTaskGroups).reduce<Task["id"][]>(
    (acc, group) => {
      return group.taskIds && group.taskIds.length > 0 ? [...acc, ...group.taskIds] : acc;
    },
    [],
  );

  const onReset = useCallback(() => {
    setValue("taskGroups", {});
  }, [setValue]);

  const [selectedTaskTemplateId, setSelectedTaskTemplateId] = useState<
    "All" | number
  >(watch("taskTemplateId") ?? "All");
  const onSelectTaskTemplate = useCallback(
    (event: SyntheticEvent<Element, Event>, value: NonNullable<{id: number | string, name: string}>) => {
      if (value.id === "All" || isNumber(value.id)) {
        setSelectedTaskTemplateId(value.id);
        // onReset();
      }
    },
    [onReset],
  );

  const items = useMemo(() => {
    const selectedTaskTemplate = taskTemplates.find(
      (template) => template.id === selectedTaskTemplateId,
    )

    if (selectedTaskTemplateId !== "All" && selectedTaskTemplateId !== watch("taskTemplateId")) {

      // update the "manhour allocation by grade" by task template
      const updatedManhourPercentageByGrade: ManhourAllocation = watch("manhourPercentageByGrade")
      selectedTaskTemplate?.gradeAllocations.forEach((gradeAllocation) => {
        updatedManhourPercentageByGrade[gradeAllocation.grade.id] = gradeAllocation?.percentage
      })

      setValue("manhourPercentageByGrade", updatedManhourPercentageByGrade)
      if (Object.values(updatedManhourPercentageByGrade).reduce((acc, value) => acc + value, 0) === 100) clearErrors("manhourPercentageByGrade")
      else setError("manhourPercentageByGrade", { message: "manhourPercentageByGrade value is not valid", type: "invalid" })

      // update the "manhour allocation by grade by stage" by task template
      const updatedTaskGroups = watch("taskGroups")
      const taskGroupsKeys = Object.keys(updatedTaskGroups)
      selectedTaskTemplate?.groupAllocations.forEach((groupAllocation) => {
        const taskGroupId = groupAllocation.taskGroup.id
        if (taskGroupsKeys.includes(taskGroupId.toString())) {
          updatedTaskGroups[taskGroupId] = { ...updatedTaskGroups[taskGroupId], percentAllocation: groupAllocation?.percentage }
        }
      })

      const percentageToZeroGroupIds = difference(taskGroupsKeys.map(key => parseFloat(key)), selectedTaskTemplate?.groupAllocations.map(groupAllocation => groupAllocation.taskGroup.id)!!)
      percentageToZeroGroupIds.forEach((percentageToZeroGroupId) => {
        updatedTaskGroups[percentageToZeroGroupId] = { ...updatedTaskGroups[percentageToZeroGroupId], percentAllocation: 0 }
      })

      setValue("taskGroups", updatedTaskGroups)
      if (Object.values(updatedTaskGroups).reduce((acc, value) => acc + value.percentAllocation, 0) === 100) clearErrors("taskGroups")
      else setError("taskGroups", { message: "Task Groups value is not invalid", type: "invalid" })
    }

    setValue("taskTemplateId", selectedTaskTemplateId)

    const taskList =
      selectedTaskTemplateId === "All"
        ? tasks
        : selectedTaskTemplate?.tasks || tasks;


    return taskList.map((t) => ({
      id: t.id,
      label: t.name,
      group: t.taskGroup,
    }));
  }, [tasks, selectedTaskTemplateId, taskTemplates]);

  const selectedItems = useMemo(() => {
    return intersectionWith(
      tasks,
      currentTaskIds,
      (task, taskId) => task.id === taskId,
    ).map((t) => ({ id: t.id, label: t.name, group: t.taskGroup }));
  }, [currentTaskIds, tasks]);

  return (
    <Card sx={{ display: isActive ? "block" : "none" }}>
      <CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
        <Typography variant="overline" display="block" marginBlockEnd={1}>
          {t("Task List Setup")}
        </Typography>
        <Grid
          container
          spacing={2}
          columns={{ xs: 6, sm: 12 }}
          marginBlockEnd={1}
        >
          <Grid item xs={6}>
            <Autocomplete
              disableClearable
              // disablePortal
              noOptionsText={t("No Task List Source")}
              value={taskTemplates.find(taskTemplate => taskTemplate.id === selectedTaskTemplateId) ?? {id: "All", name: t("All tasks")}}
              options={[{id: "All", name: t("All tasks")}, ...taskTemplates.map(taskTemplate => ({id: taskTemplate.id, name: taskTemplate.name}))]}
              getOptionLabel={(taskTemplate) => taskTemplate.name}
              isOptionEqualToValue={(option, value) => option?.id === value?.id}
              renderOption={(params, option) => {
                return (
                  <MenuItem {...params} key={option.id} value={option.id}>
                    {option.name}
                  </MenuItem>
                );
              }}
              onChange={onSelectTaskTemplate}
              renderInput={(params) => <TextField {...params} variant="outlined" label={t("Task List Source")} />}
            />
          </Grid>
        </Grid>
        <TransferList
          allItems={items}
          selectedItems={selectedItems}
          onChange={(selectedTasks) => {
            const newTaskGroups = selectedTasks.reduce<
              CreateProjectInputs["taskGroups"]
            >((acc, item) => {
              if (!item.group) {
                // TODO: this should not happen (all tasks are part of a group)
                return acc;
              }
              if (!acc[item.group.id]) {
                return {
                  ...acc,
                  [item.group.id]: {
                    taskIds: [item.id],
                    percentAllocation:
                      currentTaskGroups[item.group.id]?.percentAllocation || 0,
                  },
                };
              }
              return {
                ...acc,
                [item.group.id]: {
                  ...acc[item.group.id],
                  taskIds: [...acc[item.group.id].taskIds, item.id],
                },
              };
            }, {});

            // update the "manhour allocation by grade by stage" by task template
            const taskGroupsKeys = Object.keys(newTaskGroups)
            const selectedTaskTemplate = taskTemplates.find(
              (template) => template.id === selectedTaskTemplateId,
            )
            selectedTaskTemplate?.groupAllocations.forEach((groupAllocation) => {
              const taskGroupId = groupAllocation.taskGroup.id
              if (taskGroupsKeys.includes(taskGroupId.toString())) {
                newTaskGroups[taskGroupId] = { ...newTaskGroups[taskGroupId], percentAllocation: groupAllocation?.percentage }
              }
            })

            const percentageToZeroGroupIds = difference(taskGroupsKeys.map(key => parseFloat(key)), selectedTaskTemplate?.groupAllocations.map(groupAllocation => groupAllocation.taskGroup.id)!!)
            percentageToZeroGroupIds.forEach((percentageToZeroGroupId) => {
              newTaskGroups[percentageToZeroGroupId] = { ...newTaskGroups[percentageToZeroGroupId], percentAllocation: 0 }
            })

            setValue("taskGroups", newTaskGroups)
            if (Object.values(newTaskGroups).reduce((acc, value) => acc + value.percentAllocation, 0) === 100) clearErrors("taskGroups")
            else setError("taskGroups", { message: "Task Groups value is not invalid", type: "invalid" })
          }}
          allItemsLabel={t("Task Pool")}
          selectedItemsLabel={t("Project Task List")}
        />
        {/* <CardActions sx={{ justifyContent: "flex-end" }}>
          <Button variant="text" startIcon={<RestartAlt />} onClick={onReset}>
            {t("Reset")}
          </Button>
        </CardActions> */}
      </CardContent>
    </Card>
  );
};

export default TaskSetup;
