import { DeveloperBoard as ProvisionIcon, LibraryAdd as CreateGroupIcon, Tune } from "@mui/icons-material";
import { Box, Checkbox, Chip, Grid2, IconButton, ListItemIcon, ListItemText, Menu, MenuItem, Skeleton, Tab, Tabs, Theme, Tooltip, Typography, useTheme } from "@mui/material";
import { blue, green, orange } from "@mui/material/colors";
import { makeStyles } from "@mui/styles";
import ResponsiveTable, { Column } from "common/ResponsiveTable";
import ProvisionDevice from "device/ProvisionDevice";
import { pond } from "protobuf-ts/pond";
import { useDeviceAPI, useGlobalState, useGroupAPI } from "providers";
import { useCallback, useEffect, useState } from "react";
import PageContainer from "./PageContainer";
import { useMobile } from "hooks";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
import { getDeviceStateHelper } from "pbHelpers/DeviceState";
import { Device, Group, Tag } from "models";
import GroupSettings from "group/GroupSettings";
import SmartBreadcrumb from "common/SmartBreadcrumb";
import GroupActions from "group/GroupActions";
// import CircleGraphIcon from "common/CircleGraphIcon";
import DevicesSummary from "device/DevicesSummary";
import BindaptIcon from "products/Bindapt/BindaptIcon";
import { describePower } from "pbHelpers/Power";
import { Tag as TagUI } from "common/Tag";
import moment from "moment";
import StatusPlenum from "common/StatusPlenum";
import StatusSen5x from "common/StatusSen5x";
import StatusDust from "common/StatusDust";
import StatusGas from "common/StatusGas";
import { cloneDeep } from "lodash";
import LoadingScreen from "app/LoadingScreen";

const useStyles = makeStyles((theme: Theme) => {
  return ({
    buttonBox: {
      position: "absolute", 
      zIndex: 1, 
      right: theme.spacing(4),
      transform: "translateY(-50%)", // Move it up by half its height
      transition: "opacity 0.2s ease-in-out",
      opacity: 1,
      // top: 0,
    },
    fadeBox: {
      opacity: 0, // Fully transparent by default
      transition: "opacity 0.2s ease-in-out", // Smooth transition
      "&:hover": {
        opacity: 1, // Fully opaque on hover
      },
    },
    provisionIcon: {
      color: blue["700"]
    },
    cellContainer: {
      margin: theme.spacing(1),
      marginLeft: theme.spacing(2),
      display: "flex",
      width: theme.spacing(10)
      // justifyContent: "center",
    },
    descriptionCellContainer: {
      margin: theme.spacing(1),
      marginLeft: theme.spacing(2),
      display: "flex",
      // width: theme.spacing(26)
      // justifyContent: "center",
    },
    tagsCellContainer: {
      margin: theme.spacing(1),
      marginLeft: theme.spacing(2),
      display: "flex",
      width: theme.spacing(18)
      // justifyContent: "center",
    },
    green: {
      color: green["600"]
    },
    tab: {
      display: "block",
      overflow: "hidden",
      textOverflow: "ellipsis",
      maxWidth: theme.spacing(26),
      whiteSpace: "nowrap",
      padding: theme.spacing(1.5)
    }
  });
});

