import { Box, Button, DialogActions, DialogContent, DialogTitle, Grid2, Switch, TextField } from "@mui/material";
import ResponsiveDialog from "common/ResponsiveDialog";
import SearchSelect, { Option } from "common/SearchSelect";
import { Bin } from "models";
import { pond } from "protobuf-ts/pond";
import GrainDescriber, { GrainOptions, ToGrainOption } from "grain/GrainDescriber";
import { useEffect, useMemo, useState } from "react";
import React from "react";
import CustomGrainSelector from "./CustomGrainSelector";
import { cloneDeep } from "lodash";
import { useBinAPI, useSnackbar } from "providers";

interface Props {
    bin: Bin
    open: boolean
    closeDialog: () => void
    permissions: pond.Permission[]
    /**
     * this function can be passed in if you want to just return a new bin with the changes and handle the actual update in the parent, 
     * it will stop the component from doing the update itself
     * @param bin the bin with the new changes
     * @returns 
     */
    updateBin?: (bin: Bin) => void
    /**
     * this function can be passed in as a callback function if the component handles the update
     * @param updated whether the bin api was used to update the bin
     * @returns 
     */
    updateCallback?: (bin: Bin) => void
}

export default function ChangeGrainDialog(props: Props){
    const { bin, open, permissions, closeDialog, updateBin, updateCallback } = props
    const canEdit = useMemo(()=>{
        return permissions ? permissions.includes(pond.Permission.PERMISSION_WRITE) : false;
    },[permissions])

    const [isCustom, setIsCustom] = useState(false)
    const grainOptions = GrainOptions();
    const [grainOption, setGrainOption] = useState<Option>();
    const [newGrainType, setNewGrainType] = useState<pond.Grain>(0);
    const [newGrainSettings, setNewGrainSettings] = useState<pond.GrainSettings | undefined>()
    const binAPI = useBinAPI()
    const {openSnack} = useSnackbar()
    const [grainSubtype, setGrainSubtype] = useState("")

    useEffect(()=>{
        setGrainOption(ToGrainOption(bin.grain()))
        setIsCustom(bin.grain() === pond.Grain.GRAIN_CUSTOM)
        setGrainSubtype(bin.subtype())
        setNewGrainType(bin.grain())
    },[bin])

    /**
     * this function is where the split happens, 
     * if update bin is passed in it will just clone the bin, change the settings and pass the updated clone to the parent so that it can handle the api call
     * otherwise the component will update the bin itself through the bin api and upon completion pass that updated bin to the parent if successfull
     * in the event both functions are passed in the parent update will be given priority and the internal update will not occur
     */
    const updateBinSettings = () => {
      let clone = cloneDeep(bin)
      let inventory = clone.settings.inventory ?? pond.BinInventory.create()
      inventory.grainType = newGrainType
      inventory.customGrain = newGrainSettings
      inventory.grainSubtype = grainSubtype
        if(updateBin){
            //simply pass the clone up to the parent and it can deal with it
            updateBin(clone)
        }else if (updateCallback) {
            //use the actual bin api to update the bin inside the component and upon completion return the updated bin
            binAPI.updateBin(bin.key(), clone.settings).then(resp => {
              openSnack("Updated the grain type")
              updateCallback(clone)
            }).catch(err => {
              openSnack("There was a problem changing the grain type")
            })
        }
    }

    //closes the dialog
    const close = () => {
        closeDialog()
    }
        
        return (
          <ResponsiveDialog
            open={open}
            onClose={close}>
            <DialogTitle>Change Grain Type</DialogTitle>
            <DialogContent>
              <Grid2 container justifyContent="space-between" alignItems="center">
                <Grid2>
                  <Grid2 container alignItems="center">
                    <Grid2 >Grain</Grid2>
                    <Grid2 >
                      <Switch
                        color="default"
                        value={isCustom}
                        checked={isCustom}
                        onChange={(_, checked) => {
                            setIsCustom(checked)
                            if(checked){
                              setNewGrainType(pond.Grain.GRAIN_CUSTOM)
                            }else{
                              setNewGrainType(bin.grain())
                              setNewGrainSettings(undefined)
                            }
                        }}
                        name="storage"
                      />
                    </Grid2>
                    <Grid2 >Custom</Grid2>
                  </Grid2>
                </Grid2>
              </Grid2>
              {!isCustom && (
                <Box>
                  <SearchSelect
                    label="Type"
                    selected={grainOption}
                    changeSelection={option => {
                      let newGrainType = option
                        ? pond.Grain[option.value as keyof typeof pond.Grain]
                        : pond.Grain.GRAIN_INVALID;
                      setGrainOption(ToGrainOption(newGrainType));
                      setNewGrainType(newGrainType);
                      //setBushPerTonne(GrainDescriber(newGrainType).bushelsPerTonne.toFixed(2));
                    }}
                    group
                    disabled={!canEdit}
                    options={grainOptions}
                  />
                </Box>
              )}
              {isCustom ? (
                <React.Fragment>
                  <CustomGrainSelector initialGrain={bin.customGrain()} onGrainSettingsChange={settings => {setNewGrainSettings(settings)}}/>
                </React.Fragment>
              ) : (
                <TextField
                  sx={{marginTop: 2}}
                  label="Grain Variant"
                  value={grainSubtype}
                  type="text"
                  onChange={event => {
                    setGrainSubtype(event.target.value);
                  }}
                  fullWidth
                  variant="outlined"
                  disabled={!grainOption}
                />
              )}
            </DialogContent>
            <DialogActions>
              <Button
                onClick={() => {
                  close();
                }}>
                Cancel
              </Button>
              <Button
                variant="contained"
                color="primary"
                // disabled={grainErrorCheck()}
                onClick={() => {
                  updateBinSettings();
                  close()
                }}>
                Confirm
              </Button>
            </DialogActions>
          </ResponsiveDialog>
        );
}