import { DeveloperBoard as ProvisionIcon, LibraryAdd as CreateGroupIcon } from "@mui/icons-material";
import { Box, Chip, Grid2, IconButton, Skeleton, Tab, Tabs, Theme, Tooltip, Typography } 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, useGroupAPI } from "providers";
import { 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";

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",
    },
    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 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, ] = useState<"asc" | "desc">("asc");
  const [orderBy, ] = 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 [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 groupID = useParams<{ groupID: string }>()?.groupID ?? "all";
  const [tab, setTab] = useState(groupID==="all" ? groupID : groupID);

  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 updateGroups = (newGroups: Group[]) => {
    setGroups(newGroups);
  };

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

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

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

  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") {
      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
    ).then(resp => {
      let newGroups: Group[] = []
      resp.data.groups?.forEach((group: pond.Group) => {
        newGroups.push(Group.create(group))
      })
      updateGroups(newGroups) 
    }).finally(() => {
      setGroupsLoading(false)
    })
  }

  const loadDevices = () => {
    setDevicesLoading(true)
    deviceAPI.list(
      limit, 
      page*limit, 
      order, 
      orderBy, 
      undefined,
      undefined,
      undefined,
      undefined,
      undefined,
      undefined,
      undefined,
      getKeys(),
      getTypes(),
      fieldContains,
      search,
    ).then(resp => {
      let newDevices: Device[] = []
      resp.data.devices.forEach(device => {
        if (device.status?.plenum?.temperature) {
          setHasPlenums(true)
        }
        newDevices.push(Device.create(device))
      })
      setDevices(newDevices)
      setTotal(resp.data.total)
    }).finally(() => {
      setDevicesLoading(false)
    })
  }

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

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

  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"));
  };

  const toDevice = (device: Device) => {
    let url = prependToUrl(getGroup() ? "groups/" + getGroup().id() : "")
    url = url + "/" + device.id()
    navigate(url, { replace: true, 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 = [
      {
        title: "State",
        render: (device: Device) => {
          const status = device.status ?? pond.DeviceStatus.create()
          const deviceStateHelper = getDeviceStateHelper(status.state);
          return (
            <Box className={classes.cellContainer}>
              <Tooltip title={deviceStateHelper.description}>{deviceStateHelper.icon}</Tooltip>
            </Box>
          )
        }
      },
      {
        title: "ID",
        render: (device: Device) => <span className={classes.cellContainer}>
          {device.settings?.deviceId}
        </span>
      },
      {
        title: "Device",
        render: (device: Device) => {
          return (
            <Box className={classes.cellContainer} >
              <Chip 
                variant="outlined"
                label={device.settings?.name ? device.settings.name : "Device " + device.settings?.deviceId} 
              />
            </Box>
          )
        }
      },
      {
        title: "Description",
        render: (device: Device) => {
          const description = device.settings?.description ?? ""
          return (
            <Box className={classes.descriptionCellContainer}>
              <Tooltip title={device.settings?.description}>
                <span>
                  {description.length > 32
                    ? description.substring(0, 32) + "..."
                    : description}
                </span>
              </Tooltip>
            </Box>
          )
        }
      },
      {
        title: "Tags",
        render: (device: Device) => {
          return (
            <Grid2 container spacing={1} className={classes.descriptionCellContainer}>
              {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",
        render: (device: Device) => {
          if (device.status.plenum?.temperature) {
            return (
              <Grid2 container direction="column" marginLeft={2}>
                <Grid2>
                  <Typography variant="body2" style={{ color: orange[300]}}>
                    {device.status.plenum.temperature.toFixed(1)}°C
                  </Typography>
                </Grid2>
                <Grid2>
                  <Typography variant="body2" color="info">
                    {device.status.plenum.humidity.toFixed(1)}%
                  </Typography>
                </Grid2>
              </Grid2>
            )
          } 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 getGroup = () => {
    let group = groups[parseInt(tab)]
    return group
  }

  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>
    )
  }

  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} 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} />
      <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 group={getGroup()} permissions={groupPermissions} devices={devices} refreshCallback={loadDevices}/>}
      />
      <ProvisionDevice
        isOpen={isProvisionDialogOpen}
        refreshCallback={loadDevices}
        closeDialogCallback={closeProvisionDialog}
      />
      <GroupSettings
        initialGroup={selectedGroup}
        mode={groupSettingsMode}
        isDialogOpen={groupSettingsIsOpen}
        closeDialogCallback={closeGroupSettings}
        refreshCallback={loadDevices}
        canEdit={true}
        groupDevices={devices}
      />
    </PageContainer>
  )
}