import React from "react";
import {
  Box,
  Checkbox,
  Chip,
  Collapse,
  Divider,
  FormControlLabel,
  List,
  ListItem,
  ListItemIcon,
  ListItemSecondaryAction,
  ListItemText,
} from "@material-ui/core";
import ExpandLess from '@material-ui/icons/ExpandLess';
import ExpandMore from '@material-ui/icons/ExpandMore';
import { Trie } from "./trie";
import { TrieSelectProvider, useTrieSelect } from "./TrieSelectContext";
import useStyles from "../../useStyles";

export const TrieSelect = ({
  label,
  classification,
  onChange = () => { },
  options = [],
}) => {

  return (
    <TrieSelectProvider onChange={onChange}>
      <TrieSelectList
        label={label}
        classification={classification}
        options={options}
      />
    </TrieSelectProvider>
  );
}

const TrieSelectList = ({
  label,
  classification,
  options,
}) => {
  const { selected, remove } = useTrieSelect();
  const classes = useStyles();
  const trie = new Trie(options);

  return (
    <>
      <List>
        <TrieSelectLevel
          node={trie.getRoot()}
          classification={classification}
          label={label}
        />
      </List>
      <ul className={classes.chipList}>
        {selected.map((signal) => {
          return (
            <li key={signal}>
              <Chip label={signal} onDelete={() => remove([signal])} />
            </li>
          );
        })}
      </ul>
    </>
  )
}

const TrieSelectLevel = ({
  prefix = "",
  node,
  children,
  classification,
  label,
  level = -1,
}) => {
  const classes = useStyles();
  const { selected, add, remove } = useTrieSelect();
  const [open, setOpen] = React.useState(false);
  const completeChildren = Object.values(node.children).filter(child => child.isComplete);
  const hasCompleteChildren = completeChildren.length > 0;
  const descendantCount = `${node.count} ${classification}`;
  const isParentOfMultiple = completeChildren.length > 1;
  const isAdoptiveParentOfMultiple = completeChildren.length <= 1 && node.count > 1;

  const handleExpand = () => {
    setOpen(open => !open);
  };

  const handleCheck = (names = [], checked) => {
    if (checked) {
      remove(names);
    } else {
      add(names)
    }
  }

  const getWords = (node, prepend = prefix, result = new Set()) => {
    if (prepend === prefix && node.isComplete) result.add(prepend);

    for (const child of Object.values(node.children)) {
      const word = (prepend ? prepend + "_" : "") + child.data;
      if (child.isComplete) {
        result.add(word);
      }
      if (child.children) {
        getWords(child, word, result);
      }
    }

    return Array.from(result);
  }

  const indent = (level) => `${12 * level}px`;

  const listItems = (level) => (
    <>
      {children}
      {Object.values(node.children).map((child) => {
        const fullName = (prefix ? prefix + "_" : "") + child.data;
        const isChecked = selected.includes(fullName);
        return (
          <TrieSelectLevel
            prefix={fullName}
            node={child}
            key={fullName}
            classification={classification}
            level={level}
          >
            {child.isComplete && (
              <ListItem className={classes.whiteBackground}>
                <Box sx={{ paddingLeft: indent(level), display: "flex", alignItems: "center" }}>
                  <ListItemIcon>
                    <Checkbox checked={isChecked} onClick={() => handleCheck([fullName], isChecked)} />
                  </ListItemIcon>
                  <ListItemText primary={fullName} />
                </Box>
              </ListItem>
            )}
          </TrieSelectLevel>
        );
      })}
    </>
  );

  if (isParentOfMultiple || isAdoptiveParentOfMultiple) {
    const allDescendants = getWords(node, prefix);
    const isSelectAll = allDescendants.every(descendant => selected.includes(descendant));
    return (
      <>
        <ListItem onClick={handleExpand} divider className={classes.defaultBackground}>
          <Box sx={{ paddingLeft: indent(level) }}>
            <ListItemText primary={prefix === "" ? label : prefix} secondary={descendantCount} />
          </Box>
          <ListItemSecondaryAction>
            <Box sx={{ display: "flex", alignItems: "center", gap: "16px" }}>
              <FormControlLabel
                label="Select All"
                labelPlacement="start"
                control={
                  <Checkbox
                    checked={isSelectAll}
                    onClick={() => handleCheck(allDescendants, isSelectAll)}
                  />
                }
              />
              {open ? (<ExpandLess />) : (<ExpandMore />)}
            </Box>
          </ListItemSecondaryAction>
        </ListItem>
        <Collapse in={open}>
          <List>
            {listItems(level + 1)}
          </List>
          {hasCompleteChildren && <Divider />}
        </Collapse>
      </>
    )
  }

  return listItems(level);
}
