import { Button } from "../../../elements/Button";
import { Component, createRef } from "preact";
import { CopyableBox } from "../../../elements/CopyableBox";
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
import { ErrorMessage, sendErrorNotification } from "../../../elements/ErrorMessage";
import { Form } from "../../../elements/Form";
import { Margin } from "../../../elements/Margin";
import { SecretTitleElement } from "../SecretTitleElement";
import { TransitKeyType } from "../../../../api/types/transit";
import { objectToMap } from "../../../../utils";
import i18next from "i18next";

type versionOption = { version: string; label: string };

type TransitRewrapState = {
  transitKey: TransitKeyType;
  ciphertext: string;
};

export class TransitRewrap extends Component<DefaultPageProps, TransitRewrapState> {
  errorMessageRef = createRef<ErrorMessage>();

  async componentDidMount() {
    const baseMount = this.props.matches["baseMount"];
    const secretItem = this.props.matches["secretItem"];

    try {
      const transitKey = await this.props.api.getTransitKey(baseMount, secretItem);
      this.setState({ transitKey });
    } catch (e: unknown) {
      const error = e as Error;
      sendErrorNotification(error.message);
    }
  }

  render() {
    if (!this.state.transitKey) return;

    const baseMount = this.props.matches["baseMount"];
    const secretItem = this.props.matches["secretItem"];

    const title = (
      <SecretTitleElement
        type="transit"
        baseMount={baseMount}
        item={secretItem}
        suffix={i18next.t("transit_rewrap_suffix")}
      />
    );

    if (!this.state.ciphertext) {
      const stringVersions = Array.from(
        objectToMap(this.state.transitKey.keys).keys(),
      ).reverse() as unknown as string[];

      const versions = stringVersions.map((val): number => parseInt(val, 10));

      // get the selectable version options in the same
      // format the official UI uses.
      // e.g: ["2 (latest)", "1"]

      const options: versionOption[] = versions.map((val): versionOption => {
        const i18nkey =
          val == Math.max(...versions)
            ? "transit_rewrap_latest_version_option_text"
            : "transit_rewrap_version_option_text";
        return {
          version: String(val),
          label: i18next.t(i18nkey, { version_num: String(val) }),
        };
      });

      return (
        <>
          {title}
          <Form onSubmit={async (data) => await this.onSubmit(data)}>
            <Margin>
              <select class="uk-select uk-width-1-2" name="version">
                {options.map((option) => (
                  <option label={option.label} value={option.version}>
                    {option.label}
                  </option>
                ))}
              </select>
            </Margin>
            <Margin>
              <textarea
                class="uk-textarea uk-width-1-2"
                name="ciphertext"
                placeholder={i18next.t("transit_rewrap_input_placeholder")}
              />
            </Margin>

            <Margin>
              <ErrorMessage ref={this.errorMessageRef} />
            </Margin>

            <Button text={i18next.t("transit_rewrap")} color="primary" type="submit" />
          </Form>
        </>
      );
    } else {
      return (
        <>
          {title}
          <CopyableBox
            title={i18next.t("transit_rewrap_result_title")}
            contentString={this.state.ciphertext}
            goBack={() => {
              this.setState({ ciphertext: null });
            }}
          />
        </>
      );
    }
  }

  async onSubmit(data: FormData): Promise<void> {
    const baseMount = this.props.matches["baseMount"];
    const secretItem = this.props.matches["secretItem"];
    try {
      const res = await this.props.api.transitRewrap(baseMount, secretItem, {
        ciphertext: data.get("ciphertext") as string,
        key_version: parseInt(data.get("version") as string, 10),
      });
      this.setState({ ciphertext: res.ciphertext });
    } catch (e: unknown) {
      const error = e as Error;
      this.errorMessageRef.current.setErrorMessage(error.message);
    }
  }
}