import { 
  AccountBox, 
  Close, 
  ExpandLess, 
  ExpandMore, 
  Face, 
  Share as ShareIcon, 
  Notifications as NotificationsIcon, 
  Email as EmailIcon,
  Textsms as TextIcon,
  Contrast,
} from "@mui/icons-material";
import { AppBar, Box, Button, Checkbox, CircularProgress, Collapse, Divider, FormControl, FormControlLabel, FormGroup, FormHelperText, FormLabel, Grid2, IconButton, List, ListItem, ListItemButton, ListItemIcon, ListItemText, MenuItem, Radio, RadioGroup, Slider, TextField, Theme, ToggleButton, ToggleButtonGroup, Toolbar, Tooltip, Typography } from "@mui/material";
import ResponsiveDialog from "common/ResponsiveDialog";
import UserAvatar from "./UserAvatar";
import { useGlobalState, useSnackbar, useUserAPI } from "providers";
import { useEffect, useState } from "react";
import { makeStyles } from "@mui/styles";
import { blue } from "@mui/material/colors";
import ShareObject from "./ShareObject";
import { pond } from "protobuf-ts/pond";
import { User, userScope } from "models";
import SearchSelect from "common/SearchSelect";
import {Option as OptionType} from "common/SearchSelect";
import moment from "moment";
import { IconPicker } from "common/IconPicker";
import { MuiTelInput } from "mui-tel-input";
import { useThemeMode } from "theme/AppThemeProvider";
// import ContractsIcon from "products/CommonIcons/contractIcon";
import UnitsIcon from "@mui/icons-material/Category";
import { setThemeType } from "theme";
import { IsAdaptiveAgriculture } from "services/whiteLabel";
import { setDistanceUnit, setGrainUnit, setPressureUnit, setTemperatureUnit } from "utils";
import FieldsIcon from "products/AgIcons/FieldsIcon";

const useStyles = makeStyles((theme: Theme) => {
  return ({
    title: {
      marginLeft: theme.spacing(2),
      marginRight: theme.spacing(2),
      flex: 1
    },
    checkboxIcon: {
      minWidth: theme.spacing(5),
      [theme.breakpoints.up("sm")]: {
        minWidth: theme.spacing(6)
      },
      [theme.breakpoints.up("md")]: {
        minWidth: theme.spacing(7)
      }
    },
    shareIcon: {
      color: blue["600"],
      "&:hover": {
        color: blue["700"]
      }
    },
    iconButton: {
      margin: theme.spacing(1),
      position: "absolute",
      right: theme.spacing(6)
    }
  });
});

interface Props {
  isOpen: boolean;
  closeDialogCallback: () => void;
}