export default function Devices() {
  const theme = useTheme();
  const isMobile = useMobile();
  const classes = useStyles();
  const navigate = useNavigate();
  const location = useLocation();
  const deviceAPI = useDeviceAPI();
  const groupAPI = useGroupAPI();
  const [devicesLoading, setDevicesLoading] = useState(false)
  const [limit, setLimit] = useState(10);
  const [page, setPage] = useState(0);

  const [order, setOrder] = useState<"asc" | "desc">(() => {
    // Load from sessionStorage on initial render
    const savedOrder = sessionStorage.getItem('order');
    return (savedOrder === "asc" || savedOrder === "desc") ? savedOrder : "asc";
  });

  // Save to sessionStorage whenever order changes
  useEffect(() => {
    sessionStorage.setItem('order', order);
  }, [order]);

  const [orderBy, setOrderBy] = useState(() => {
    // Load from sessionStorage on initial render
    const savedOrder = sessionStorage.getItem('orderBy');
    return (savedOrder && savedOrder?.length > 0) ? savedOrder : "name";
  });

  // Save to sessionStorage whenever order changes
  useEffect(() => {
    sessionStorage.setItem('orderBy', orderBy);
  }, [orderBy]);

  // const [orderBy, setOrderBy] = useState("name");
  const [search, setSearch] = useState("");
  const [total, setTotal] = useState(0);
  const [devices, setDevices] = useState<Device[]>([])
  const [isProvisionDialogOpen, setIsProvisionDialogOpen] = useState<boolean>(false);
  const [hasPlenums, setHasPlenums] = useState(false)
  const [hasSen5x, setHasSen5x] = useState(false)
  const [hasCo, setHasCo] = useState(false)
  const [hasCo2, setHasCo2] = useState(false)
  const [hasNo2, setHasNo2] = useState(false)
  const [hasO2, setHasO2] = useState(false)

  const [groupsLoading, setGroupsLoading] = useState(false)
  const [groups, setGroups] = useState<Group[]>([]);
  const [groupLimit, ] = useState(10);
  const [groupPage, ] = useState(0);
  const [orderGroup, ] = useState<"asc" | "desc">("asc");
  const [orderGroupBy, ] = useState("name");
  const [searchGroup, ] = useState("");
  // const [totalGroups, setTotalGroups] = useState(0);

  const [groupPermissions, setGroupPermissions] = useState<pond.Permission[]>([])
  const [groupsLoaded, setGroupsLoaded] = useState(false)

  const groupID = useParams<{ groupID: string }>()?.groupID ?? "all";
  // const [tab, setTab] = useState(groupID==="all" ? groupID : groupID);
  const [tab, setTab] = useState(() => {
    console.log("groupID: "+groupID)
    if (groupID!=="all") return groupID
    const stored = sessionStorage.getItem(location.pathname+"-groups-tab");
    console.log("stored: "+stored)
    return stored !== null ? stored : "all";
  });

  useEffect(() => {
    console.log(tab)
    sessionStorage.setItem(location.pathname+"-groups-tab", tab);
  }, [tab]);

  const [selectedGroup, setSelectedGroup] = useState<Group | undefined>(undefined);
  const [groupSettingsMode, setGroupSettingsMode] = useState<
    "add" | "update" | "remove" | undefined
  >(undefined);
  const [groupSettingsIsOpen, setGroupSettingsIsOpen] = useState<boolean>(false);

  const [fieldContains, setFieldContains] = useState<Map<string, string>>(new Map<string, string>())
  
  const [separateDust, setSeparateDust] = useState(() => {
    const stored = localStorage.getItem('separateDust');
    return stored !== null ? stored === 'true' : false;
  });

  useEffect(() => {
    localStorage.setItem('separateDust', separateDust.toString());
  }, [separateDust]);

  const [groupGas, setGroupGas] = useState(() => {
    const stored = localStorage.getItem('groupGas');
    return stored !== null ? stored === 'true' : false;
  });

  useEffect(() => {
    localStorage.setItem('groupGas', groupGas.toString());
  }, [groupGas]);

  const [preferencesAnchor, setPreferencesAnchor] = useState<any>(null)

  const [{ as }] = useGlobalState()

  const updateGroups = (newGroups: Group[]) => {
    setGroups(newGroups);
  };

  const getGroup = () => {
    return groups[parseInt(tab)]
  }

  useEffect(() => {
    setGroupPermissions([])
    if (tab === "all" || !getGroup()) return
    groupAPI.getGroupPermissions(getGroup().id()).then(resp => {
      setGroupPermissions(resp.data.permissions)
    })
  }, [tab])

  const openProvisionDialog = () => {
    setIsProvisionDialogOpen(true);
  };

  const closeProvisionDialog = () => {
    setIsProvisionDialogOpen(false);
  };

  const removeGroupCallback = useCallback(() => {
    let newGroups = [...groups];
    newGroups.splice(parseInt(tab), 1);
    setGroups(newGroups);
    setTab("all");
    setGroupSettingsIsOpen(false);
  }, [groups, tab]); // Include dependencies

  const addGroupCallback = useCallback((groupSettings: pond.GroupSettings) => {
    let newGroups = [...groups];
    let group = pond.Group.create({
      settings: groupSettings
    })
    newGroups.push(Group.create(group))
    setGroups(newGroups);
    // setTab(groups.length.toString())
  }, [groups, tab]); // Include dependencies

  const openGroupSettings = (
    group: Group | undefined,
    mode: "add" | "update" | "remove" | undefined
  ) => {
    setGroupSettingsIsOpen(true);
    setGroupSettingsMode(mode);
    setSelectedGroup(group);
  };

  const closeGroupSettings = (_event: any) => {
    setGroupSettingsIsOpen(false);
    setGroupSettingsMode(undefined);
    setSelectedGroup(undefined);
  };
  
  const getKeys = () => {
    if (tab !== "all" && getGroup()) {
      let keys = getContextKeys()
      //keys.splice(keys.length - 1, 0, getGroup().id().toString());
      keys.push(getGroup().id().toString());
      return keys
    } else {
      return getContextKeys()
    }
  }

  const getTypes = () => {
    if (tab !== "all") {
      let types = getContextTypes()
      //types.splice(types.length - 1, 0, "group");
      types.push("group");
      return types
    } else {
      return getContextTypes()
    }
  }

  const loadGroups = () => {
    if (groupsLoading) return
    if (groups.length > 0) return
    setGroupsLoading(true)
    groupAPI.listGroups(
      groupLimit,
      groupPage*groupLimit, 
      orderGroup, 
      orderGroupBy, 
      searchGroup,
      undefined,
      getKeys(),
      getTypes(),
    ).then(resp => {
      let newGroups: Group[] = []
      resp.data.groups?.forEach((group: pond.Group) => {
        newGroups.push(Group.create(group))
      })
      updateGroups(newGroups) 
    }).finally(() => {
      setGroupsLoading(false)
      setGroupsLoaded(true)
    })
  }

  const loadDevices = () => {
    setDevicesLoading(true)
    if (!groupsLoaded) return
    deviceAPI.list(
      limit, 
      page*limit, 
      order, 
      orderBy, 
      undefined,
      undefined,
      undefined,
      undefined,
      undefined,
      undefined,
      undefined,
      getKeys(),
      getTypes(),
      fieldContains,
      search,
      as
    ).then(resp => {
      let newDevices: Device[] = []
      resp.data.devices.forEach(device => {
        if (device.status?.plenum?.temperature) setHasPlenums(true)
        if (device.status?.sen5x?.temperature) setHasSen5x(true)
        if (device.status?.o2) setHasO2(true)
        if (device.status?.co) setHasCo(true)
        if (device.status?.co2) setHasCo2(true)
        if (device.status?.no2) setHasNo2(true)
        newDevices.push(Device.create(device))
      })
      setDevices(newDevices)
      setTotal(resp.data.total)
    }).finally(() => {
      setDevicesLoading(false)
    })
  }

  useEffect(() => {
    loadDevices()
  }, [limit, page, order, orderBy, fieldContains, search, tab, as, groupsLoaded])

  useEffect(() => {
    loadGroups()
  }, [groupLimit, groupPage, orderGroup, orderGroupBy, searchGroup, as])

  const handleChange = (event: any) => {
    setLimit(event.target.value);
  };

  // const prependToUrl = (prependage: number | string) => {
  //   const basePath = location.pathname.replace(/\/$/, ""); 
  //   return(`/${prependage}/${basePath}`.replace(/\/{2,}/g, "/").replace(/(\/[^/]+)\/\1+/g, "$1"));
  // };

  function insertGroupContext(groupID: string, deviceID: string): string {
    const path = location.pathname
    const segments = path.split('/').filter(Boolean);
    const deviceIndex = segments.findIndex(segment => segment === 'devices');

    if (deviceIndex === -1) {
      throw new Error('Path does not contain "devices"');
    }

    // Build the new segments
    const newSegments = [
      ...segments.slice(0, deviceIndex),
      'groups',
      groupID,
      ...segments.slice(deviceIndex),
      deviceID
    ];

    return '/' + newSegments.join('/');
  }

  // useEffect(() => {
  //   console.log(devices)
  // }, [devices])

  const toDevice = (device: Device) => {
    let url = getGroup() ? insertGroupContext(getGroup().id().toString(), device.id().toString()) : ""
    if (url.length < 1) url = device.id().toString()
    navigate(url, { state: {device: device} })
  };

  const handleTabChange = (_event: React.SyntheticEvent, newValue: string) => {
    if (newValue !== "never") setTab(newValue);
    if (newValue === "never") openGroupSettings(undefined, "add");
  };

  const columns = (): Column<Device>[] => {
    let columns: Column<Device>[] = [
      {
        title: "State",
        // cellStyle: {width: 100000},
        // sortKey: "state",
        render: (device: Device) => {
          const status = device.status ?? pond.DeviceStatus.create()
          const deviceStateHelper = getDeviceStateHelper(status.state);
          return (
            <Box className={classes.cellContainer} style={{ width: theme.spacing(0.5)}}>
            {/* <Box > */}
              <Tooltip title={deviceStateHelper.description}>{deviceStateHelper.icon}</Tooltip>
            </Box>
          )
        }
      },
      {
        title: "ID",
        sortKey: "deviceId",
        render: (device: Device) => <span className={classes.cellContainer}>
          {device.settings?.deviceId}
        </span>
      },
      {
        title: "Device",
        cellStyle: { width: 160 },
        sortKey: "name",
        render: (device: Device) => {
          return (
            <Box className={classes.cellContainer}>
            {/* // <Box > */}
              <Chip 
                variant="outlined"
                label={device.settings?.name ? device.settings.name : "Device " + device.settings?.deviceId} 
                sx={{ maxWidth: 160}}
              />
            </Box>
          )
        }
      },
      {
        title: "Description",
        cellStyle: { width: 400 },
        render: (device: Device) => {
          const description = device.settings?.description ?? ""
          let size = (hasCo2 && !groupGas) ? 26 : 36
          return (
            <Box className={classes.descriptionCellContainer} >
              <Tooltip title={description}>
                <span>
                  {description.length > size
                    ? description.substring(0, size) + "..."
                    : description}
                </span>
              </Tooltip>
            </Box>
          )
        }
      },
      {
        title: "Tags",
        sortKey: "tags",
        render: (device: Device) => {
          return (
            <Grid2 container spacing={1} className={classes.tagsCellContainer}>
              {device.status.tags.map((tag: pond.TagSettings) => (
                <Grid2 key={"device-"+device.id()+"-tag-"+tag.key}>
                  <TagUI tag={Tag.any({ settings: tag })} />
                </Grid2>
              ))}
            </Grid2>
          )
        }
      },
    ]
    if (hasPlenums) {
      columns.push({
        title: "Plenum",
        // sortKey: "hi",
        // disableSort: true,
        render: (device: Device) => {
          if (device.status.plenum?.temperature) {
            return (
              <Box sx={{ marginLeft: 1 }}>
                <StatusPlenum device={device} />
              </Box>
            )
          } else {
            return (
              <></>
            )
          }
        }
      })
    }
    if (hasSen5x) {
      columns.push({
        title: "Sen5X",
        // sortKey: "hi",
        // disableSort: true,
        render: (device: Device) => {
          if (device.status.sen5x?.temperature) {
            return (
              <Box sx={{ marginLeft: 1 }}>
                <StatusSen5x device={device} noDust={separateDust} />
              </Box>
            )
          } else {
            return (
              <></>
            )
          }
        }
      })
      if (separateDust) columns.push({
        title: "Dust",
        render: (device: Device) => {
          if (device.status.sen5x?.temperature) {
            return (
              <Box sx={{ marginLeft: 1 }}>
                <StatusDust device={device} />
              </Box>
            )
          } else {
            return (
              <></>
            )
          }
        }
      })
    }
    if (hasCo) {
      columns.push({
        title: groupGas ? "Gas" : "CO",
        render: (device: Device) => {
          if (device.status.co) {
            return (
              <Box sx={{ marginLeft: 1 }}>
                <StatusGas device={device} gasType={groupGas ? "all" : "co"}/>
              </Box>
            )
          } else {
            return (
              <></>
            )
          }
        }
      })
    }
    if (hasCo2 && !groupGas) {
      columns.push({
        title: "CO2",
        render: (device: Device) => {
          if (device.status.co2) {
            return (
              <Box sx={{ marginLeft: 1 }}>
                <StatusGas device={device} gasType={"co2"}/>
              </Box>
            )
          } else {
            return (
              <></>
            )
          }
        }
      })
    }
    if (hasNo2 && !groupGas) {
      columns.push({
        title: "NO2",
        render: (device: Device) => {
          if (device.status.no2) {
            return (
              <Box sx={{ marginLeft: 1 }}>
                <StatusGas device={device} gasType={"no2"}/>
              </Box>
            )
          } else {
            return (
              <></>
            )
          }
        }
      })
    }
    if (hasO2 && !groupGas) {
      columns.push({
        title: "O2",
        render: (device: Device) => {
          if (device.status.o2) {
            return (
              <Box sx={{ marginLeft: 1 }}>
                <StatusGas device={device} gasType={"o2"}/>
              </Box>
            )
          } else {
            return (
              <></>
            )
          }
        }
      })
    }
    return columns
  }

  const provisionButton= () => {
    return (
      <Tooltip title="Provision Device">
        <IconButton onClick={openProvisionDialog} aria-label="Provision Device">
          <ProvisionIcon className={classes.provisionIcon} />
        </IconButton>
      </Tooltip>
    )
  }

  const groupButton = () => {
    return (
      <Tooltip title="Create Group">
        <IconButton
          onClick={() => openGroupSettings(undefined, "add")}
          aria-label="Create Group">
          <CreateGroupIcon className={classes.green} />
        </IconButton>
      </Tooltip>
    )
  }

  const subtitle = () => { 
    return (
      <>
      {provisionButton()}
      {groupButton()}
      </>
    )
  }

  const mobile = (row: Device) => {
    return (
      <Box sx={{ margin: 2 }}>
        <Grid2 spacing={1} container direction={"row"} justifyContent="space-between" alignItems={"center"}>
          <Grid2 >
            {/* {GetDeviceProductIcon(row)} */}
            {/* {icon} */}
            <BindaptIcon />
          </Grid2>
          <Grid2 size={{ xs: 9}}>
            <Grid2 container direction="column">
              <Grid2>
                {row.name()}
              </Grid2>
              <Grid2>
                Last Active: {moment(row.status.lastActive).fromNow()}
              </Grid2>
            </Grid2>
          </Grid2>
          <Grid2 >
            {describePower(row.status.power).icon}
          </Grid2>
        </Grid2>
      </Box>
    )
  }

  const gutter = (row: Device) => {
    return (
      <Box sx={{ margin: 1 }}>
        <Grid2 container spacing={1} direction="column">
          <Grid2>
            {row.settings.description}
          </Grid2>
          {row.status.plenum && 
            <Grid2 container direction="row" spacing={0}>
              <Grid2>
                <Typography color={orange[400]}>
                  {row.status.plenum.temperature}°C
                </Typography>
              </Grid2>
              <Grid2 >
                <Typography style={{ marginRight: 6 }}>
                  {", "}
                </Typography>
              </Grid2>
              <Grid2>
                <Typography color={blue[300]}>
                  {row.status.plenum.humidity}%
                </Typography>
              </Grid2>
            </Grid2>
          }
        </Grid2>
      </Box>
    )
  }

  const preferencesButton = () => {
    return (
      <IconButton onClick={(event) => setPreferencesAnchor(event.currentTarget)}>
        <Tune />
      </IconButton>
    )
  }

  const preferencesMenu = () => {
    return (
      <Menu
        id="userMenu"
        anchorEl={preferencesAnchor}
        open={preferencesAnchor !== null}
        onClose={() => setPreferencesAnchor(null)}
        disableAutoFocusItem>
          <MenuItem 
            onClick={() => setSeparateDust(!separateDust)}
            sx={{ marginLeft: -0.75 }}
            dense
          >
            <ListItemIcon>
              <Checkbox checked={!separateDust} />
            </ListItemIcon>
            <ListItemText primary={"Group Dust"} />
          </MenuItem>
          <MenuItem 
            onClick={() => setGroupGas(!groupGas)}
            sx={{ marginLeft: -0.75 }}
            dense
          >
            <ListItemIcon>
              <Checkbox checked={groupGas} />
            </ListItemIcon>
            <ListItemText primary={"Group Gas"} />
          </MenuItem>
      </Menu>
    )
  }

  useEffect(() => {
    console.log('Current tab value:', tab, typeof tab);
  }, [tab]);

  if (!groupsLoaded) return (
    <LoadingScreen message="Loading groups" />
  )

  return(
    <PageContainer padding={isMobile ? 0 : 2}>
      <Box 
        sx={{ 
          borderRadius: 1, 
          border: "1px solid rgba(150, 150, 150, 0.2)", 
          marginTop: 0, 
          marginBottom: 1 
        }}
      >
        <Tabs
          value={groups.length > 0 ? tab : "all"}
          onChange={handleTabChange}
          variant="scrollable"
          scrollButtons="auto"
          sx={{ borderRadius: 1 }}
        >
          <Tab wrapped value={"all"} label="All" />
          {groupsLoading ? 
            <Tab value={"loading"} label={<Skeleton variant="rectangular" height={24} width={128} animation="pulse" />}/>
          : groups.map((group, index) => {
            if (group.id()) return (
              <Tab className={classes.tab} wrapped value={index.toString()} label={<Typography variant="inherit" noWrap>{group.name()}</Typography>} key={"group-tab-"+index}/>
            )
          })}
          <Tab wrapped value={"never"} label={<CreateGroupIcon className={classes.green} />} onClick={() => openGroupSettings(undefined, "add")} />
        </Tabs>
      </Box>
      <DevicesSummary setFieldContains={setFieldContains} group={getGroup()} />
      <ResponsiveTable<Device>
        title={<SmartBreadcrumb prependPaths={getGroup() && ["groups", getGroup().id().toString()]} groupName={getGroup() && getGroup().name()} paddingBottom={1}/>}
        subtitle={subtitle}
        rows={devices}
        renderGutter={ isMobile ? gutter : undefined }
        columns={columns}
        renderMobile={mobile}
        total={total}
        pageSize={limit}
        page={page}
        setPage={setPage}
        handleRowsPerPageChange={handleChange}
        onRowClick={toDevice}
        setSearchText={setSearch}
        isLoading={devicesLoading}
        actions={getGroup() && <GroupActions removeCallback={removeGroupCallback} group={getGroup()} permissions={groupPermissions} devices={devices} refreshCallback={loadDevices}/>}
        order={order}
        setOrder={setOrder}
        orderBy={orderBy}
        setOrderBy={setOrderBy}
        endTitleElement={preferencesButton}
        loadMore={()=>{
          let currentRows = cloneDeep(devices)
          deviceAPI.list(
            limit, 
            currentRows.length,
            order, 
            orderBy, 
            undefined,
            undefined,
            undefined,
            undefined,
            undefined,
            undefined,
            undefined,
            getKeys(),
            getTypes(),
            fieldContains,
            search,
            as
          ).then(resp => {
            let newDevices: Device[] = []
            resp.data.devices.forEach(device => {
              if (device.status?.plenum?.temperature) setHasPlenums(true)
              if (device.status?.sen5x?.temperature) setHasSen5x(true)
              if (device.status?.o2) setHasO2(true)
              if (device.status?.co) setHasCo(true)
              if (device.status?.co2) setHasCo2(true)
              if (device.status?.no2) setHasNo2(true)
              newDevices.push(Device.create(device))
            })
            setDevices(currentRows.concat(newDevices))
          }).catch(_err => {

          })
        }}
      />
      <ProvisionDevice
        isOpen={isProvisionDialogOpen}
        refreshCallback={loadDevices}
        closeDialogCallback={closeProvisionDialog}
      />
      {/* This GroupSettings is used for adding */}
      <GroupSettings
        initialGroup={selectedGroup}
        mode={groupSettingsMode}
        isDialogOpen={groupSettingsIsOpen}
        closeDialogCallback={closeGroupSettings}
        refreshCallback={() => {}}
        canEdit={true}
        groupDevices={devices}
        removeGroupCallback={removeGroupCallback}
        addGroupCallback={addGroupCallback}
      />
      {preferencesMenu()}
    </PageContainer>
  )
}