import {
  Avatar,
  Box,
  IconButton,
  ListItemAvatar,
  ListItemText,
  Menu,
  MenuItem,
  Theme,
  Toolbar,
  Tooltip,
  TypeBackground
} from "@mui/material";
import { blue, green, orange, red } from "@mui/material/colors";
import { makeStyles } from "@mui/styles";
//import { TypeBackground } from "@material-ui/core/styles/createPalette";
import {
  ArrowUpward,
  CloudDownload,
  CloudUpload,
  Delete,
  MoreVert,
  OpenInNew
} from "@mui/icons-material";
import classNames from "classnames";
import ResponsiveTable, { Column } from "common/ResponsiveTable";
import SmartBreadcrumb from "common/SmartBreadcrumb";
import UpdateFirmwareChannel from "firmware/UpdateFirmwareChannel";
import UploadFirmware from "firmware/UploadFirmware";
import { useFirmwareAPI, useSnackbar, useThemeType, useWidth } from "hooks";
//import MaterialTable, { Column, MTableToolbar } from "material-table";
import { Firmware as FirmwareModel } from "models";
import moment from "moment";
import PageContainer from "pages/PageContainer";
import { getDevicePlatformLabel, getDevicePlatformName } from "pbHelpers/DevicePlatform";
import { getUpgradeChannelColour, getUpgradeChannelLabel } from "pbHelpers/UpgradeChannel";
import { pond } from "protobuf-ts/pond";
import { useGlobalState } from "providers";
import { useCallback, useEffect, useState } from "react";
import { downloadFile } from "utils/download";
import { or } from "utils/types";
import { cloneDeep } from "lodash";

const useStyles = makeStyles((theme: Theme) => {
  const themeType = useThemeType()
  return ({
    gutter: {
      paddingLeft: theme.spacing(2),
      paddingRight: theme.spacing(2),
      [theme.breakpoints.up("sm")]: {
        paddingLeft: theme.spacing(3),
        paddingRight: theme.spacing(3)
      }
    },
    actionsMenu: {
      background:
        themeType === "light"
          ? theme.palette.background["200" as keyof TypeBackground]
          : theme.palette.background["700" as keyof TypeBackground]
    },
    avatar: {
      margin: theme.spacing(1)
    },
    downloadIcon: {
      color: theme.palette.text.primary,
      backgroundColor: blue["500"],
      "&:hover": {
        backgroundColor: blue["600"]
      }
    },
    updateIcon: {
      color: theme.palette.text.primary,
      backgroundColor: orange["500"],
      "&:hover": {
        backgroundColor: orange["600"]
      }
    },
    changelogIcon: {
      color: theme.palette.text.primary,
      backgroundColor: green["500"],
      "&:hover": {
        backgroundColor: green["600"]
      }
    },
    deleteIcon: {
      color: theme.palette.text.primary,
      backgroundColor: red["500"],
      "&:hover": {
        backgroundColor: red["600"]
      }
    },
    menuItem: {
      paddingTop: theme.spacing(2),
      paddingBottom: theme.spacing(2)
    },
    title: {
      flex: "0 0 auto"
    },
    toolbar:
      themeType === "light"
        ? {
            position: "sticky",
            justifyContent: "space-between",
            background: "#fff",
            zIndex: theme.zIndex.mobileStepper,
            top: "55px",
            paddingRight: theme.spacing(1),
            [theme.breakpoints.up("sm")]: {
              paddingRight: theme.spacing(2),
              top: "63px"
            }
          }
        : {
            position: "sticky",
            justifyContent: "space-between",
            background: theme.palette.background["800" as keyof TypeBackground],
            zIndex: theme.zIndex.mobileStepper,
            top: "55px",
            paddingRight: theme.spacing(1),
            [theme.breakpoints.up("sm")]: {
              paddingRight: theme.spacing(2),
              top: "63px"
            }
          },
    toolbarActions: {
      color: theme.palette.text.secondary
    },
    cellPadding: {
      paddingLeft: theme.spacing(0.5) + "px",
      paddingRight: theme.spacing(0.5) + "px",
      "@media (min-width: 321px)": {
        paddingLeft: theme.spacing(1) + "px",
        paddingRight: theme.spacing(1) + "px"
      },
      [theme.breakpoints.up("sm")]: {
        paddingLeft: theme.spacing(4) + "px",
        paddingRight: theme.spacing(4) + "px"
      }
    },
    pointer: {
      cursor: "pointer"
    },
    tableHead:
      themeType === "light"
        ? {
            position: "sticky",
            background: "#fff",
            zIndex: theme.zIndex.mobileStepper,
            top: "110px",
            [theme.breakpoints.up("sm")]: {
              top: "126px"
            }
          }
        : {
            position: "sticky",
            background: theme.palette.background["800" as keyof TypeBackground],
            zIndex: theme.zIndex.mobileStepper,
            top: "110px",
            [theme.breakpoints.up("sm")]: {
              top: "126px"
            }
          },
    noFirmware: {
      marginTop: theme.spacing(16)
    },
    darkIcon: {
      color: theme.palette.primary.dark
    },
    loading: {
      display: "flex",
      alignItems: "center",
      justifyContent: "center",
      marginTop: theme.spacing(16)
    }
  })
})

