import {
  Button,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
} from "@mui/material";
import React from "react";
import { ServerApi } from "../api/ServerApi";
import {
  TokensApi,
  type BaseToken,
  type TokenWithSecret,
} from "../api/TokensApi";
import { useAlert } from "../hooks/contexts_provider/AlertDialogProvider";
import { useLoadingMessage } from "../hooks/contexts_provider/LoadingMessageProvider";
import { time } from "../utils/DateUtils";
import {
  checkConstraint,
  checkNumberConstraint,
  isIPNetworkValid,
} from "../utils/FormUtils";
import { CheckboxInput } from "../widgets/forms/CheckboxInput";
import { DateInput } from "../widgets/forms/DateInput";
import { NetworksInput } from "../widgets/forms/NetworksInput";
import { TextInput } from "../widgets/forms/TextInput";

const SECS_IN_DAY = 3600 * 24;

export function CreateTokenDialog(p: {
  open: boolean;
  onClose: () => void;
  onCreated: (t: TokenWithSecret) => void;
}): React.ReactElement {
  const alert = useAlert();
  const loadingMessage = useLoadingMessage();

  const [newTokenUndef, setNewToken] = React.useState<BaseToken | undefined>();
  const newToken: BaseToken = newTokenUndef ?? {
    name: "",
    max_inactivity: 3600 * 24 * 90,
    read_only: false,
  };

  const valid =
    checkConstraint(ServerApi.Config.constraints.token_name, newToken.name) ===
      undefined &&
    checkNumberConstraint(
      ServerApi.Config.constraints.token_max_inactivity,
      newToken.max_inactivity
    ) === undefined &&
    (newToken.networks === undefined ||
      newToken.networks.every((n) => isIPNetworkValid(n)));

  const handleSubmit = async () => {
    try {
      loadingMessage.show("Creating access token...");
      const token = await TokensApi.Create(newToken);
      p.onCreated(token);

      // Clear form
      setNewToken(undefined);
    } catch (e) {
      console.error(`Failed to create token! ${e}`);
      alert(`Failed to create API token! ${e}`);
    } finally {
      loadingMessage.hide();
    }
  };

  return (
    <Dialog open={p.open} onClose={p.onClose}>
      <DialogTitle>Create new API token</DialogTitle>
      <DialogContent>
        <TextInput
          editable
          required
          label="Token name"
          value={newToken.name}
          onValueChange={(v) => {
            setNewToken({
              ...newToken,
              name: v ?? "",
            });
          }}
          size={ServerApi.Config.constraints.token_name}
        />

        <NetworksInput
          editable
          label="Allowed networks (CIDR notation)"
          value={newToken.networks}
          onChange={(v) => {
            setNewToken({
              ...newToken,
              networks: v,
            });
          }}
        />

        <TextInput
          editable
          required
          label="Max inactivity period (days)"
          type="number"
          value={(newToken.max_inactivity / SECS_IN_DAY).toString()}
          onValueChange={(i) => {
            setNewToken({
              ...newToken,
              max_inactivity: Number(i) * SECS_IN_DAY,
            });
          }}
          size={{
            min:
              ServerApi.Config.constraints.token_max_inactivity.min /
              SECS_IN_DAY,
            max:
              ServerApi.Config.constraints.token_max_inactivity.max /
              SECS_IN_DAY,
          }}
        />

        <DateInput
          editable
          label="Expiration date (optional)"
          value={newToken.expiration}
          onChange={(i) => {
            setNewToken((t) => {
              return {
                ...(t ?? newToken),
                expiration: i ?? undefined,
              };
            });
          }}
          disablePast
          checkValue={(s) => s > time()}
        />

        <CheckboxInput
          editable
          label="Read only"
          checked={newToken.read_only}
          onValueChange={(v) => {
            setNewToken({
              ...newToken,
              read_only: v,
            });
          }}
        />
      </DialogContent>
      <DialogActions>
        <Button onClick={p.onClose}>Cancel</Button>
        <Button onClick={handleSubmit} disabled={!valid} autoFocus>
          Create token
        </Button>
      </DialogActions>
    </Dialog>
  );
}
