import AddIcon from "@mui/icons-material/Add";
import RefreshIcon from "@mui/icons-material/Refresh";
import { Alert, AlertTitle, IconButton, Tooltip } from "@mui/material";
import type { GridColDef } from "@mui/x-data-grid";
import { DataGrid, GridActionsCellItem } from "@mui/x-data-grid";
import { QRCodeCanvas } from "qrcode.react";
import React from "react";
import { APIClient } from "../api/ApiClient";
import { TokensApi, type Token, type TokenWithSecret } from "../api/TokensApi";
import { CreateTokenDialog } from "../dialogs/CreateTokenDialog";
import { AsyncWidget } from "../widgets/AsyncWidget";
import { CopyTextChip } from "../widgets/CopyTextChip";
import { MatrixGWRouteContainer } from "../widgets/MatrixGWRouteContainer";
import { TimeWidget } from "../widgets/TimeWidget";
import DeleteIcon from "@mui/icons-material/DeleteOutlined";
import { useSnackbar } from "../hooks/contexts_provider/SnackbarProvider";
import { useConfirm } from "../hooks/contexts_provider/ConfirmDialogProvider";
import { useAlert } from "../hooks/contexts_provider/AlertDialogProvider";
import { time } from "../utils/DateUtils";

export function APITokensRoute(): React.ReactElement {
  const count = React.useRef(0);

  const [openCreateTokenDialog, setOpenCreateTokenDialog] =
    React.useState(false);

  const [createdToken, setCreatedToken] =
    React.useState<TokenWithSecret | null>(null);

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

  const load = async () => {
    setList(await TokensApi.GetList());
  };

  const handleRefreshTokensList = () => {
    count.current += 1;
    setList(undefined);
  };

  const handleOpenCreateTokenDialog = () => setOpenCreateTokenDialog(true);

  const handleCancelCreateToken = () => setOpenCreateTokenDialog(false);

  const handleCreatedToken = (s: TokenWithSecret) => {
    setCreatedToken(s);
    setOpenCreateTokenDialog(false);
    handleRefreshTokensList();
  };

  return (
    <MatrixGWRouteContainer
      label={"API tokens"}
      actions={
        <span>
          <Tooltip title="Create new token">
            <IconButton onClick={handleOpenCreateTokenDialog}>
              <AddIcon />
            </IconButton>
          </Tooltip>
          &nbsp;&nbsp;
          <Tooltip title="Refresh tokens list">
            <IconButton onClick={handleRefreshTokensList}>
              <RefreshIcon />
            </IconButton>
          </Tooltip>
        </span>
      }
    >
      {/* Create token dialog anchor */}
      <CreateTokenDialog
        open={openCreateTokenDialog}
        onCreated={handleCreatedToken}
        onClose={handleCancelCreateToken}
      />

      {/* Info about created token */}
      {createdToken && <CreatedToken token={createdToken!} />}

      {/* Tokens list */}
      <AsyncWidget
        loadKey={count.current}
        ready={list !== undefined}
        load={load}
        errMsg="Failed to load the list of tokens!"
        build={() => (
          <TokensListGrid list={list!} onReload={handleRefreshTokensList} />
        )}
      />
    </MatrixGWRouteContainer>
  );
}

function CreatedToken(p: { token: TokenWithSecret }): React.ReactElement {
  return (
    <Alert severity="success" style={{ margin: "10px" }}>
      <div
        style={{
          display: "flex",
          flexDirection: "row",
        }}
      >
        <div style={{ textAlign: "center", marginRight: "10px" }}>
          <div style={{ padding: "15px", backgroundColor: "white" }}>
            <QRCodeCanvas
              value={`matrixgw://api=${encodeURIComponent(
                APIClient.ActualBackendURL()
              )}&id=${p.token.id}&secret=${p.token.secret}`}
            />
          </div>
          <br />
          <em>Mobile App Qr Code</em>
        </div>
        <div>
          <AlertTitle>Token successfully created</AlertTitle>
          The API token <i>{p.token.name}</i> was successfully created. Please
          note the following information as they won't be available after.
          <br />
          <br />
          API URL: <CopyTextChip text={APIClient.ActualBackendURL()} />
          <br />
          Token ID: <CopyTextChip text={p.token.id.toString()} />
          <br />
          Token secret: <CopyTextChip text={p.token.secret} />
        </div>
      </div>
    </Alert>
  );
}

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

  // Delete a token
  const handleDeleteClick = (token: Token) => async () => {
    try {
      if (
        !(await confirm(
          `Do you really want to delete the token named '${token.name}' ?`
        ))
      )
        return;

      await TokensApi.Delete(token);
      p.onReload();

      snackbar("The token was successfully deleted!");
    } catch (e) {
      console.error(e);
      alert(`Failed to delete API token! ${e}`);
    }
  };

  const columns: GridColDef<(typeof p.list)[number]>[] = [
    { field: "id", headerName: "ID", flex: 1 },
    {
      field: "name",
      headerName: "Name",
      flex: 3,
    },
    {
      field: "networks",
      headerName: "Networks restriction",
      flex: 3,
      renderCell(params) {
        return (
          params.row.networks?.join(", ") ?? (
            <span style={{ fontStyle: "italic" }}>Unrestricted</span>
          )
        );
      },
    },
    {
      field: "created",
      headerName: "Creation",
      flex: 3,
      renderCell(params) {
        return <TimeWidget time={params.row.created} />;
      },
    },
    {
      field: "last_used",
      headerName: "Last usage",
      flex: 3,
      renderCell(params) {
        return (
          <span
            style={{
              color:
                params.row.last_used + params.row.max_inactivity < time()
                  ? "red"
                  : undefined,
            }}
          >
            <TimeWidget time={params.row.last_used} />
          </span>
        );
      },
    },
    {
      field: "max_inactivity",
      headerName: "Max inactivity",
      flex: 3,
      renderCell(params) {
        return (
          <span
            style={{
              color:
                params.row.last_used + params.row.max_inactivity < time()
                  ? "red"
                  : undefined,
            }}
          >
            <TimeWidget time={params.row.max_inactivity} isDuration />
          </span>
        );
      },
    },
    {
      field: "expiration",
      headerName: "Expiration",
      flex: 3,
      renderCell(params) {
        return (
          <span
            style={{
              color:
                params.row.expiration && params.row.expiration < time()
                  ? "red"
                  : undefined,
            }}
          >
            <TimeWidget time={params.row.expiration} showDate />
          </span>
        );
      },
    },
    {
      field: "read_only",
      headerName: "Read only",
      flex: 2,
      type: "boolean",
    },
    {
      field: "actions",
      type: "actions",
      headerName: "Actions",
      flex: 2,
      cellClassName: "actions",
      getActions: ({ row }) => {
        return [
          <GridActionsCellItem
            key={row.id}
            icon={<DeleteIcon />}
            label="Delete"
            onClick={handleDeleteClick(row)}
            color="inherit"
          />,
        ];
      },
    },
  ];

  if (p.list.length === 0)
    return (
      <div
        style={{
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
        }}
      >
        You do not have created any token yet!
      </div>
    );

  return (
    <DataGrid
      style={{ flex: "1" }}
      rows={p.list}
      columns={columns}
      autoPageSize
      getRowId={(c) => c.id}
      isCellEditable={() => false}
      isRowSelectable={() => false}
    />
  );
}