export default function UserSettings(props: Props) {
  const themeMode = useThemeMode()
  const { isOpen, closeDialogCallback } = props;
  const [globalState, dispatch] = useGlobalState()
  const [sharing, setSharing] = useState(false)
  const userAPI = useUserAPI();
  const classes = useStyles()
  const { success } = useSnackbar();

  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [user, setUser] = useState<User>(globalState.user);
  const [profileExpanded, setProfileExpanded] = useState<boolean>(false);
  const [avatarExpanded, setAvatarExpanded] = useState<boolean>(false);
  const [notificationsExpanded, setNotificationsExpanded] = useState<boolean>(false);
  const [unitsExpanded, setUnitsExpanded] = useState<boolean>(false);
  const [mapsExpanded, setMapsExpanded] = useState<boolean>(false);
  const [avatarUrl, setAvatarUrl] = useState<string>("");
  const [sliderVal, setSliderVal] = useState(globalState.user.settings.mapZoom);
  // const [themeValue, setThemeValue] = useState<"light" | "dark" | "system">(themeMode.mode)

  useEffect(() => {
    function changeIcon(icon: string | undefined) {
      let updatedUser = User.clone(user);
      updatedUser.settings.avatar = icon ? icon : user.settings.avatar;
      setUser(updatedUser);
    }
    if (avatarUrl === "") {
      changeIcon(undefined);
    } else {
      changeIcon(avatarUrl);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [avatarUrl]);

  const submit = () => {
    userAPI
      .updateUser(user.id(), user.protobuf())
      .then(() => {
        dispatch({ key: "user", value: user });
        success("User settings successfully updated!");
        setTemperatureUnit(user.settings.temperatureUnit);
        setPressureUnit(user.settings.pressureUnit);
        setDistanceUnit(user.settings.distanceUnit);
        setGrainUnit(user.settings.grainUnit);
      })
      .catch((error: any) => {
        error("Error occurred while updating your profile");
      })
      .finally(() => {
        setIsLoading(false);
        closeDialogCallback();
      });
  };

  const setDefaultState = () => {
    setIsLoading(false);
    setUser(globalState.user);
  };

  const closeDialog = () => {
    setDefaultState();
    closeDialogCallback();
  };

  const loading = () => {
    return <CircularProgress variant="indeterminate" color="primary" />;
  };

  const changeName = (name: string) => {
    let updatedUser = User.clone(user);
    updatedUser.settings.name = name;
    setUser(updatedUser);
  };

  const changeTimezone = (tz: string) => {
    let updatedUser = User.clone(user);
    updatedUser.settings.timezone = tz;
    setUser(updatedUser);
  };

  const changePhoneNumber = (newPhoneNumber: string) => {
    let updatedUser = User.clone(user);
    updatedUser.settings.phoneNumber = newPhoneNumber;
    setUser(updatedUser);
  };

  const changeDefaultZoom = (value: number) => {
    setSliderVal(value);
    let updatedUser = User.clone(user);
    updatedUser.settings.mapZoom = value;
    setUser(updatedUser)
  };

  const mapSettings = () => {
    return (
      <Box display="flex">
          <Typography>Map Zoom Level</Typography>
          <Slider
            valueLabelDisplay="auto"
            value={sliderVal}
            min={1}
            max={16}
            onChange={(_, val) => {
              changeDefaultZoom(val as number);
            }}
          />
      </Box>
    );
  };

  const generalSettings = () => {
    const { name, email, phoneNumber, timezone } = user.settings;

    return (
      <Grid2 container direction="column" spacing={4} justifyContent="flex-start" alignItems="flex-start">
        <ShareObject
          scope={userScope(user.id())}
          label={""}
          permissions={[
            pond.Permission.PERMISSION_READ,
            pond.Permission.PERMISSION_SHARE,
            pond.Permission.PERMISSION_USERS,
            pond.Permission.PERMISSION_WRITE
          ]}
          isDialogOpen={sharing}
          closeDialogCallback={() => setSharing(false)}
        />
        <Tooltip title={"Share control of profile with another user"}>
          <IconButton
            aria-label="Share"
            className={classes.iconButton}
            onClick={() => setSharing(true)}>
            <ShareIcon className={classes.shareIcon} />
          </IconButton>
        </Tooltip>
        <Grid2>
          <TextField
            label="Preferred Name"
            fullWidth
            value={name}
            helperText={"Email: " + email}
            onChange={event => changeName(event.target.value.toString())}
          />
        </Grid2>
        <Grid2>
          <FormControl component="fieldset">
            <FormLabel component="legend" htmlFor="phone-number-input">
              Phone Number
            </FormLabel>
            <MuiTelInput value={phoneNumber} onChange={changePhoneNumber} />
          </FormControl>
        </Grid2>
        <Grid2 size={{ xs: 12 }}>
          <Box>
            <SearchSelect
              label="Timezone"
              selected={{ label: timezone, value: timezone } as OptionType}
              options={moment.tz.names().map(tz => ({ label: tz, value: tz } as OptionType))}
              changeSelection={(selected: OptionType | null) =>
                changeTimezone(selected ? selected.value : "")
              }
            />
          </Box>
        </Grid2>
      </Grid2>
    );
  };

  const handleChangeNotifyByDefault = (notifyByDefault: boolean) => {
    let updatedUser = User.clone(user);
    updatedUser.settings.notifyByDefault = notifyByDefault;
    setUser(updatedUser);
  };

  const handleNotificationMethod = (
    checked: boolean,
    notificationMethod: pond.NotificationMethod
  ) => {
    let updatedUser = User.clone(user);
    let notificationMethods = updatedUser.settings.notificationMethods;
    if (checked) {
      if (!notificationMethods.includes(notificationMethod)) {
        notificationMethods.push(notificationMethod);
      }
    } else {
      notificationMethods = notificationMethods.filter(element => element !== notificationMethod);
    }
    updatedUser.settings.notificationMethods = notificationMethods;
    setUser(updatedUser);
  };

  const notificationsSettings = () => {
    const { notifyByDefault, notificationMethods } = user.settings;

    return (
      <Grid2 container direction="column" spacing={4} justifyContent="flex-start" alignItems="flex-start">
        <Grid2>
          <FormControl component="fieldset">
            <FormLabel component="legend">Notification Preference</FormLabel>
            <RadioGroup
              aria-label="notification-default"
              name="notificationDefault"
              value={notifyByDefault}
              onChange={event => handleChangeNotifyByDefault(event.target.value === "true")}>
              <FormControlLabel value={true} control={<Radio />} label="Opt-in" />
              <FormControlLabel value={false} control={<Radio />} label="Opt-out" />
            </RadioGroup>
            <FormHelperText>
              {notifyByDefault
                ? "Notifications are enabled by default"
                : "Notifications are disabled by default"}
            </FormHelperText>
          </FormControl>
        </Grid2>
        <Grid2>
          <FormControl component="fieldset">
            <FormLabel component="legend">Notification Methods</FormLabel>
            <FormGroup>
              <FormControlLabel
                control={
                  <Checkbox
                    onChange={(_event, checked) =>
                      handleNotificationMethod(
                        checked,
                        pond.NotificationMethod.NOTIFICATION_METHOD_EMAIL
                      )
                    }
                    checked={
                      notificationMethods
                        ? notificationMethods.includes(
                            pond.NotificationMethod.NOTIFICATION_METHOD_EMAIL
                          )
                        : false
                    }
                  />
                }
                label={
                  <ListItem dense disableGutters>
                    <ListItemIcon className={classes.checkboxIcon}>
                      <EmailIcon />
                    </ListItemIcon>
                    <ListItemText primary="Email" />
                  </ListItem>
                }
              />

              <FormControlLabel
                control={
                  <Checkbox
                    onChange={(_event, checked) =>
                      handleNotificationMethod(
                        checked,
                        pond.NotificationMethod.NOTIFICATION_METHOD_TEXT
                      )
                    }
                    checked={
                      notificationMethods
                        ? notificationMethods.includes(
                            pond.NotificationMethod.NOTIFICATION_METHOD_TEXT
                          )
                        : false
                    }
                  />
                }
                label={
                  <ListItem dense disableGutters>
                    <ListItemIcon className={classes.checkboxIcon}>
                      <TextIcon />
                    </ListItemIcon>
                    <ListItemText
                      primary="Text Message (SMS)"
                      secondary="Requires a valid phone number"
                      secondaryTypographyProps={{ variant: "caption" }}
                    />
                  </ListItem>
                }
              />

              <FormControlLabel
                control={
                  <Checkbox
                    onChange={(_event, checked) =>
                      handleNotificationMethod(
                        checked,
                        pond.NotificationMethod.NOTIFICATION_METHOD_APP
                      )
                    }
                    checked={
                      notificationMethods
                        ? notificationMethods.includes(
                            pond.NotificationMethod.NOTIFICATION_METHOD_APP
                          )
                        : false
                    }
                  />
                }
                label={
                  <ListItem dense disableGutters>
                    <ListItemIcon className={classes.checkboxIcon}>
                      <TextIcon />
                    </ListItemIcon>
                    <ListItemText
                      primary="In-App Notifications"
                      secondary="No email or phone number required"
                      secondaryTypographyProps={{ variant: "caption" }}
                    />
                  </ListItem>
                }
              />
            </FormGroup>
          </FormControl>
        </Grid2>
      </Grid2>
    );
  };

  const avatarSettings = () => {
    return <IconPicker url={user.settings.avatar} setUrl={setAvatarUrl} id={user.settings.id} />;
  };

  const handleChange = (event: React.MouseEvent<HTMLElement>, theme: "light" | "dark" | "system") => {
    event.preventDefault()
    themeMode.setMode(theme)
    setThemeType(theme)
  };

  const changePressureUnit = (value: any) => {
    let updatedUser = User.clone(user);
    let pressureUnit: pond.PressureUnit;
    switch (value) {
      case 1:
        pressureUnit = pond.PressureUnit.PRESSURE_UNIT_KILOPASCALS;
        break;
      case 2:
        pressureUnit = pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER;
        break;
      default:
        pressureUnit = pond.PressureUnit.PRESSURE_UNIT_UNKNOWN;
        break;
    }
    updatedUser.settings.pressureUnit = pressureUnit;
    setUser(updatedUser);
  };

  const changeTemperatureUnit = (value: any) => {
    let updatedUser = User.clone(user);
    let temperatureUnit: pond.TemperatureUnit;
    switch (value) {
      case 1:
        temperatureUnit = pond.TemperatureUnit.TEMPERATURE_UNIT_CELSIUS;
        break;
      case 2:
        temperatureUnit = pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT;
        break;
      default:
        temperatureUnit = pond.TemperatureUnit.TEMPERATURE_UNIT_UNKNOWN;
        break;
    }
    updatedUser.settings.temperatureUnit = temperatureUnit;
    setUser(updatedUser);
  };

  const changeDistanceUnit = (value: any) => {
    let updatedUser = User.clone(user);
    let distanceUnit: pond.DistanceUnit;
    switch (value) {
      case 1:
        distanceUnit = pond.DistanceUnit.DISTANCE_UNIT_FEET;
        break;
      case 2:
        distanceUnit = pond.DistanceUnit.DISTANCE_UNIT_METERS;
        break;
      default:
        distanceUnit = pond.DistanceUnit.DISTANCE_UNIT_UNKNOWN;
        break;
    }
    updatedUser.settings.distanceUnit = distanceUnit;
    setUser(updatedUser);
  };

  const changeGrainUnit = (value: any) => {
    let updatedUser = User.clone(user);
    let grainUnit: pond.GrainUnit;
    switch (value) {
      case 1:
        grainUnit = pond.GrainUnit.GRAIN_UNIT_BUSHELS;
        break;
      case 2:
        grainUnit = pond.GrainUnit.GRAIN_UNIT_WEIGHT;
        break;
      default:
        grainUnit = pond.GrainUnit.GRAIN_UNIT_UNKNOWN;
        break;
    }
    updatedUser.settings.grainUnit = grainUnit;
    setUser(updatedUser);
  };

  const unitPreferences = () => {
    const { pressureUnit, temperatureUnit, distanceUnit, grainUnit } = user.settings;
    return (
      <Grid2 container>
        <Grid2 size={{ xs: 12 }}>
          <TextField
            select
            fullWidth
            id="pressureUnit"
            name="pressureUnit"
            label="Pressure Unit"
            value={pressureUnit ? pressureUnit : pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER}
            onChange={event => changePressureUnit(event.target.value)}
            margin="normal"
            variant="outlined"
            InputLabelProps={{ shrink: true }}>
            <MenuItem value={pond.PressureUnit.PRESSURE_UNIT_KILOPASCALS}>
              Kilopascals (kPa)
            </MenuItem>
            <MenuItem value={pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER}>
              Inches of Water (iwg)
            </MenuItem>
          </TextField>
        </Grid2>
        <Grid2 size={{ xs: 12 }}>
          <TextField
            select
            fullWidth
            id="temperatureUnit"
            name="temperatureUnit"
            label="Temperature Unit"
            value={
              temperatureUnit ? temperatureUnit : pond.TemperatureUnit.TEMPERATURE_UNIT_CELSIUS
            }
            onChange={event => changeTemperatureUnit(event.target.value)}
            margin="normal"
            variant="outlined"
            InputLabelProps={{ shrink: true }}>
            <MenuItem value={pond.TemperatureUnit.TEMPERATURE_UNIT_CELSIUS}>Celsius (°C)</MenuItem>
            <MenuItem value={pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT}>
              Fahrenheit (°F)
            </MenuItem>
          </TextField>
        </Grid2>
        <Grid2 size={{ xs: 12 }}>
          <TextField
            select
            fullWidth
            id="distanceUnit"
            name="distanceUnit"
            label="Distance Unit"
            value={distanceUnit ? distanceUnit : pond.DistanceUnit.DISTANCE_UNIT_METERS}
            onChange={event => changeDistanceUnit(event.target.value)}
            margin="normal"
            variant="outlined"
            InputLabelProps={{ shrink: true }}>
            <MenuItem value={pond.DistanceUnit.DISTANCE_UNIT_METERS}>Meters (m)</MenuItem>
            <MenuItem value={pond.DistanceUnit.DISTANCE_UNIT_FEET}>Feet (ft)</MenuItem>
          </TextField>
        </Grid2>
        {IsAdaptiveAgriculture() && (
          <Grid2 size={{ xs: 12 }}>
            <TextField
              select
              fullWidth
              id="grainUnit"
              name="grainUnit"
              label="Grain Unit"
              value={grainUnit ? grainUnit : pond.GrainUnit.GRAIN_UNIT_BUSHELS}
              onChange={event => changeGrainUnit(event.target.value)}
              margin="normal"
              variant="outlined"
              InputLabelProps={{ shrink: true }}>
              <MenuItem value={pond.GrainUnit.GRAIN_UNIT_BUSHELS}>Bushels (bu)</MenuItem>
              <MenuItem value={pond.GrainUnit.GRAIN_UNIT_WEIGHT}>Tonnes (mT)</MenuItem>
            </TextField>
          </Grid2>
        )}
      </Grid2>
    );
  };

  const themeToggle = () => {
    return (
      <ToggleButtonGroup
        value={themeMode.mode}
        exclusive
        onChange={handleChange}
        size="small"
        sx={{margin:-1}}
      >
        <ToggleButton value="light">
          light
        </ToggleButton>
        <ToggleButton value="system">
          system
        </ToggleButton>
        <ToggleButton value="dark">
          dark
        </ToggleButton>
      </ToggleButtonGroup>
    )
  }

  const settingsList = () => {
    return (
      <List disablePadding>
        <ListItem >
          <ListItemIcon>
            <Contrast />
          </ListItemIcon>
          <ListItemText primary={"Theme"} />
          {themeToggle()}
        </ListItem>

        <Divider />

        <ListItemButton onClick={() => setProfileExpanded(!profileExpanded)}>
          <ListItemIcon>
            <AccountBox />
          </ListItemIcon>
          <ListItemText primary={"Profile"} />
          {profileExpanded ? <ExpandLess /> : <ExpandMore />}
        </ListItemButton>
        <Collapse in={profileExpanded} timeout="auto" unmountOnExit>
          <List component="div">
            <ListItem>
              <ListItemText disableTypography inset>
                {isLoading ? loading() : generalSettings()}
              </ListItemText>
            </ListItem>
          </List>
        </Collapse>

        <Divider />

        <ListItemButton onClick={() => setAvatarExpanded(!avatarExpanded)}>
          <ListItemIcon>
            <Face />
          </ListItemIcon>
          <ListItemText primary={"Display Picture"} />
          {avatarExpanded ? <ExpandLess /> : <ExpandMore />}
        </ListItemButton>
        <Collapse in={avatarExpanded} timeout="auto" unmountOnExit>
          <List
            component="div"
            sx={{
              paddingLeft: 4,
              paddingRight: 4
            }}>
            {isLoading ? loading() : avatarSettings()}
          </List>
        </Collapse>

        <Divider />

        <ListItemButton onClick={() => setNotificationsExpanded(!notificationsExpanded)}>
          <ListItemIcon>
            <NotificationsIcon />
          </ListItemIcon>
          <ListItemText primary="Notifications" />
          {notificationsExpanded ? <ExpandLess /> : <ExpandMore />}
        </ListItemButton>
        <Collapse in={notificationsExpanded} timeout="auto" unmountOnExit>
          <List component="div">
            <ListItem>
              <ListItemText disableTypography inset>
                {isLoading ? loading() : notificationsSettings()}
              </ListItemText>
            </ListItem>
          </List>
        </Collapse>

        <Divider />

        <ListItemButton onClick={() => setUnitsExpanded(!unitsExpanded)}>
          <ListItemIcon>
            <UnitsIcon />
          </ListItemIcon>
          <ListItemText primary="Preferred Units" />
          {unitsExpanded ? <ExpandLess /> : <ExpandMore />}
        </ListItemButton>
        <Collapse in={unitsExpanded} timeout="auto" unmountOnExit>
          <List component="div">
            <ListItem>
              <ListItemText disableTypography inset>
                {isLoading ? loading() : unitPreferences()}
              </ListItemText>
            </ListItem>
          </List>
        </Collapse>

        <Divider />

        <ListItemButton onClick={() => setMapsExpanded(!mapsExpanded)}>
          <ListItemIcon>
            <FieldsIcon />
          </ListItemIcon>
          <ListItemText primary={"Map Settings"} />
          {mapsExpanded ? <ExpandLess /> : <ExpandMore />}
        </ListItemButton>
        <Collapse in={mapsExpanded} timeout="auto" unmountOnExit>
          <List component="div">
            <ListItem>
              <ListItemText disableTypography inset>
                {isLoading ? loading() : mapSettings()}
              </ListItemText>
            </ListItem>
          </List>
        </Collapse>
      </List>
    );
  };

  return (
    <ResponsiveDialog
      maxWidth="sm"
      fullWidth
      open={isOpen}
      onClose={closeDialog}
      aria-labelledby="user-settings-dialog">
      <AppBar position="relative">
        <Toolbar>
          <IconButton edge="start" color="inherit" onClick={closeDialog} aria-label="close">
            <Close />
          </IconButton>
          <UserAvatar user={user} />
          <Typography variant="h6" className={classes.title}>
            User Settings
          </Typography>
          <Button color="inherit" onClick={submit}>
            Save
          </Button>
        </Toolbar>
      </AppBar>
      {settingsList()}
    </ResponsiveDialog>
  );
}