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

export function TokensRoute(): React.ReactElement {
  const count = React.useRef(0);
  const [list, setList] = React.useState<Token[] | undefined>();

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

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

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

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

  const onRequestCreateToken = () => {
    setOpenCreateTokenDialog(true);
  };

  const closeCreateTokenDialog = () => {
    setOpenCreateTokenDialog(false);
  };

  const onCreatedToken = (t: TokenWithSecret) => {
    setOpenCreateTokenDialog(false);
    setCreatedToken(t);
    reload();
  };

  return (
    <AsyncWidget
      loadKey={count.current}
      ready={list !== undefined}
      load={load}
      errMsg="Failed to load API token list!"
      build={() => (
        <>
          <CreateTokenDialog
            open={openCreateTokenDialog}
            onClose={closeCreateTokenDialog}
            onCreated={onCreatedToken}
          />

          <TokensRouteInner
            list={list!}
            onReload={reload}
            onRequestCreateToken={onRequestCreateToken}
            createdToken={createdToken}
          />
        </>
      )}
    />
  );
}

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

  // Delete a token
  const handleDeleteClick = (id: GridRowId) => async () => {
    try {
      const token = p.list.find((t) => t.id === id)!;
      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[] = [
    { field: "id", headerName: "ID", flex: 1 },
    {
      field: "name",
      headerName: "Name",
      flex: 3,
    },
    {
      field: "ip_net",
      headerName: "IP restriction",
      flex: 3,
      renderCell(params) {
        return (
          params.row.ip_net ?? (
            <span style={{ fontStyle: "italic" }}>Unrestricted</span>
          )
        );
      },
    },
    {
      field: "time_create",
      headerName: "Creation",
      flex: 3,
      renderCell(params) {
        return <TimeWidget time={params.row.time_create} />;
      },
    },
    {
      field: "time_used",
      headerName: "Last usage",
      flex: 3,
      renderCell(params) {
        return <TimeWidget time={params.row.time_used} />;
      },
    },
    {
      field: "max_inactivity",
      headerName: "Max inactivity",
      flex: 3,
      renderCell(params) {
        return <TimeWidget time={params.row.max_inactivity} isDuration />;
      },
    },
    {
      field: "read_only",
      headerName: "Read only",
      flex: 2,
      type: "boolean",
    },
    {
      field: "right_account",
      headerName: "Account",
      flex: 2,
      type: "boolean",
    },
    {
      field: "right_movement",
      headerName: "Movement",
      flex: 2,
      type: "boolean",
    },
    {
      field: "right_inbox",
      headerName: "Inbox",
      flex: 2,
      type: "boolean",
    },
    {
      field: "right_file",
      headerName: "File",
      flex: 2,
      type: "boolean",
    },
    {
      field: "right_auth",
      headerName: "Auth",
      flex: 2,
      type: "boolean",
    },
    {
      field: "right_stats",
      headerName: "Stats",
      flex: 2,
      type: "boolean",
    },
    {
      field: "right_backup",
      headerName: "Backup",
      flex: 2,
      type: "boolean",
    },
    {
      field: "actions",
      type: "actions",
      headerName: "Actions",
      flex: 2,
      cellClassName: "actions",
      getActions: ({ id }) => {
        return [
          <GridActionsCellItem
            key={id}
            icon={<DeleteIcon />}
            label="Delete"
            onClick={handleDeleteClick(id)}
            color="inherit"
          />,
        ];
      },
    },
  ];

  return (
    <MoneyMgrWebRouteContainer
      label="API Tokens"
      actions={
        <span>
          <Tooltip title="Create new token">
            <IconButton onClick={p.onRequestCreateToken}>
              <AddIcon />
            </IconButton>
          </Tooltip>
          <Tooltip title="Refresh table">
            <IconButton onClick={p.onReload}>
              <RefreshIcon />
            </IconButton>
          </Tooltip>
        </span>
      }
    >
      {p.createdToken && <CreatedToken token={p.createdToken} />}
      <DataGrid
        style={{ flex: "1" }}
        rows={p.list}
        columns={columns}
        autoPageSize
        getRowId={(c) => c.id}
        isCellEditable={() => false}
        isRowSelectable={() => false}
      />
    </MoneyMgrWebRouteContainer>
  );
}

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={`moneymgr://api=${encodeURIComponent(
                APIClient.backendURL()
              )}&id=${p.token.id}&secret=${p.token.token}`}
            />
          </div>
          <br />
          <em>Mobile App Qr Code</em>
        </div>
        <div>
          <AlertTitle>Token successfully created</AlertTitle>
          The API token was successfully created. Please note the following
          information as they won't be available next.
          <br />
          Token ID: <CopyTextChip text={p.token.id.toString()} />
          <br />
          Token value: <CopyTextChip text={p.token.token} />
        </div>
      </div>
    </Alert>
  );
}
