import { mdiFolderUploadOutline } from "@mdi/js";
import Icon from "@mdi/react";
import DeleteIcon from "@mui/icons-material/Delete";
import DownloadIcon from "@mui/icons-material/Download";
import FileUploadIcon from "@mui/icons-material/FileUpload";
import RefreshIcon from "@mui/icons-material/Refresh";
import {
  IconButton,
  Paper,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Tooltip,
} from "@mui/material";
import { filesize } from "filesize";
import React from "react";
import { OTAAPI, OTAUpdate } from "../api/OTAApi";
import { DeployOTAUpdateDialogProvider } from "../dialogs/DeployOTAUpdateDialogProvider";
import { UploadUpdateDialog } from "../dialogs/UploadUpdateDialog";
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
import { AsyncWidget } from "../widgets/AsyncWidget";
import { RouterLink } from "../widgets/RouterLink";
import { SolarEnergyRouteContainer } from "../widgets/SolarEnergyRouteContainer";

export function OTARoute(): React.ReactElement {
  const [list, setList] = React.useState<string[] | undefined>();
  const load = async () => {
    setList(await OTAAPI.SupportedPlatforms());
  };

  return (
    <AsyncWidget
      loadKey={1}
      ready={!!list}
      load={load}
      errMsg="Failed to load OTA screen!"
      build={() => <_OTARoute platforms={list!} />}
    />
  );
}

function _OTARoute(p: { platforms: Array<string> }): React.ReactElement {
  const key = React.useRef(1);
  const [showUploadDialog, setShowUploadDialog] = React.useState(false);

  const [list, setList] = React.useState<undefined | OTAUpdate[]>();

  const load = async () => {
    const list = await OTAAPI.ListOTAUpdates();
    list.sort((a, b) =>
      `${a.platform}#${a.version}`.localeCompare(`${b.platform}#${b.version}`)
    );
    list.reverse();
    setList(list);
  };

  const reload = async () => {
    key.current += 1;
    setList(undefined);
  };

  return (
    <SolarEnergyRouteContainer
      label="OTA"
      actions={
        <span>
          <Tooltip title="Refresh the list of updates">
            <IconButton onClick={reload}>
              <RefreshIcon />
            </IconButton>
          </Tooltip>
          <Tooltip title="Upload a new update">
            <IconButton onClick={() => setShowUploadDialog(true)}>
              <FileUploadIcon />
            </IconButton>
          </Tooltip>
        </span>
      }
    >
      {showUploadDialog && (
        <UploadUpdateDialog
          platforms={p.platforms}
          onClose={() => setShowUploadDialog(false)}
          onCreated={() => {
            setShowUploadDialog(false);
            reload();
          }}
        />
      )}
      <AsyncWidget
        loadKey={key.current}
        ready={!!list}
        errMsg="Failed to load the list of OTA updates!"
        load={load}
        build={() => <_OTAList list={list!} onReload={reload} />}
      />
    </SolarEnergyRouteContainer>
  );
}

function _OTAList(p: {
  list: OTAUpdate[];
  onReload: () => void;
}): React.ReactElement {
  const alert = useAlert();
  const confirm = useConfirm();
  const loadingMessage = useLoadingMessage();
  const snackbar = useSnackbar();

  const [deployUpdate, setDeployUpdate] = React.useState<
    OTAUpdate | undefined
  >();

  const deleteUpdate = async (update: OTAUpdate) => {
    if (
      !(await confirm(
        `Do you really want to delete the update for platform ${update.platform} version ${update.version}?`
      ))
    )
      return;

    try {
      loadingMessage.show("Deleting update...");

      await OTAAPI.DeleteUpdate(update);

      snackbar("The update was successfully deleted!");

      p.onReload();
    } catch (e) {
      console.error("Failed to delete update!", e);
      alert(`Failed to delete the update! ${e}`);
    } finally {
      loadingMessage.hide();
    }
  };

  return (
    <>
      {deployUpdate && (
        <DeployOTAUpdateDialogProvider
          update={deployUpdate!}
          onClose={() => setDeployUpdate(undefined)}
        />
      )}
      <TableContainer component={Paper}>
        <Table sx={{ minWidth: 650 }} aria-label="simple table">
          <TableHead>
            <TableRow>
              <TableCell align="center">Platform</TableCell>
              <TableCell align="center">Version</TableCell>
              <TableCell align="center">File size</TableCell>
              <TableCell align="center"></TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {p.list.map((row, num) => (
              <TableRow hover key={num}>
                <TableCell align="center">{row.platform}</TableCell>
                <TableCell align="center">{row.version}</TableCell>
                <TableCell align="center">{filesize(row.file_size)}</TableCell>
                <TableCell align="center">
                  <Tooltip title="Deploy the update to devices">
                    <IconButton onClick={() => setDeployUpdate(row)}>
                      <Icon path={mdiFolderUploadOutline} size={1} />
                    </IconButton>
                  </Tooltip>
                  <Tooltip title="Download a copy of the firmware">
                    <RouterLink to={OTAAPI.DownloadOTAUpdateURL(row)}>
                      <IconButton>
                        <DownloadIcon />
                      </IconButton>
                    </RouterLink>
                  </Tooltip>
                  <Tooltip title="Delete firmware update">
                    <IconButton onClick={() => deleteUpdate(row)}>
                      <DeleteIcon />
                    </IconButton>
                  </Tooltip>
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
    </>
  );
}
