"use client";

import { useTranslation } from "react-i18next";
import React, { SyntheticEvent, useEffect, useMemo } from "react";
import RestartAlt from "@mui/icons-material/RestartAlt";
import SearchResults, { Column } from "../SearchResults";
import { Search, Clear, PersonAdd, PersonRemove } from "@mui/icons-material";
import {
  Stack,
  Typography,
  Grid,
  TextField,
  InputAdornment,
  IconButton,
  FormControl,
  InputLabel,
  Select,
  MenuItem,
  Box,
  Button,
  Card,
  CardActions,
  CardContent,
  TabsProps,
  Tab,
  Tabs,
  SelectChangeEvent,
  Autocomplete,
} from "@mui/material";
import differenceWith from "lodash/differenceWith";
import intersectionWith from "lodash/intersectionWith";
import uniq from "lodash/uniq";
import ResourceCapacity from "./ResourceCapacity";
import { useFormContext } from "react-hook-form";
import { CreateProjectInputs } from "@/app/api/projects/actions";
import ResourceAllocation from "./ResourceAllocation";
import { Task } from "@/app/api/tasks";
import { Grade } from "@/app/api/grades";
import { StaffResult } from "@/app/api/staff";

const staffComparator = (a: StaffResult, b: StaffResult, teamLeads: StaffResult[]) => {
  const priorityTeamId = teamLeads[0]?.teamId;
  if (a.teamId === priorityTeamId && b.teamId !== priorityTeamId) {
    return -1;
  }
  if (a.teamId !== priorityTeamId && b.teamId === priorityTeamId) {
    return 1;
  }
  return (
    Number(b.active) - Number(a.active) ||
    a.team?.localeCompare(b.team) ||
    a.grade?.localeCompare(b.grade) ||
    a.id - b.id
  );
};

export interface Props {
  allStaffs: StaffResult[];
  isActive: boolean;
  defaultManhourBreakdownByGrade?: { [gradeId: number]: number };
  allTasks: Task[];
  grades: Grade[];
  teamLeads: StaffResult[];
}

