import { Add, ExpandMore } from "@mui/icons-material";
import { Accordion, AccordionDetails, AccordionSummary, Box, Button, Divider, IconButton, List, ListItem, ListSubheader, Menu, MenuItem, Typography } from "@mui/material";
import { Component, Device, Interaction } from "models";
import { interactionResultText } from "pbHelpers/Interaction";
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
import { pond, quack } from "protobuf-ts/pond";
import React, { useEffect, useState } from "react";

export interface Control {
  conditions: pond.InteractionCondition[];
  sourceComponents: Component[];
  result: pond.InteractionResult | null;
  sinkComponent: Component
  device: Device
}

interface Props {
  devices: Device[]
  controls: Control[]
  permissions: pond.Permission[]
  addNew?: (device: Device) => void
}

export default function Controls(props: Props){
  const { devices, controls, addNew, permissions } = props
  const [deviceControls, setDeviceControls] = useState<Map<number, Control[]>>(new Map())
  const [openDeviceMenu, setOpenDeviceMenu] = useState(false)
  const [anchor, setAnchor] = useState<null | HTMLElement>(null)
  

  useEffect(()=>{
    let map: Map<number, Control[]> = new Map()
    controls.forEach(control => {
      let mappedControls = map.get(control.device.id())
      if(mappedControls){
        mappedControls.push(control)
      }else{
        map.set(control.device.id(), [control])
      }
    })
    setDeviceControls(map)
  },[controls])

  const readableConditions = (control: Control) => {
    let conditions: string = ""
    let firstSource = control.sourceComponents[0]
    control.conditions.forEach((condition, index) => {
      let describer = describeMeasurement(condition.measurementType, firstSource.type(), firstSource.subType());
      let type = describer.label();
      let comparison =
      condition.comparison === quack.RelationalOperator.RELATIONAL_OPERATOR_EQUAL_TO
      ? "Exactly"
      : condition.comparison === quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN
      ? "Above"
      : "Below";
      let value = describer.toDisplay(condition.value);
      conditions = conditions + (index !== 0 ? " and " : "") + type + " " + comparison + " " + value + describer.GetUnit()
    })
    return conditions
  };

  const controlAccordion = (control: Control) => {
    let tempInteraction = Interaction.create()
    tempInteraction.settings.result = control.result
    let resultText = interactionResultText(tempInteraction, control.sinkComponent)

    return (
      <Accordion sx={{width: "100%"}}>
        <AccordionSummary expandIcon={<ExpandMore />}>
          <Box>
            <Typography>
              {resultText}:
            </Typography>
            <Typography>
              {readableConditions(control)}
            </Typography>
          </Box>
        </AccordionSummary>
        <AccordionDetails>
          <List>
            <ListSubheader>Controlling Components</ListSubheader>
            {control.sourceComponents.map((comp, i) => (
              <ListItem key={i}>{comp.name()}</ListItem>
            ))}
          </List>
        </AccordionDetails>
      </Accordion>
    )
  }

  const deviceMenu = () => {
    return (
      <Menu
        open={openDeviceMenu}
        anchorEl={anchor}
        onClose={() => {
          setAnchor(null)
          setOpenDeviceMenu(false)
        }}>
          {devices.map(dev => (
            <MenuItem 
              key={dev.id()} 
              onClick={() => {
                setAnchor(null)
                setOpenDeviceMenu(false)
                if (addNew) addNew(dev)
                
              }}>
                {dev.name()}
            </MenuItem>
          ))}
      </Menu>
    )
  }

  return (
    <React.Fragment>
      {deviceMenu()}
      <List style={{ margin: 5 }}>
        <ListSubheader sx={{paddingY: 1, display: "flex", justifyContent: "space-between", alignItems: "center"}}>
          <Typography>
            Controls
          </Typography>
          {addNew &&
            <Button 
              disabled={!permissions.includes(pond.Permission.PERMISSION_WRITE)}
              variant="contained"
              onClick={(e)=>{
                setOpenDeviceMenu(true)
                setAnchor(e.currentTarget)
              }} 
              color="primary">
                <Add />Control
            </Button>
          }
        </ListSubheader>
        {devices.map(device => (
          <React.Fragment key={device.id()}>
            <Typography sx={{paddingY: 1, paddingX: 2}}>{device.name()}</Typography>
            <Divider />
            {deviceControls.get(device.id()) ? deviceControls.get(device.id())?.map((control, i) => (
              <ListItem key={i}>{controlAccordion(control)}</ListItem>
              ))
            :
              <Typography sx={{paddingY: 1, paddingX: 2}}>No Control Interactions For Device</Typography>
            }
          </React.Fragment>
        ))}
      </List>
    </React.Fragment>
  )
}