export default function Firmware() {
  const classes = useStyles();
  const width = useWidth();
  const { error, success } = useSnackbar();
  const firmwareAPI = useFirmwareAPI();
  const [{ user }] = useGlobalState();
  const [pageSize, setPageSize] = useState<number>(5);
  const [tablePage, setTablePage] = useState(0)
  const [searchText, setSearchText] = useState("")
  const [tableData, setTableData] = useState<FirmwareModel[]>([])
  const [total, setTotal] = useState(0)
  const [selected, setSelected] = useState<FirmwareModel | undefined>(undefined);
  const [actionsOpen, setActionsOpen] = useState<boolean>(false);
  const [isUploadFirmwareDialogOpen, setIsUploadFirmwareDialogOpen] = useState<boolean>(false);
  const [isUpdateFirmwareChannelDialogOpen, setIsUpdateFirmwareChannelDialogOpen] = useState<
    boolean
  >(false);
  const [anchor, setAnchor] = useState<any>(null);
  // const TitleMap = new Map([
  //   ["Uploaded", "uploaded"],
  //   ["Version", "version"],
  //   ["Platform", "platform"],
  //   ["Channel", "channel"],
  //   ["Size", "size"]
  // ]);
  // let tableRef = useRef<any>(React.createRef());

  // const reloadTable = () => {
  //   tableRef.current.onQueryChange();
  // };

  const load = useCallback(() => {
    firmwareAPI.listFirmware(pageSize, pageSize * tablePage, "desc", "version", searchText)
    .then((response) => {
      setTotal(response.data.total ? response.data.total : 0)
      let rows: FirmwareModel[] = or(response.data.firmware, []).map(
        (firmwareData: any) => {
          return FirmwareModel.create(pond.Firmware.fromObject(firmwareData));
        }
      );
      setTableData(rows)
    })
    .catch(() => {
      //failed to load
      error("Failed to load firmware versions")
    });
  },[pageSize, tablePage, searchText])

  useEffect(()=>{
    load()
  },[load])

  const download = () => {
    if (selected) {
      firmwareAPI
        .downloadInstaller(selected.settings.platform, selected.settings.version)
        .then((response: Response) => {
          var filename: string =
            selected.settings.version +
            "-" +
            getDevicePlatformName(selected.settings.platform) +
            ".tar";
          downloadFile(response, filename);
        })
        .catch((err: any) => {
          error(
            err.response ? err.response.statusText : "Error occured while downloading firmware"
          );
        })
        .then(() => closeActionsMenu());
    }
  };

  const hasChangelog = () => {
    return (
      selected && selected.settings.channel !== pond.UpgradeChannel.UPGRADE_CHANNEL_DEVELOPMENT
    );
  };

  const viewChangelog = () => {
    if (selected && selected.settings.version) {
      window.open(
        "https://gitlab.com/brandx/gadwall/-/tags/" + selected.settings.version,
        "_blank"
      );
    }
  };

  const deleteFirmware = () => {
    if (selected) {
      firmwareAPI
        .removeFirmware(selected.settings.platform, selected.settings.version)
        .then(() => {
          success("Successfully removed firmware");
        })
        .catch((err: any) => {
          error(
            err.response
              ? err.response.statusText
              : "Error occured while delete the firmware release"
          );
        })
        .then(() => {
          closeActionsMenu();
          load();
        });
    }
  };

  const openActionsMenu = (firmware: FirmwareModel) => (event: any) => {
    if (user.settings.actions.includes("upload-firmware")) {
      setActionsOpen(true);
      setAnchor(event.currentTarget);
      setSelected(firmware);
    } else {
      error("Missing upload-firmware action");
    }
  };

  const closeActionsMenu = () => {
    setActionsOpen(false);
    setAnchor(null);
    setSelected(undefined);
  };

  const openUploadFirmwareDialog = (event: any) => {
    if (user.settings.actions.includes("upload-firmware")) {
      setActionsOpen(false);
      setAnchor(event.currentTarget);
      setIsUploadFirmwareDialogOpen(true);
    } else {
      error("Missing upload-firmware action");
    }
  };

  const closeUploadFirmwareDialog = () => {
    setActionsOpen(false);
    setAnchor(undefined);
    setSelected(undefined);
    setIsUploadFirmwareDialogOpen(false);
  };

  const openUpdateFirmwareChannelDialog = (event: any) => {
    setActionsOpen(false);
    setAnchor(event.currentTarget);
    setIsUpdateFirmwareChannelDialogOpen(true);
  };

  const closeUpdateFirmwareChannelDialog = () => {
    setActionsOpen(false);
    setAnchor(undefined);
    setSelected(undefined);
    setIsUpdateFirmwareChannelDialogOpen(false);
  };

  const renderActionsMenu = () => {
    return (
      <Menu
        id="actionsMenu"
        anchorEl={anchor}
        open={actionsOpen}
        onClose={closeActionsMenu}
        disableAutoFocusItem
        MenuListProps={{ classes: { root: classes.actionsMenu } }}>
        <MenuItem className={classes.menuItem} onClick={download}>
          <ListItemAvatar>
            <Avatar
              className={classNames(classes.avatar, classes.downloadIcon)}
              alt="Cloud Download">
              <CloudDownload className={classes.downloadIcon} />
            </Avatar>
          </ListItemAvatar>
          <ListItemText primary="Download Installer" />
        </MenuItem>
        <MenuItem className={classes.menuItem} onClick={openUpdateFirmwareChannelDialog}>
          <ListItemAvatar>
            <Avatar className={classNames(classes.avatar, classes.updateIcon)} alt="Update">
              <ArrowUpward className={classes.updateIcon} />
            </Avatar>
          </ListItemAvatar>
          <ListItemText primary="Update Channel" />
        </MenuItem>
        <MenuItem
          disabled={!hasChangelog()}
          className={classes.menuItem}
          onClick={viewChangelog}>
          <ListItemAvatar>
            <Avatar className={classNames(classes.avatar, classes.changelogIcon)} alt="Open New">
              <OpenInNew className={classes.changelogIcon} />
            </Avatar>
          </ListItemAvatar>
          <ListItemText primary="View Changelog" />
        </MenuItem>
        <MenuItem className={classes.menuItem} onClick={deleteFirmware}>
          <ListItemAvatar>
            <Avatar className={classNames(classes.avatar, classes.deleteIcon)} alt="Delete">
              <Delete className={classes.deleteIcon} />
            </Avatar>
          </ListItemAvatar>
          <ListItemText primary="Delete Version" />
        </MenuItem>
      </Menu>
    );
  };

  const columns = (small: boolean): Column<FirmwareModel>[] => {
    return [
      {
        title: "Uploaded",
        hidden: small,
        //defaultSort: "desc",
        cellStyle: {padding: 2},
        render: row => {
          return <span>{moment(row.status.uploaded).fromNow()}</span>;
        }
      },
      {
        title: "Version",
        cellStyle: {padding: 2},
        render: row => <span>{row.settings.version}</span>
      },
      {
        title: "Platform",
        cellStyle: {padding: 2},
        render: row => <span>{getDevicePlatformLabel(row.settings.platform)}</span>
      },
      {
        title: "Channel",
        cellStyle: {padding: 2},
        render: row => (
          <span style={{ color: getUpgradeChannelColour(row.settings.channel) }}>
            {getUpgradeChannelLabel(row.settings.channel)}
          </span>
        )
      },
      {
        title: "Size",
        cellStyle: {padding: 2},
        //type: "numeric",
        hidden: small,
        render: row => <span>{row.settings.size} bytes</span>
      },
      {
        title: "Actions",
        cellStyle: {padding: 2},
        //type: "numeric",
        //sorting: false,
        render: row => (
          <IconButton aria-label="Actions" onClick={openActionsMenu(row)}>
            <MoreVert fontSize={small ? "small" : "inherit"} />
          </IconButton>
        )
      }
    ];
  };

  const actionToolbar = () => {
    return (
      <Toolbar className={classes.gutter}>
        {user.allowedTo("upload-firmware") && (
          <Tooltip title="Upload Firmware" placement="bottom">
            <span>
              <IconButton aria-label="Upload Firmware" onClick={openUploadFirmwareDialog}>
                <CloudUpload
                  fontSize={width === "xs" ? "small" : "inherit"}
                  className={classes.darkIcon}
                />
              </IconButton>
            </span>
          </Tooltip>
        )}
      </Toolbar>
    );
  };

  return (
    <PageContainer>
      <Box margin={2}>
        <ResponsiveTable<FirmwareModel>
          subtitle={actionToolbar()}
          setSearchText={(search) => setSearchText(search)}
          title={<SmartBreadcrumb />}
          page={tablePage}
          pageSize={pageSize}
          rows={tableData}
          total={total}
          columns={columns(width === "xs" || width === "sm")}
          setPage={(page)=>{setTablePage(page)}}
          handleRowsPerPageChange={(e)=>{setPageSize(e.target.value)}}
          loadMore={() => {
            let current = cloneDeep(tableData)
            firmwareAPI.listFirmware(pageSize, current.length, "desc", "version", searchText)
            .then((response) => {
              let newRows: FirmwareModel[] = or(response.data.firmware, []).map(
                (firmwareData: any) => {
                  return FirmwareModel.create(pond.Firmware.fromObject(firmwareData));
                }
              );
              setTableData(current.concat(newRows))
            })
            .catch(() => {
              //failed to load
              error("Failed to load more firmware versions")
            });
          }}
        />
      </Box>
      <UploadFirmware
        isOpen={isUploadFirmwareDialogOpen}
        closeDialogCallback={closeUploadFirmwareDialog}
        refreshCallback={() => load()}
      />
      <UpdateFirmwareChannel
        firmware={selected ? selected : FirmwareModel.create()}
        isOpen={isUpdateFirmwareChannelDialogOpen}
        closeCallback={closeUpdateFirmwareChannelDialog}
        refreshCallback={() => load()}
      />
      {renderActionsMenu()}
    </PageContainer>
  );
}