const StaffAllocation: React.FC<Props> = ({
  allStaffs,
  allTasks,
  isActive,
  defaultManhourBreakdownByGrade,
  grades,
  teamLeads,
}) => {
  const { t } = useTranslation();
  const { setValue, getValues, watch } = useFormContext<CreateProjectInputs>();

  const [filteredStaff, setFilteredStaff] = React.useState(
    allStaffs.sort((a, b) => staffComparator(a, b, teamLeads)),
  );
  const selectedStaffIds = watch("allocatedStaffIds");

  // Adding / Removing staff
  const addStaff = React.useCallback(
    (staff: StaffResult) => {
      const currentStaffIds = getValues("allocatedStaffIds");
      setValue("allocatedStaffIds", [...currentStaffIds, staff.id]);
    },
    [getValues, setValue],
  );
  const removeStaff = React.useCallback(
    (staff: StaffResult) => {
      const currentStaffIds = getValues("allocatedStaffIds");
      setValue(
        "allocatedStaffIds",
        currentStaffIds.filter((id) => id !== staff.id),
      );
    },
    [getValues, setValue],
  );
  const clearStaff = React.useCallback(() => {
    setValue("allocatedStaffIds", []);
  }, [setValue]);

  const staffPoolColumns = React.useMemo<Column<StaffResult>[]>(
    () => [
      {
        label: t("Add"),
        name: "id",
        onClick: addStaff,
        buttonIcon: <PersonAdd />,
      },
      { label: t("Team"), name: "team" },
      { label: t("Grade"), name: "grade" },
      { label: t("Staff ID"), name: "staffId" },
      { label: t("Staff Name"), name: "name" },
      { label: t("Title"), name: "currentPosition" },
      { label: t("Active"), name: "active", type: "checkbox" },
    ],
    [addStaff, t],
  );

  const allocatedStaffColumns = React.useMemo<Column<StaffResult>[]>(
    () => [
      {
        label: t("Remove"),
        name: "id",
        onClick: removeStaff,
        buttonIcon: <PersonRemove />,
      },
      { label: t("Team"), name: "team" },
      { label: t("Grade"), name: "grade" },
      { label: t("Staff ID"), name: "staffId" },
      { label: t("Staff Name"), name: "name" },
      { label: t("Title"), name: "currentPosition" },
      { label: t("Active"), name: "active", type: "checkbox" },
    ],
    [removeStaff, t],
  );

  // Query related
  const [query, setQuery] = React.useState("");
  const onQueryInputChange = React.useCallback<
    React.ChangeEventHandler<HTMLInputElement>
  >((e) => {
    setQuery(e.target.value);
  }, []);
  const clearQueryInput = React.useCallback(() => {
    setQuery("");
  }, []);
  const columnFilters = React.useMemo<(keyof StaffResult)[]>(
    () => ["team", "grade"],
    [],
  );
  const filterValues = React.useMemo(() => {
    return columnFilters.reduce<{ [filter in keyof StaffResult]?: string[] }>(
      (acc, filter) => {
        return {
          ...acc,
          [filter]: uniq(allStaffs.map((staff) => staff[filter])),
        };
      },
      {},
    );
  }, [columnFilters, allStaffs]);
  const defaultFilterValues = React.useMemo(() => {
    return columnFilters.reduce<{ [filter in keyof StaffResult]?: string }>(
      (acc, filter) => {
        return { ...acc, [filter]: "All" };
      },
      {},
    );
  }, [columnFilters]);
  const [filters, setFilters] = React.useState(defaultFilterValues);
  const makeFilterSelect = React.useCallback(
    (filter: keyof StaffResult) => (event: SyntheticEvent<Element, Event>, value: NonNullable<string>) => {
      setFilters((f) => ({ ...f, [filter]: value }));
    },
    [],
  );

  useEffect(() => {
    setFilteredStaff(
      allStaffs.filter((staff) => {
        const q = query.toLowerCase();
        return (
          (staff.name?.toLowerCase().includes(q) ||
            staff.staffId?.toLowerCase().includes(q) ||
            staff.currentPosition?.toLowerCase().includes(q)) &&
          Object.entries(filters).every(([filterKey, filterValue]) => {
            const staffColumnValue = staff[filterKey as keyof StaffResult];
            return staffColumnValue === filterValue || filterValue === "All";
          })
        );
      }),
    );
  }, [allStaffs, filters, query]);

  // Tab related
  const [tabIndex, setTabIndex] = React.useState(0);
  const handleTabChange = React.useCallback<NonNullable<TabsProps["onChange"]>>(
    (_e, newValue) => {
      setTabIndex(newValue);
    },
    [],
  );

  const reset = React.useCallback(() => {
    clearQueryInput();
    clearStaff();
    setFilters(defaultFilterValues);
  }, [clearQueryInput, clearStaff, defaultFilterValues]);

  return (
    <>
      {/* <Card sx={{ display: isActive ? "block" : "none" }}>
        <CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
          <ResourceCapacity />
        </CardContent>
      </Card> */}
      <Card sx={{ display: isActive ? "block" : "none" }}>
        <CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
          <Stack gap={2}>
            <Typography variant="overline" display="block">
              {t("Staff Allocation")}
            </Typography>
            <Grid container spacing={2} columns={{ xs: 6, sm: 12 }}>
              <Grid item xs={6} display="flex" alignItems="center">
                <Search sx={{ marginInlineEnd: 1 }} />
                <TextField
                  variant="standard"
                  fullWidth
                  onChange={onQueryInputChange}
                  value={query}
                  placeholder={t("Search by staff ID, name or title")}
                  InputProps={{
                    endAdornment: query && (
                      <InputAdornment position="end">
                        <IconButton onClick={clearQueryInput}>
                          <Clear />
                        </IconButton>
                      </InputAdornment>
                    ),
                  }}
                />
              </Grid>
              {columnFilters.map((filter, idx) => {
                const label = staffPoolColumns.find(
                  (c) => c.name === filter,
                )!.label;

                return (
                  <Grid key={`${filter.toString()}-${idx}`} item xs={3}>
                    <FormControl fullWidth>
                      <Autocomplete
                        disableClearable
                        // disablePortal
                        size="small"
                        noOptionsText={t(`No ${label}`)}
                        value={filters[filter]}
                        options={["All", ...(filterValues[filter] ?? [])]}
                        getOptionLabel={(filterValue) => filterValue}
                        isOptionEqualToValue={(option, value) => option === value}
                        renderOption={(params, option) => {
                          return (
                            <MenuItem {...params} key={option} value={option}>
                              {option}
                            </MenuItem>
                          );
                        }}
                        onChange={makeFilterSelect(filter)}
                        renderInput={(params) => <TextField {...params} variant="outlined" label={t(label)} />}
                      />
                    </FormControl>
                  </Grid>
                );
              })}
            </Grid>
            <Tabs value={tabIndex} onChange={handleTabChange}>
              <Tab label={t("Staff Pool")} />
              <Tab
                label={`${t("Allocated Staff")} (${selectedStaffIds.length})`}
              />
            </Tabs>
            <Box sx={{ marginInline: -3 }}>
              {tabIndex === 0 && (
                <SearchResults
                  noWrapper
                  items={differenceWith(
                    filteredStaff,
                    selectedStaffIds,
                    (staff, staffId) => staff.id === staffId,
                  )}
                  columns={staffPoolColumns}
                />
              )}
              {tabIndex === 1 && (
                <SearchResults
                  noWrapper
                  items={intersectionWith(
                    allStaffs,
                    selectedStaffIds,
                    (staff, staffId) => staff.id === staffId,
                  )}
                  columns={allocatedStaffColumns}
                />
              )}
            </Box>
          </Stack>
          {/* <CardActions sx={{ justifyContent: "flex-end" }}>
            <Button variant="text" startIcon={<RestartAlt />} onClick={reset}>
              {t("Reset")}
            </Button>
          </CardActions> */}
        </CardContent>
      </Card>
      {/* MUI X-Grid will throw an error if it is rendered without any dimensions; so not rendering when not active */}
      {isActive && (
        <Card>
          <CardContent>
            <ResourceAllocation
              grades={grades}
              allTasks={allTasks}
              manhourBreakdownByGrade={defaultManhourBreakdownByGrade}
            />
          </CardContent>
        </Card>
      )}
    </>
  );
};

export default StaffAllocation;
