import { Button } from "@mui/material";
import Grid from "@mui/material/Grid";
import React from "react";
import { useNavigate } from "react-router-dom";
import { GroupApi } from "../../api/GroupApi";
import { NWFilter, NWFilterApi } from "../../api/NWFilterApi";
import { NetworkApi, NetworkInfo } from "../../api/NetworksApi";
import { ServerApi } from "../../api/ServerApi";
import { APIToken, TokensApi } from "../../api/TokensApi";
import { VMApi, VMInfo } from "../../api/VMApi";
import { useAlert } from "../../hooks/providers/AlertDialogProvider";
import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
import { useSnackbar } from "../../hooks/providers/SnackbarProvider";
import { AsyncWidget } from "../AsyncWidget";
import { TabsWidget } from "../TabsWidget";
import { EditSection } from "../forms/EditSection";
import { IPInputWithMask } from "../forms/IPInput";
import { RadioGroupInput } from "../forms/RadioGroupInput";
import { TextInput } from "../forms/TextInput";
import { TokenRawRightsEditor } from "./TokenRawRightsEditor";
import { TokenRightsEditor } from "./TokenRightsEditor";

const SECS_PER_DAY = 3600 * 24;

export enum TokenWidgetStatus {
  Create,
  Read,
  Update,
}

interface DetailsProps {
  token: APIToken;
  status: TokenWidgetStatus;
  onChange?: () => void;
}

export function APITokenDetails(p: DetailsProps): React.ReactElement {
  const [vms, setVMs] = React.useState<VMInfo[]>();
  const [groups, setGroups] = React.useState<string[]>();
  const [networks, setNetworks] = React.useState<NetworkInfo[]>();
  const [nwFilters, setNetworkFilters] = React.useState<NWFilter[]>();
  const [tokens, setTokens] = React.useState<APIToken[]>();

  const load = async () => {
    setVMs(await VMApi.GetList());
    setGroups(await GroupApi.GetList());
    setNetworks(await NetworkApi.GetList());
    setNetworkFilters(await NWFilterApi.GetList());
    setTokens(await TokensApi.GetList());
  };

  return (
    <AsyncWidget
      loadKey={"1"}
      load={load}
      errMsg="Failed to load some system entities!"
      build={() => (
        <APITokenDetailsInner
          vms={vms!}
          groups={groups!}
          networks={networks!}
          nwFilters={nwFilters!}
          tokens={tokens!}
          {...p}
        />
      )}
    />
  );
}

enum TokenTab {
  General = 0,
  Rights,
  RawRights,
  Danger,
}

type DetailsInnerProps = DetailsProps & {
  vms: VMInfo[];
  groups: string[];
  networks: NetworkInfo[];
  nwFilters: NWFilter[];
  tokens: APIToken[];
};

function APITokenDetailsInner(p: DetailsInnerProps): React.ReactElement {
  const [currTab, setCurrTab] = React.useState(TokenTab.General);

  return (
    <>
      <TabsWidget
        currTab={currTab}
        onTabChange={setCurrTab}
        options={[
          { label: "General", value: TokenTab.General, visible: true },
          {
            label: "Rights",
            value: TokenTab.Rights,
            visible: true,
          },
          {
            label: "Raw rights",
            value: TokenTab.RawRights,
            visible: true,
          },

          {
            label: "Danger zone",
            value: TokenTab.Danger,
            color: "red",
            visible: p.status === TokenWidgetStatus.Read,
          },
        ]}
      />
      {currTab === TokenTab.General && <APITokenTabGeneral {...p} />}
      {currTab === TokenTab.Rights && <APITokenRights {...p} />}
      {currTab === TokenTab.RawRights && <APITokenRawRights {...p} />}
      {currTab === TokenTab.Danger && <APITokenTabDanger {...p} />}
    </>
  );
}

function APITokenTabGeneral(p: DetailsInnerProps): React.ReactElement {
  const [ipVersion, setIpVersion] = React.useState<4 | 6>(
    (p.token.ip_restriction ?? "").includes(":") ? 6 : 4
  );

  return (
    <Grid container spacing={2}>
      {/* Metadata section */}
      <EditSection title="Metadata">
        {p.status !== TokenWidgetStatus.Create && (
          <TextInput label="UUID" editable={false} value={p.token.id} />
        )}

        <TextInput
          label="Name"
          editable={p.status === TokenWidgetStatus.Create}
          value={p.token.name}
          onValueChange={(v) => {
            p.token.name = v ?? "";
            p.onChange?.();
          }}
          size={ServerApi.Config.constraints.api_token_name_size}
        />

        <TextInput
          label="Description"
          editable={p.status === TokenWidgetStatus.Create}
          value={p.token.description}
          onValueChange={(v) => {
            p.token.description = v ?? "";
            p.onChange?.();
          }}
          multiline={true}
          size={ServerApi.Config.constraints.api_token_description_size}
        />
      </EditSection>

      <EditSection title="General settings">
        {p.status === TokenWidgetStatus.Create && (
          <RadioGroupInput
            {...p}
            editable={p.status === TokenWidgetStatus.Create}
            options={[
              { label: "IPv4", value: "4" },
              { label: "IPv6", value: "6" },
            ]}
            value={ipVersion.toString()}
            onValueChange={(v) => {
              setIpVersion(Number(v) as any);
            }}
            label="Token IP restriction version"
          />
        )}
        <IPInputWithMask
          {...p}
          label="Token IP network restriction"
          ipAndMask={p.token.ip_restriction}
          editable={p.status === TokenWidgetStatus.Create}
          version={ipVersion}
          onValueChange={(_ip, _mask, ipAndMask) => {
            p.token.ip_restriction = ipAndMask;
            p.onChange?.();
          }}
        />

        <TextInput
          editable={p.status === TokenWidgetStatus.Create}
          label="Max inactivity of tokens (days)"
          type="number"
          value={
            p.token.max_inactivity
              ? Math.floor(p.token.max_inactivity / SECS_PER_DAY).toString()
              : ""
          }
          onValueChange={(v) => {
            const secs = Number(v ?? "0") * SECS_PER_DAY;
            p.token.max_inactivity = secs === 0 ? undefined : secs;
            p.onChange?.();
          }}
        />
      </EditSection>
    </Grid>
  );
}

function APITokenRights(p: DetailsInnerProps): React.ReactElement {
  return (
    <div style={{ padding: "30px" }}>
      <TokenRightsEditor
        {...p}
        editable={p.status !== TokenWidgetStatus.Read}
      />
    </div>
  );
}

function APITokenRawRights(p: DetailsInnerProps): React.ReactElement {
  return (
    <div style={{ padding: "30px" }}>
      <TokenRawRightsEditor
        {...p}
        editable={p.status !== TokenWidgetStatus.Read}
      />
    </div>
  );
}

function APITokenTabDanger(p: DetailsInnerProps): React.ReactElement {
  const confirm = useConfirm();
  const snackbar = useSnackbar();
  const alert = useAlert();
  const navigate = useNavigate();

  const requestDelete = async () => {
    try {
      if (
        !(await confirm(
          "Do you really want to delete this API token?",
          `Delete API token ${p.token.name}`,
          "Delete"
        ))
      )
        return;

      await TokensApi.Delete(p.token);

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

  return (
    <Button color="error" onClick={requestDelete}>
      Delete this API token
    </Button>
  );
}