"use client";

import { useTranslation } from "react-i18next";
import React, { useEffect } 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,
} from "@mui/material";
import differenceBy from "lodash/differenceBy";
import uniq from "lodash/uniq";
import ResourceCapacity from "./ResourceCapacity";
import { useFormContext } from "react-hook-form";
import { CreateProjectInputs } from "@/app/api/projects/actions";

interface StaffResult {
  id: number;
  name: string;
  team: string;
  grade: string;
  title: string;
}

const mockStaffs: StaffResult[] = [
  {
    name: "Albert",
    grade: "1",
    id: 1,
    team: "ABC",
    title: "Associate Quantity Surveyor",
  },
  {
    name: "Bernard",
    grade: "2",
    id: 2,
    team: "ABC",
    title: "Quantity Surveyor",
  },
  {
    name: "Carl",
    grade: "3",
    id: 3,
    team: "XYZ",
    title: "Senior Quantity Surveyor",
  },
  { name: "Denis", grade: "4", id: 4, team: "ABC", title: "Manager" },
  { name: "Edward", grade: "5", id: 5, team: "ABC", title: "Director" },
  { name: "Fred", grade: "1", id: 6, team: "XYZ", title: "General Laborer" },
  { name: "Gordon", grade: "2", id: 7, team: "ABC", title: "Inspector" },
  {
    name: "Heather",
    grade: "3",
    id: 8,
    team: "XYZ",
    title: "Field Engineer",
  },
  { name: "Ivan", grade: "4", id: 9, team: "ABC", title: "Senior Manager" },
  {
    name: "Jackson",
    grade: "5",
    id: 10,
    team: "XYZ",
    title: "Senior Director",
  },
  {
    name: "Kurt",
    grade: "1",
    id: 11,
    team: "ABC",
    title: "Construction Assistant",
  },
  { name: "Lawrence", grade: "2", id: 12, team: "ABC", title: "Operator" },
];

interface Props {
  allStaff?: StaffResult[];
  isActive: boolean;
}

const StaffAllocation: React.FC<Props> = ({
  allStaff = mockStaffs,
  isActive,
}) => {
  const { t } = useTranslation();
  const { setValue, getValues } = useFormContext<CreateProjectInputs>();

  const [filteredStaff, setFilteredStaff] = React.useState(allStaff);
  const [selectedStaff, setSelectedStaff] = React.useState<
    typeof filteredStaff
  >(
    allStaff.filter((staff) =>
      getValues("allocatedStaffIds").includes(staff.id),
    ),
  );

  // Adding / Removing staff
  const addStaff = React.useCallback((staff: StaffResult) => {
    setSelectedStaff((staffs) => [...staffs, staff]);
  }, []);
  const removeStaff = React.useCallback((staff: StaffResult) => {
    setSelectedStaff((staffs) => staffs.filter((s) => s.id !== staff.id));
  }, []);
  const clearStaff = React.useCallback(() => {
    setSelectedStaff([]);
  }, []);
  // Sync with form
  useEffect(() => {
    setValue(
      "allocatedStaffIds",
      selectedStaff.map((staff) => staff.id),
    );
  }, [selectedStaff, setValue]);

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

  const allocatedStaffColumns = React.useMemo<Column<StaffResult>[]>(
    () => [
      {
        label: t("Remove"),
        name: "id",
        onClick: removeStaff,
        buttonIcon: <PersonRemove />,
      },
      { label: t("Staff ID"), name: "id" },
      { label: t("Staff Name"), name: "name" },
      { label: t("Team"), name: "team" },
      { label: t("Grade"), name: "grade" },
      { label: t("Title"), name: "title" },
    ],
    [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(allStaff.map((staff) => staff[filter])),
        };
      },
      {},
    );
  }, [columnFilters, allStaff]);
  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: SelectChangeEvent<string>) => {
      setFilters((f) => ({ ...f, [filter]: event.target.value }));
    },
    [],
  );

  React.useEffect(() => {
    setFilteredStaff(
      allStaff.filter((staff) => {
        const q = query.toLowerCase();
        return (
          (staff.name.toLowerCase().includes(q) ||
            staff.id.toString().includes(q) ||
            staff.title.toLowerCase().includes(q)) &&
          Object.entries(filters).every(([filterKey, filterValue]) => {
            const staffColumnValue = staff[filterKey as keyof StaffResult];
            return staffColumnValue === filterValue || filterValue === "All";
          })
        );
      }),
    );
  }, [allStaff, 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 }}>
          <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>
                      <InputLabel size="small">{label}</InputLabel>
                      <Select
                        label={label}
                        size="small"
                        value={filters[filter]}
                        onChange={makeFilterSelect(filter)}
                      >
                        <MenuItem value={"All"}>{t("All")}</MenuItem>
                        {filterValues[filter]?.map((option, index) => (
                          <MenuItem key={`${option}-${index}`} value={option}>
                            {option}
                          </MenuItem>
                        ))}
                      </Select>
                    </FormControl>
                  </Grid>
                );
              })}
            </Grid>
            <Tabs value={tabIndex} onChange={handleTabChange}>
              <Tab label={t("Staff Pool")} />
              <Tab
                label={`${t("Allocated Staff")} (${selectedStaff.length})`}
              />
            </Tabs>
            <Box sx={{ marginInline: -3 }}>
              {tabIndex === 0 && (
                <SearchResults
                  noWrapper
                  items={differenceBy(filteredStaff, selectedStaff, "id")}
                  columns={staffPoolColumns}
                />
              )}
              {tabIndex === 1 && (
                <SearchResults
                  noWrapper
                  items={selectedStaff}
                  columns={allocatedStaffColumns}
                />
              )}
            </Box>
          </Stack>
          <CardActions sx={{ justifyContent: "flex-end" }}>
            <Button variant="text" startIcon={<RestartAlt />} onClick={reset}>
              {t("Reset")}
            </Button>
          </CardActions>
        </CardContent>
      </Card>
      <Card sx={{ display: isActive ? "block" : "none" }}>
        <CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
          <ResourceCapacity />
        </CardContent>
      </Card>
    </>
  );
};

export default StaffAllocation;
