/*
 This file is part of GNU Taler
 (C) 2021-2024 Taler Systems S.A.

 GNU Taler is free software; you can redistribute it and/or modify it under the
 terms of the GNU General Public License as published by the Free Software
 Foundation; either version 3, or (at your option) any later version.

 GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with
 GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */

/**
 *
 * @author Sebastian Javier Marchano (sebasjm)
 */

import {
  assertUnreachable,
  HttpStatusCode,
  TalerMerchantApi,
} from "@gnu-taler/taler-util";
import {
  ButtonBetterBulma,
  LocalNotificationBannerBulma,
  useLocalNotificationBetter,
  useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import {
  FormErrors,
  FormProvider,
} from "../../../../components/form/FormProvider.js";
import { Input } from "../../../../components/form/Input.js";
import { InputSelector } from "../../../../components/form/InputSelector.js";
import { undefinedIfEmpty } from "../../../../utils/table.js";
import { useSessionContext } from "../../../../context/session.js";
import { Tooltip } from "../../../../components/Tooltip.js";

const TALER_SCREEN_ID = 76;

type Entity = TalerMerchantApi.WebhookAddDetails;

interface Props {
  onCreate: () => void;
  onBack?: () => void;
}

const validType = [
  "pay",
  "refund",
  "order_settled",
  "category_added",
  "category_updated",
  "category_deleted",
  "inventory_added",
  "inventory_updated",
  "inventory_deleted",
] as const;
const validMethod = ["GET", "POST", "PUT", "PATCH", "HEAD"];

export function CreatePage({ onCreate, onBack }: Props): VNode {
  const { i18n } = useTranslationContext();

  const [state, setState] = useState<Partial<Entity>>({});
  const [notification, safeFunctionHandler] = useLocalNotificationBetter();

  const { state: session, lib } = useSessionContext();
  const errors = undefinedIfEmpty<FormErrors<Entity>>({
    webhook_id: !state.webhook_id ? i18n.str`Required` : undefined,
    event_type: !state.event_type
      ? i18n.str`Required`
      : // @ts-ignore checking if event type is on the valid list
        validType.indexOf(state.event_type) === -1
        ? i18n.str`Must be one of '${validType.join(", ")}'`
        : undefined,
    http_method: !state.http_method
      ? i18n.str`Required`
      : validMethod.indexOf(state.http_method) === -1
        ? i18n.str`Must be one of '${validMethod.join(", ")}'`
        : undefined,
    url: !state.url
      ? i18n.str`Required`
      : isInvalidUrl(state.url)
        ? i18n.str`URL is invalid`
        : undefined,
  });

  const hasErrors = errors !== undefined;

  const data = state as TalerMerchantApi.WebhookAddDetails;

  const create = safeFunctionHandler(
    i18n.str`add webhook`,
    lib.instance.addWebhook.bind(lib.instance),
    !session.token || hasErrors ? undefined : [session.token, data],
  );
  create.onSuccess = onCreate;
  create.onFail = (fail) => {
    switch (fail.case) {
      case HttpStatusCode.Unauthorized:
        return i18n.str`Unauthorized.`;
      case HttpStatusCode.NotFound:
        return i18n.str`Not found.`;
      default:
        assertUnreachable(fail);
    }
  };

  return (
    <div>
      <LocalNotificationBannerBulma notification={notification} />
      <section class="section is-main-section">
        <div class="columns">
          <div class="column" />
          <div class="column is-four-fifths">
            <FormProvider
              object={state}
              valueHandler={setState}
              errors={errors}
            >
              <Input<Entity>
                name="webhook_id"
                label={i18n.str`ID`}
                tooltip={i18n.str`Webhook ID to use`}
              />
              {/* <Input<Entity>
                name="webhook_id"
                label={i18n.str`ID`}
                tooltip={i18n.str`Super long string that will make the tooltip very big. Super long string that will make the tooltip very big. Super long string that will make the tooltip very big. Super long string that will make the tooltip very big.`}
              />
              <Input<Entity>
                name="webhook_id"
                label={i18n.str`Medium size field`}
                tooltip={i18n.str`Super long string that will make the tooltip very big. Super long string that will make the tooltip very big. Super long string that will make the tooltip very big. Super long string that will make the tooltip very big.`}
              />
              <Input<Entity>
                name="webhook_id"
                label={i18n.str`Large field name that is close to edge`}
                tooltip={i18n.str`Super long string that will make the tooltip very big. Super long string that will make the tooltip very big. Super long string that will make the tooltip very big. Super long string that will make the tooltip very big.`}
              /> */}
              <InputSelector
                name="event_type"
                label={i18n.str`Event`}
                values={["choose", ...validType]}
                toStr={(v) => {
                  const idx = validType.indexOf(v);
                  if (idx === -1) return i18n.str`Choose one...`;
                  const d = validType[idx];
                  switch (d) {
                    case "pay":
                      return i18n.str`Payment`;
                    case "refund":
                      return i18n.str`Refund`;
                    case "order_settled":
                      return i18n.str`Order settled`;
                    case "category_added":
                      return i18n.str`Category added`;
                    case "category_updated":
                      return i18n.str`Category updated`;
                    case "category_deleted":
                      return i18n.str`Category deleted`;
                    case "inventory_added":
                      return i18n.str`Inventory added`;
                    case "inventory_updated":
                      return i18n.str`Inventory updated`;
                    case "inventory_deleted":
                      return i18n.str`Inventory deleted`;
                    default: {
                      assertUnreachable(d);
                    }
                  }
                }}
                tooltip={i18n.str`The event of the webhook: why the webhook is used`}
              />
              <InputSelector
                name="http_method"
                label={i18n.str`Method`}
                toStr={(v) => {
                  const idx = validMethod.indexOf(v);
                  if (idx === -1) return i18n.str`Choose one...`;
                  return [
                    i18n.str`GET`,
                    i18n.str`POST`,
                    i18n.str`PUT`,
                    i18n.str`PATCH`,
                    i18n.str`HEAD`,
                  ][idx];
                }}
                values={["choose", ...validMethod]}
                tooltip={i18n.str`Method used by the webhook`}
              />

              <Input<Entity>
                name="url"
                label={i18n.str`URL`}
                tooltip={i18n.str`URL of the webhook where the customer will be redirected`}
              />

              <p>
                {/* prettier will add some nodes which we don't want because of i18n */}
                {/* prettier-ignore */}
                <i18n.Translate>
                  The text below supports the <a
                    target="_blank"
                    rel="noreferrer"
                    href="https://mustache.github.io/mustache.5.html"
                  >
                    mustache
                  </a> template engine. Any string between <pre style={{ display: "inline", padding: 0 }}>
                    &#123;&#123;
                  </pre> and <pre style={{ display: "inline", padding: 0 }}>
                    &#125;&#125;
                  </pre> will be replaced with the value of the corresponding variable.
                </i18n.Translate>
              </p>
              <p>
                {/* prettier will add some nodes which we don't want because of i18n */}
                {/* prettier-ignore */}
                <i18n.Translate>
                  For example, <pre style={{ display: "inline", padding: 0 }}>
                    &#123;&#123;contract_terms.amount&#125;&#125;
                  </pre> will be replaced with the the order's price.
                </i18n.Translate>
              </p>
              <p>
                <i18n.Translate>
                  The short list of variables are:
                </i18n.Translate>
              </p>
              <div class="menu">
                <ul
                  class="menu-list"
                  style={{ listStyleType: "disc", marginLeft: 20 }}
                >
                  <li>
                    <b>contract_terms.summary:</b>{" "}
                    <i18n.Translate>order's description</i18n.Translate>
                  </li>
                  <li>
                    <b>contract_terms.amount:</b>{" "}
                    <i18n.Translate>order's price</i18n.Translate>
                  </li>
                  <li>
                    <b>order_id:</b>{" "}
                    <i18n.Translate>
                      order's unique identification
                    </i18n.Translate>
                  </li>
                  {state.event_type === "refund" && (
                    <Fragment>
                      <li>
                        <b>refund_amout:</b>{" "}
                        <i18n.Translate>
                          the amount that was being refunded
                        </i18n.Translate>
                      </li>
                      <li>
                        <b>reason:</b>{" "}
                        <i18n.Translate>
                          the reason entered by the merchant staff for granting
                          the refund
                        </i18n.Translate>
                      </li>
                      <li>
                        <b>timestamp:</b>{" "}
                        <i18n.Translate>
                          time of the refund in nanoseconds since 1970
                        </i18n.Translate>
                      </li>
                    </Fragment>
                  )}
                </ul>
              </div>
              <Input<Entity>
                name="header_template"
                label={i18n.str`Http header`}
                inputType="multiline"
                tooltip={i18n.str`Header template of the webhook`}
              />
              <Input<Entity>
                name="body_template"
                inputType="multiline"
                label={i18n.str`Http body`}
                tooltip={i18n.str`Body template used by the webhook.`}
              />
              <div class="buttons is-right mt-5">
                {onBack && (
                  <button type="button" class="button" onClick={onBack}>
                    <i18n.Translate>Cancel</i18n.Translate>
                  </button>
                )}
                <Tooltip
                  text={
                    hasErrors
                      ? i18n.str`Please complete the marked fields`
                      : i18n.str`Confirm operation`
                  }
                >
                  <ButtonBetterBulma type="submit" onClick={create}>
                    <i18n.Translate>Confirm</i18n.Translate>
                  </ButtonBetterBulma>
                </Tooltip>
              </div>
            </FormProvider>
          </div>
          <div class="column" />
        </div>
      </section>
    </div>
  );
}

function isInvalidUrl(url: string) {
  try {
    const asd = new URL("./", url);
    return false;
  } catch (e) {
    return true;
  }
}
