import { Task, TaskGroup } from "@/app/api/tasks";
import {
  Box,
  Typography,
  TextField,
  Alert,
  TableContainer,
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableRow,
  Stack,
  SxProps,
  Grid,
} from "@mui/material";
import React, { useCallback, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Props as StaffAllocationProps } from "./StaffAllocation";
import { useFormContext } from "react-hook-form";
import { CreateProjectInputs } from "@/app/api/projects/actions";
import uniqBy from "lodash/uniqBy";
import { Grade } from "@/app/api/grades";
import { manhourFormatter, percentFormatter } from "@/app/utils/formatUtil";
import TableCellEdit from "../TableCellEdit";

interface Props {
  allTasks: Task[];
  manhourBreakdownByGrade: StaffAllocationProps["defaultManhourBreakdownByGrade"];
  grades: Grade[];
}

const baseCellSx: SxProps = {
  textAlign: "right",
};

const leftBorderCellSx: SxProps = {
  borderLeft: "1px solid",
  borderColor: "divider",
};

const rightBorderCellSx: SxProps = {
  borderRight: "1px solid",
  borderColor: "divider",
};

const leftRightBorderCellSx: SxProps = {
  borderLeft: "1px solid",
  borderRight: "1px solid",
  borderColor: "divider",
};

const errorCellSx: SxProps = {
  outline: "1px solid",
  outlineColor: "error.main",

  // borderLeft: "1px solid",
  // borderRight: "1px solid",
  // borderTop: "1px solid",
  // borderBottom: "1px solid",
  // borderColor: 'error.main'
}

const ResourceAllocationByGrade: React.FC<Props> = ({ grades }) => {
  const { t } = useTranslation();
  const { watch, register, setValue, formState: { errors }, setError, clearErrors } = useFormContext<CreateProjectInputs>();

  const manhourPercentageByGrade = watch("manhourPercentageByGrade");
  const totalManhour = watch("totalManhour");
  const totalPercentage = Object.values(manhourPercentageByGrade).reduce(
    (acc, percent) => acc + percent,
    0,
  );
  // const totalPercentage = Math.round(Object.values(manhourPercentageByGrade).reduce(
  //   (acc, percent) => acc + percent,
  //   0,
  // ) * 100) / 100;

  const makeUpdatePercentage = useCallback(
    (gradeId: Grade["id"]) => (percentage?: number) => {
      if (percentage !== undefined) {
        const updatedManhourPercentageByGrade = {
          ...manhourPercentageByGrade,
          [gradeId]: percentage,
        }
        setValue("manhourPercentageByGrade", updatedManhourPercentageByGrade);

        const keys = Object.keys(updatedManhourPercentageByGrade)
        if (keys.filter(k => updatedManhourPercentageByGrade[k as any] < 0).length > 0 ||
          keys.reduce((acc, value) => acc + updatedManhourPercentageByGrade[value as any], 0) !== 100) {
          setError("manhourPercentageByGrade", { message: "manhourPercentageByGrade value is not valid", type: "invalid" })
        } else {
          clearErrors("manhourPercentageByGrade")
        }

      }
    },
    [manhourPercentageByGrade, setValue],
  );

  return (
    <Box>
      <Typography variant="overline" display="block" marginBlockEnd={1}>
        {t("Manhour Allocation By Grade")}
      </Typography>
      <Grid container columnSpacing={2}>
        <Grid item xs={8}>
          <TextField
            label={t("Total Project Manhour")}
            fullWidth
            type="number"
            {...register("totalManhour", {
              valueAsNumber: true,
              required: "totalManhour code required!",
              min: 1,
            })}
            error={Boolean(errors.totalManhour)}
          />
        </Grid>
        <Grid item xs={4}>
          <TextField
            label={t("Rate Per Manhour")}
            fullWidth
            type="number"
            {...register("ratePerManhour", {
              valueAsNumber: true,
              required: "ratePerManhour code required!",
              min: 1,
            })}
            error={Boolean(errors.ratePerManhour)}
          />
        </Grid>
      </Grid>
      <Box
        sx={(theme) => ({
          marginBlockStart: 2,
          marginInline: -3,
          borderBottom: `1px solid ${theme.palette.divider}`,
        })}
      >
        <TableContainer sx={{ maxHeight: 440 }}>
          <Table>
            <TableHead>
              <TableRow>
                <TableCell sx={rightBorderCellSx}>
                  {t("Allocation Type")}
                </TableCell>
                {grades.map((column, idx) => (
                  <TableCell sx={baseCellSx} key={`${column.id}${idx}`}>
                    {column.name}
                  </TableCell>
                ))}
                <TableCell sx={{...baseCellSx, leftBorderCellSx}}>{t("Total")}</TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              <TableRow>
                <TableCell sx={rightBorderCellSx}>{t("Percentage")}</TableCell>
                {grades.map((column, idx) => (
                  <TableCellEdit
                    key={`${column.id}${idx}`}
                    value={manhourPercentageByGrade[column.id]}
                    renderValue={((val) => (val.toString().includes(".")? val.toString() : val.toFixed(1)) + "%")}
                    // renderValue={(val) => percentFormatter.format(val)}
                    onChange={makeUpdatePercentage(column.id)}
                    convertValue={(inputValue) => Number(inputValue)}
                    cellSx={{ ...baseCellSx, backgroundColor: "primary.lightest" }}
                    inputSx={{ ...baseCellSx, width: "3rem" }}
                    error={manhourPercentageByGrade[column.id] < 0}
                  />
                ))}
                <TableCell sx={{...baseCellSx, ...(totalPercentage === 100 && leftBorderCellSx), ...(totalPercentage !== 100 && { ...errorCellSx, borderRight: "1px solid", borderColor: "error.main" }) }}>
                  {((totalPercentage.toString().includes(".") && totalPercentage.toString() || totalPercentage.toFixed(1)) + "%")}
                  {/* {percentFormatter.format(totalPercentage)} */}
                </TableCell>
              </TableRow>
              <TableRow>
                <TableCell sx={rightBorderCellSx}>{t("Manhour")}</TableCell>
                {grades.map((column, idx) => (
                  <TableCell sx={baseCellSx} key={`${column.id}${idx}`}>
                    {manhourFormatter.format(
                      manhourPercentageByGrade[column.id] / 100 * totalManhour,
                    )}
                  </TableCell>
                ))}
                <TableCell sx={{...baseCellSx, leftBorderCellSx}}>
                  {manhourFormatter.format(totalManhour)}
                </TableCell>
              </TableRow>
            </TableBody>
          </Table>
        </TableContainer>
      </Box>
    </Box>
  );
};

