"use client";

import * as React from "react";
import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
import ListItemText from "@mui/material/ListItemText";
import ListItemIcon from "@mui/material/ListItemIcon";
import Checkbox from "@mui/material/Checkbox";
import IconButton from "@mui/material/Fab";
import Divider from "@mui/material/Divider";
import ChevronLeft from "@mui/icons-material/ChevronLeft";
import ChevronRight from "@mui/icons-material/ChevronRight";
import intersection from "lodash/intersection";
import difference from "lodash/difference";
import Stack from "@mui/material/Stack";
import Paper from "@mui/material/Paper";
import Typography from "@mui/material/Typography";
import ListSubheader from "@mui/material/ListSubheader";

export interface LabelWithId {
  id: string;
  label: string;
}

export interface TransferListProps {
  allItems: LabelWithId[];
  initiallySelectedItems: LabelWithId[];
  onChange: () => void;
  allItemsLabel: string;
  selectedItemsLabel: string;
}

interface ItemListProps {
  items: LabelWithId[];
  checkedItems: LabelWithId[];
  label: string;
  handleToggleAll: (
    items: LabelWithId[],
    checkedItems: LabelWithId[],
  ) => React.MouseEventHandler;
  handleToggle: (item: LabelWithId) => React.MouseEventHandler;
}

const ItemList: React.FC<ItemListProps> = ({
  items,
  checkedItems,
  label,
  handleToggle,
  handleToggleAll,
}) => {
  return (
    <Paper sx={{ width: "100%" }} variant="outlined">
      <List
        sx={{
          height: 400,
          bgcolor: "background.paper",
          overflow: "auto",
        }}
        disablePadding
        dense
        component="ul"
        subheader={
          <ListSubheader
            disableGutters
            component="li"
            onClick={handleToggleAll(items, checkedItems)}
          >
            <Stack direction="row" paddingY={1} paddingX={2}>
              <ListItemIcon>
                <Checkbox
                  checked={
                    checkedItems.length === items.length && items.length !== 0
                  }
                  indeterminate={
                    checkedItems.length !== items.length &&
                    checkedItems.length !== 0
                  }
                  disabled={items.length === 0}
                />
              </ListItemIcon>
              <Stack>
                <Typography variant="subtitle2">{label}</Typography>
                <Typography variant="caption">{`${checkedItems.length}/${items.length} selected`}</Typography>
              </Stack>
            </Stack>
            <Divider />
          </ListSubheader>
        }
      >
        {items.map((item) => {
          return (
            <ListItem key={item.id} onClick={handleToggle(item)}>
              <ListItemIcon>
                <Checkbox checked={checkedItems.includes(item)} tabIndex={-1} />
              </ListItemIcon>
              <ListItemText primary={item.label} />
            </ListItem>
          );
        })}
      </List>
    </Paper>
  );
};

const TransferList: React.FC<TransferListProps> = ({
  allItems,
  initiallySelectedItems,
  allItemsLabel,
  selectedItemsLabel,
  onChange,
}) => {
  // Keep a map for the original order of items
  const sortMap = React.useMemo(() => {
    return allItems.reduce<{ [id: string]: number }>(
      (acc, item, index) => ({ ...acc, [item.id]: index }),
      {},
    );
  }, [allItems]);
  const compareFn = React.useCallback(
    (a: LabelWithId, b: LabelWithId) => sortMap[a.id] - sortMap[b.id],
    [sortMap],
  );

  const [checkedList, setCheckedList] = React.useState<LabelWithId[]>([]);
  const [leftList, setLeftList] = React.useState<LabelWithId[]>(
    difference(allItems, initiallySelectedItems),
  );
  const [rightList, setRightList] = React.useState<LabelWithId[]>(
    initiallySelectedItems,
  );

  const leftListChecked = intersection(checkedList, leftList);
  const rightListChecked = intersection(checkedList, rightList);

  const handleToggle = React.useCallback(
    (value: LabelWithId) => () => {
      const isChecked = checkedList.includes(value);
      const newCheckedList = isChecked
        ? difference(checkedList, [value])
        : [...checkedList, value];

      setCheckedList(newCheckedList);
    },
    [checkedList],
  );

  const handleToggleAll = React.useCallback(
    (items: LabelWithId[], checkedItems: LabelWithId[]) => () => {
      if (checkedItems.length === items.length) {
        setCheckedList(difference(checkedList, checkedItems));
      } else {
        setCheckedList([...checkedList, ...items]);
      }
    },
    [checkedList],
  );

  const handleCheckedRight = () => {
    setRightList([...rightList, ...leftListChecked].sort(compareFn));
    setLeftList(difference(leftList, leftListChecked).sort(compareFn));
    setCheckedList(difference(checkedList, leftListChecked));
  };

  const handleCheckedLeft = () => {
    setLeftList([...leftList, ...rightListChecked].sort(compareFn));
    setRightList(difference(rightList, rightListChecked).sort(compareFn));
    setCheckedList(difference(checkedList, rightListChecked));
  };

  return (
    <Stack spacing={2} direction="row" alignItems="center" position="relative">
      <ItemList
        items={leftList}
        checkedItems={leftListChecked}
        label={allItemsLabel}
        handleToggleAll={handleToggleAll}
        handleToggle={handleToggle}
      />
      <ItemList
        items={rightList}
        checkedItems={rightListChecked}
        label={selectedItemsLabel}
        handleToggleAll={handleToggleAll}
        handleToggle={handleToggle}
      />
      <Stack
        spacing={1}
        position="absolute"
        margin="0 !important"
        left="50%"
        sx={{ transform: "translateX(-50%)" }}
      >
        <IconButton
          color="secondary"
          size="small"
          onClick={handleCheckedRight}
          disabled={leftListChecked.length === 0}
        >
          <ChevronRight />
        </IconButton>
        <IconButton
          color="secondary"
          size="small"
          onClick={handleCheckedLeft}
          disabled={rightListChecked.length === 0}
        >
          <ChevronLeft />
        </IconButton>
      </Stack>
    </Stack>
  );
};

export default TransferList;