const ResourceAllocationByStage: React.FC<Props> = ({ grades, allTasks }) => {
  const { t } = useTranslation();
  const { watch, setValue, clearErrors, setError } = useFormContext<CreateProjectInputs>();

  const currentTaskGroups = watch("taskGroups");
  const taskGroups = useMemo(
    () =>
      uniqBy(
        allTasks.reduce<TaskGroup[]>((acc, task) => {
          if (currentTaskGroups[task.taskGroup.id]) {
            return [...acc, task.taskGroup];
          }
          return acc;
        }, []),
        "id",
      ),
    [allTasks, currentTaskGroups],
  );

  const manhourPercentageByGrade = watch("manhourPercentageByGrade");
  const totalManhour = watch("totalManhour");

  const makeUpdatePercentage = useCallback(
    (taskGroupId: TaskGroup["id"]) => (percentage?: number) => {
      if (percentage !== undefined) {
        const updatedTaskGroups = {
          ...currentTaskGroups,
          [taskGroupId]: {
            ...currentTaskGroups[taskGroupId],
            percentAllocation: percentage,
          },
        }
        setValue("taskGroups", updatedTaskGroups);

        const keys = Object.keys(updatedTaskGroups)
        if (keys.filter(k => updatedTaskGroups[k as any].percentAllocation < 0).length > 0 ||
          keys.reduce((acc, value) => acc + updatedTaskGroups[value as any].percentAllocation, 0) !== 100) {
          setError("taskGroups", { message: "Task Groups value is not invalid", type: "invalid" })
        } else {
          clearErrors("taskGroups")
        }
      }
    },
    [currentTaskGroups, setValue],
  );

  return (
    <Box>
      <Typography variant="overline" display="block" marginBlockEnd={1}>
        {t("Manhour Allocation By Stage By Grade")}
      </Typography>
      <Box
        sx={(theme) => ({
          marginBlockStart: 2,
          marginInline: -3,
          borderBottom: `1px solid ${theme.palette.divider}`,
        })}
      >
        <TableContainer sx={{ maxHeight: 440 }}>
          <Table>
            <TableHead>
              <TableRow>
                <TableCell>{t("Stage")}</TableCell>
                <TableCell sx={leftBorderCellSx}>{t("Task Count")}</TableCell>
                <TableCell colSpan={2} sx={{...baseCellSx, ...leftRightBorderCellSx}}>
                  {t("Total Manhour")}
                </TableCell>
                {grades.map((column, idx) => (
                  <TableCell key={`${column.id}${idx}`}>
                    {column.name}
                  </TableCell>
                ))}
              </TableRow>
            </TableHead>
            <TableBody>
              {taskGroups.map((tg, idx) => (
                <TableRow key={`${tg.id}${idx}`}>
                  <TableCell>{tg.name}</TableCell>
                  <TableCell sx={{...baseCellSx, ...leftBorderCellSx}}>
                    {currentTaskGroups[tg.id].taskIds.length}
                  </TableCell>
                  <TableCellEdit
                    value={currentTaskGroups[tg.id].percentAllocation}
                    // renderValue={(val) => percentFormatter.format(val)}
                    renderValue={(val) => ((val.toString().includes(".")? val.toString() : val.toFixed(1)) + "%")}
                    onChange={makeUpdatePercentage(tg.id)}
                    convertValue={(inputValue) => Number(inputValue)}
                    cellSx={{
                      ...baseCellSx,
                      backgroundColor: "primary.lightest",
                    }}
                    inputSx={{ ...baseCellSx, width: "3rem" }}
                    error={currentTaskGroups[tg.id].percentAllocation < 0}
                  />
                  <TableCell sx={{...baseCellSx, ...rightBorderCellSx}}>
                    {manhourFormatter.format(
                      currentTaskGroups[tg.id].percentAllocation / 100 * totalManhour,
                    )}
                  </TableCell>
                  {grades.map((column, idx) => {
                    const stageHours =
                      currentTaskGroups[tg.id].percentAllocation / 100 * totalManhour;
                    return (
                      <TableCell sx={baseCellSx} key={`${column.id}${idx}`}>
                        {manhourFormatter.format(
                          manhourPercentageByGrade[column.id] / 100 * stageHours,
                        )}
                      </TableCell>
                    );
                  })}
                </TableRow>
              ))}
              <TableRow>
                <TableCell>{t("Total")}</TableCell>
                <TableCell sx={{...baseCellSx, ...leftBorderCellSx}}>
                  {Object.values(currentTaskGroups).reduce(
                    (acc, tg) => acc + tg.taskIds.length,
                    0,
                  )}
                </TableCell>
                <TableCell sx={{...baseCellSx,
                  ...(Object.values(currentTaskGroups).reduce((acc, tg) => acc + tg.percentAllocation, 0,) === 100 && leftBorderCellSx),
                  ...(Object.values(currentTaskGroups).reduce((acc, tg) => acc + tg.percentAllocation, 0,) !== 100 && errorCellSx)
                }}
                >
                  {((Object.values(currentTaskGroups).reduce(
                      (acc, tg) => acc + tg.percentAllocation,
                      0,
                  ).toString().includes(".") && Object.values(currentTaskGroups).reduce(
                      (acc, tg) => acc + tg.percentAllocation,
                      0,) || Object.values(currentTaskGroups).reduce(
                  (acc, tg) => (acc + tg.percentAllocation),
                  0,
                  ).toFixed(1)) + "%" )}
                  {/* {percentFormatter.format(
                      Object.values(currentTaskGroups).reduce(
                          (acc, tg) => acc + tg.percentAllocation / 100,
                          0,
                      ),
                  ).includes(".") && percentFormatter.format(Object.values(currentTaskGroups).reduce(
                          (acc, tg) => acc + tg.percentAllocation / 100,
                          0,),
                  ) || Object.values(currentTaskGroups).reduce(
                      (acc, tg) => (acc + tg.percentAllocation),
                      0,
                      ).toFixed(1) + "%" } */}
                </TableCell>
                <TableCell sx={{...baseCellSx, ...rightBorderCellSx}}>
                  {manhourFormatter.format(
                    Object.values(currentTaskGroups).reduce(
                      (acc, tg) => acc + tg.percentAllocation / 100 * totalManhour,
                      0,
                    ),
                  )}
                </TableCell>
                {grades.map((column, idx) => {
                  const hours = Object.values(currentTaskGroups).reduce(
                    (acc, tg) =>
                      acc +
                      tg.percentAllocation / 100 *
                      totalManhour *
                      manhourPercentageByGrade[column.id] / 100,
                    0,
                  );
                  return (
                    <TableCell sx={baseCellSx} key={`${column.id}${idx}`}>
                      {manhourFormatter.format(hours)}
                    </TableCell>
                  );
                })}
              </TableRow>
            </TableBody>
          </Table>
        </TableContainer>
      </Box>
    </Box>
  );
};

const NoTaskState: React.FC = () => {
  const { t } = useTranslation();
  return (
    <>
      <Typography variant="overline" display="block" marginBlockEnd={1}>
        {t("Task Breakdown")}
      </Typography>
      <Alert severity="warning">
        {t('Please add some tasks in "Project Task Setup" first!')}
      </Alert>
    </>
  );
};

const ResourceAllocationWrapper: React.FC<Props> = (props) => {
  const { getValues } = useFormContext<CreateProjectInputs>();

  if (Object.keys(getValues("taskGroups")).length === 0) {
    return <NoTaskState />;
  }

  return (
    <Stack spacing={4}>
      <ResourceAllocationByGrade {...props} />
      <ResourceAllocationByStage {...props} />
    </Stack>
  );
};

export default ResourceAllocationWrapper;
