/*
 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 {
  getMerchantAccountKycStatusSimplified,
  MerchantAccountKycStatusSimplified,
  MerchantPersona,
  TalerError,
} from "@gnu-taler/taler-util";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { ComponentChildren, Fragment, h, VNode } from "preact";
import { useSessionContext } from "../../context/session.js";
import { useInstanceKYCDetailsLongPolling } from "../../hooks/instance.js";
import { UIElement, usePreference } from "../../hooks/preference.js";
import { LangSelector } from "./LangSelector.js";

const TALER_SCREEN_ID = 17;
// const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;

interface Props {
  mobile?: boolean;
}

export function Sidebar({ mobile }: Props): VNode {
  const { i18n } = useTranslationContext();
  const { state, logOut, config } = useSessionContext();
  const kycStatus = useInstanceKYCDetailsLongPolling();

  const allKycData =
    kycStatus !== undefined &&
    !(kycStatus instanceof TalerError) &&
    kycStatus.type === "ok" &&
    !!kycStatus.body
      ? kycStatus.body.kyc_data
      : [];

  const simplifiedKycStatus = allKycData.reduce((prev, cur) => {
    const st = getMerchantAccountKycStatusSimplified(cur.status);
    if (st > prev) return st;
    return prev;
  }, MerchantAccountKycStatusSimplified.OK);

  const [{ persona }] = usePreference();
  const hideKycMenuItem =
    simplifiedKycStatus === MerchantAccountKycStatusSimplified.OK &&
    persona !== "expert";

  const isLoggedIn = state.status === "loggedIn";
  const hasToken = isLoggedIn && state.token !== undefined;

  return (
    <aside
      class="aside is-placed-left is-expanded"
      style={{ overflowY: "scroll" }}
    >
      {mobile && (
        <div
          class="footer"
          onClick={(e) => {
            return e.stopImmediatePropagation();
          }}
        >
          <LangSelector />
        </div>
      )}
      <div class="aside-tools">
        <div class="aside-tools-label">
          <div>
            <b>Taler</b> Backoffice
          </div>
          <div
            class="is-size-7 has-text-right"
            style={{ lineHeight: 0, marginTop: -10 }}
          >
            {VERSION} ({config.version})
          </div>
        </div>
      </div>
      <div class="menu is-menu-main">
        {isLoggedIn ? (
          <Fragment>
            <ul class="menu-list">
              <HtmlPersonaFlag
                htmlElement="li"
                point={UIElement.sidebar_orders}
              >
                <a href={"#/orders"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-cash-register" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>Orders</i18n.Translate>
                  </span>
                </a>
              </HtmlPersonaFlag>
              <HtmlPersonaFlag
                htmlElement="li"
                point={UIElement.sidebar_inventory}
              >
                <a href={"#/inventory"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-shopping" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>Inventory</i18n.Translate>
                  </span>
                </a>
              </HtmlPersonaFlag>
              <HtmlPersonaFlag
                htmlElement="li"
                point={UIElement.sidebar_categories}
              >
                <a href={"#/category"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-label-outline" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>Categories</i18n.Translate>
                  </span>
                </a>
              </HtmlPersonaFlag>
              <HtmlPersonaFlag
                htmlElement="li"
                point={UIElement.sidebar_wireTransfers}
              >
                <a href={"#/transfers"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-arrow-left-right" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>Wire transfers</i18n.Translate>
                  </span>
                </a>
              </HtmlPersonaFlag>
              <HtmlPersonaFlag
                htmlElement="li"
                point={UIElement.sidebar_templates}
              >
                <a href={"#/templates"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-qrcode" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>Templates</i18n.Translate>
                  </span>
                </a>
              </HtmlPersonaFlag>
              <HtmlPersonaFlag
                htmlElement="li"
                point={UIElement.sidebar_statistics}
              >
                <a href={"#/statistics"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-counter" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>Statistics</i18n.Translate>
                  </span>
                </a>
              </HtmlPersonaFlag>
              <HtmlPersonaFlag
                htmlElement="li"
                point={UIElement.sidebar_tokenFamilies}
              >
                <a href={"#/tokenfamilies"} class="has-icon">
                  <span class="menu-item-label">
                    <span class="icon">
                      <i class="mdi mdi-clock" />
                    </span>
                    <i18n.Translate>Subscriptions and Discounts</i18n.Translate>
                  </span>
                </a>
              </HtmlPersonaFlag>
            </ul>
            <p class="menu-label">
              <i18n.Translate>Configuration</i18n.Translate>
            </p>
            <ul class="menu-list">
              <HtmlPersonaFlag
                htmlElement="li"
                point={UIElement.sidebar_bankAccounts}
              >
                <a href={"#/bank"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-bank" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>Bank account</i18n.Translate>
                  </span>
                </a>
              </HtmlPersonaFlag>
              {hideKycMenuItem ? undefined : (
                <HtmlPersonaFlag
                  htmlElement="li"
                  point={UIElement.sidebar_kycStatus}
                  class={
                    simplifiedKycStatus ===
                    MerchantAccountKycStatusSimplified.WARNING
                      ? "is-warning"
                      : simplifiedKycStatus ===
                          MerchantAccountKycStatusSimplified.ERROR
                        ? "is-error"
                        : simplifiedKycStatus ===
                            MerchantAccountKycStatusSimplified.ACTION_REQUIRED
                          ? "is-warning"
                          : undefined
                  }
                >
                  <a
                    href={"#/kyc"}
                    class="has-icon"
                    style={
                      simplifiedKycStatus ===
                      MerchantAccountKycStatusSimplified.WARNING
                        ? {
                            backgroundColor: "darkorange",
                            color: "black",
                          }
                        : simplifiedKycStatus ===
                            MerchantAccountKycStatusSimplified.ERROR
                          ? {
                              backgroundColor: "darkred",
                              color: "black",
                            }
                          : simplifiedKycStatus ===
                              MerchantAccountKycStatusSimplified.ACTION_REQUIRED
                            ? {
                                backgroundColor: "darkorange",
                                color: "black",
                              }
                            : undefined
                    }
                  >
                    <span class="icon">
                      <i class="mdi mdi-account-check" />
                    </span>
                    <span class="menu-item-label">KYC Status</span>
                  </a>
                </HtmlPersonaFlag>
              )}
              <HtmlPersonaFlag
                htmlElement="li"
                point={UIElement.sidebar_otpDevices}
              >
                <a href={"#/otp-devices"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-lock" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>OTP Devices</i18n.Translate>
                  </span>
                </a>
              </HtmlPersonaFlag>
              <HtmlPersonaFlag
                htmlElement="li"
                point={UIElement.sidebar_webhooks}
              >
                <a href={"#/webhooks"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-webhook" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>Webhooks</i18n.Translate>
                  </span>
                </a>
              </HtmlPersonaFlag>
              <HtmlPersonaFlag
                htmlElement="li"
                point={UIElement.sidebar_settings}
              >
                <a href={"#/settings"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-square-edit-outline" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>Settings</i18n.Translate>
                  </span>
                </a>
              </HtmlPersonaFlag>
              <HtmlPersonaFlag
                htmlElement="li"
                point={UIElement.sidebar_password}
              >
                <a href={"#/password"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-security" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>Password</i18n.Translate>
                  </span>
                </a>
              </HtmlPersonaFlag>
              <HtmlPersonaFlag
                htmlElement="li"
                point={UIElement.sidebar_accessTokens}
              >
                <a href={"#/access-token"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-key" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>Access tokens</i18n.Translate>
                  </span>
                </a>
              </HtmlPersonaFlag>
            </ul>
          </Fragment>
        ) : undefined}
        <p class="menu-label">
          <i18n.Translate>Connection</i18n.Translate>
        </p>
        <ul class="menu-list">
          <li>
            <a class="has-icon is-state-info is-hoverable" href="#/interface">
              <span class="icon">
                <i class="mdi mdi-newspaper" />
              </span>
              <span class="menu-item-label">
                <i18n.Translate>Personalization</i18n.Translate>
              </span>
            </a>
          </li>
          <li>
            <div>
              <span style={{ width: "3rem" }} class="icon">
                <i class="mdi mdi-web" />
              </span>
              <span class="menu-item-label">{state.backendUrl.hostname}</span>
            </div>
          </li>
          <li>
            <div>
              <span style={{ width: "3rem" }} class="icon">
                ID
              </span>
              <span class="menu-item-label">{state.instance}</span>
            </div>
          </li>
          {state.isAdmin && (
            <Fragment>
              <p class="menu-label">
                <i18n.Translate>Instances</i18n.Translate>
              </p>
              <li>
                <a href={"#/instance/new"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-plus" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>New</i18n.Translate>
                  </span>
                </a>
              </li>
              <li>
                <a href={"#/instances"} class="has-icon">
                  <span class="icon">
                    <i class="mdi mdi-format-list-bulleted" />
                  </span>
                  <span class="menu-item-label">
                    <i18n.Translate>List</i18n.Translate>
                  </span>
                </a>
              </li>
            </Fragment>
          )}
          {hasToken ? (
            <li>
              <a
                class="has-icon is-state-info is-hoverable"
                onClick={(e): void => {
                  logOut();
                  e.preventDefault();
                }}
              >
                <span class="icon">
                  <i class="mdi mdi-logout default" />
                </span>
                <span class="menu-item-label">
                  <i18n.Translate>Log out</i18n.Translate>
                </span>
              </a>
            </li>
          ) : undefined}
        </ul>
      </div>
    </aside>
  );
}

type ElementMap = {
  [sdt in UIElement]: boolean;
};
const ALL_ELEMENTS = Object.values(UIElement).reduce((prev, ui) => {
  prev[ui as UIElement] = true;
  return prev;
}, {} as ElementMap);

function getAvailableForPersona(p: MerchantPersona): ElementMap {
  switch (p) {
    case "developer":
      return ALL_ELEMENTS;
    case "expert":
      return {
        [UIElement.sidebar_orders]: true,
        [UIElement.sidebar_templates]: true,
        [UIElement.sidebar_kycStatus]: true,
        [UIElement.sidebar_bankAccounts]: true,
        [UIElement.sidebar_settings]: true,
        [UIElement.sidebar_password]: true,
        [UIElement.sidebar_accessTokens]: true,
        [UIElement.sidebar_categories]: true,
        [UIElement.sidebar_webhooks]: true,
        [UIElement.sidebar_wireTransfers]: true,
        [UIElement.sidebar_inventory]: true,
        [UIElement.sidebar_otpDevices]: true,
        [UIElement.action_createOrderManually]: true,
        [UIElement.option_advanceInstanceSettings]: true,
        [UIElement.option_advanceOrderCreation]: true,
        [UIElement.option_otpDevicesOnTemplate]: true,
        [UIElement.option_paymentTimeoutOnTemplate]: true,
        [UIElement.action_useRevenueApi]: true,
        [UIElement.option_inventoryTaxes]: true,
        [UIElement.sidebar_statistics]: true,

        [UIElement.sidebar_discounts]: false,
        [UIElement.sidebar_subscriptions]: false,
        [UIElement.sidebar_tokenFamilies]: false,
        [UIElement.option_ageRestriction]: false,
      };
    case "offline-vending-machine":
      return {
        [UIElement.sidebar_orders]: true,
        [UIElement.sidebar_templates]: true,
        [UIElement.sidebar_kycStatus]: true,
        [UIElement.sidebar_bankAccounts]: true,
        [UIElement.sidebar_settings]: true,
        [UIElement.sidebar_password]: true,

        [UIElement.sidebar_accessTokens]: false,
        [UIElement.sidebar_categories]: false,
        [UIElement.sidebar_discounts]: false,
        [UIElement.sidebar_subscriptions]: false,
        [UIElement.sidebar_tokenFamilies]: false,
        [UIElement.sidebar_webhooks]: false,
        [UIElement.sidebar_wireTransfers]: false,
        [UIElement.sidebar_inventory]: false,
        [UIElement.sidebar_otpDevices]: false,
        [UIElement.action_createOrderManually]: false,
        [UIElement.option_advanceInstanceSettings]: false,
        [UIElement.option_advanceOrderCreation]: false,
        [UIElement.option_otpDevicesOnTemplate]: false,
        [UIElement.option_paymentTimeoutOnTemplate]: false,
        [UIElement.option_ageRestriction]: false,
        [UIElement.action_useRevenueApi]: false,
        [UIElement.option_inventoryTaxes]: false,
        [UIElement.sidebar_statistics]: false,
      };
    // case "inperson-vending-with-inventory":
    case "point-of-sale":
      return {
        [UIElement.sidebar_orders]: true,
        [UIElement.sidebar_templates]: true,
        [UIElement.sidebar_inventory]: true,
        [UIElement.sidebar_categories]: true,
        [UIElement.sidebar_accessTokens]: true,
        [UIElement.sidebar_kycStatus]: true,
        [UIElement.sidebar_bankAccounts]: true,
        [UIElement.sidebar_settings]: true,
        [UIElement.sidebar_password]: true,

        [UIElement.sidebar_discounts]: false,
        [UIElement.sidebar_subscriptions]: false,
        [UIElement.sidebar_tokenFamilies]: false,
        [UIElement.sidebar_webhooks]: false,
        [UIElement.sidebar_wireTransfers]: false,
        [UIElement.sidebar_otpDevices]: false,
        [UIElement.action_createOrderManually]: false,
        [UIElement.option_advanceInstanceSettings]: false,
        [UIElement.option_advanceOrderCreation]: false,
        [UIElement.option_otpDevicesOnTemplate]: false,
        [UIElement.option_paymentTimeoutOnTemplate]: false,
        [UIElement.option_ageRestriction]: false,
        [UIElement.action_useRevenueApi]: false,
        [UIElement.option_inventoryTaxes]: false,
        [UIElement.sidebar_statistics]: false,
      };
    case "digital-publishing":
      return {
        [UIElement.sidebar_orders]: true,
        [UIElement.sidebar_accessTokens]: true,
        [UIElement.sidebar_kycStatus]: true,
        [UIElement.sidebar_bankAccounts]: true,
        [UIElement.sidebar_settings]: true,
        [UIElement.sidebar_password]: true,
        [UIElement.sidebar_statistics]: true,

        [UIElement.sidebar_templates]: false,
        [UIElement.sidebar_categories]: false,
        [UIElement.sidebar_discounts]: false,
        [UIElement.sidebar_subscriptions]: false,
        [UIElement.sidebar_tokenFamilies]: false,
        [UIElement.sidebar_webhooks]: false,
        [UIElement.sidebar_wireTransfers]: false,
        [UIElement.sidebar_inventory]: false,
        [UIElement.sidebar_otpDevices]: false,
        [UIElement.action_createOrderManually]: false,
        [UIElement.option_advanceInstanceSettings]: false,
        [UIElement.option_advanceOrderCreation]: false,
        [UIElement.option_otpDevicesOnTemplate]: false,
        [UIElement.option_paymentTimeoutOnTemplate]: false,
        [UIElement.option_ageRestriction]: false,
        [UIElement.action_useRevenueApi]: false,
        [UIElement.option_inventoryTaxes]: false,
      };
    case "e-commerce":
      return {
        [UIElement.sidebar_orders]: true,
        [UIElement.sidebar_webhooks]: true,
        [UIElement.sidebar_accessTokens]: true,
        [UIElement.sidebar_kycStatus]: true,
        [UIElement.sidebar_bankAccounts]: true,
        [UIElement.sidebar_settings]: true,
        [UIElement.sidebar_password]: true,
        [UIElement.sidebar_statistics]: true,

        [UIElement.sidebar_templates]: false,
        [UIElement.sidebar_categories]: false,
        [UIElement.sidebar_discounts]: false,
        [UIElement.sidebar_subscriptions]: false,
        [UIElement.sidebar_tokenFamilies]: false,
        [UIElement.sidebar_wireTransfers]: false,
        [UIElement.sidebar_inventory]: false,
        [UIElement.sidebar_otpDevices]: false,
        [UIElement.action_createOrderManually]: false,
        [UIElement.option_advanceInstanceSettings]: false,
        [UIElement.option_advanceOrderCreation]: false,
        [UIElement.option_otpDevicesOnTemplate]: false,
        [UIElement.option_paymentTimeoutOnTemplate]: false,
        [UIElement.option_ageRestriction]: false,
        [UIElement.action_useRevenueApi]: false,
        [UIElement.option_inventoryTaxes]: false,
      };
  }
}

export function HtmlPersonaFlag<T extends keyof h.JSX.IntrinsicElements>(
  props: {
    htmlElement: T;
    point: UIElement;
    children: ComponentChildren;
  } & h.JSX.IntrinsicElements[T],
): VNode | null {
  const { htmlElement: el, children, point, ...rest } = props;
  const [{ persona }] = usePreference();
  const { config } = useSessionContext();
  const isEnabled = getAvailableForPersona(persona ?? config.default_persona)[
    point
  ];
  if (isEnabled) return h(el as any, rest as any, children);
  return null;
}

export function ComponentPersonaFlag<FN extends (props: P) => VNode, P>(
  props: {
    Comp: FN;
    point: UIElement;
    children: ComponentChildren;
  } & P,
): VNode | null {
  const { children, point, Comp, ...rest } = props;
  const [{ persona }] = usePreference();
  const { config } = useSessionContext();
  const isEnabled = getAvailableForPersona(persona ?? config.default_persona)[
    point
  ];
  const d = rest as any;
  if (isEnabled) return <Comp {...d}>{children}</Comp>;
  return null;
}

export function FragmentPersonaFlag(props: {
  point: UIElement;
  showAnywayIf?: boolean;
  children: ComponentChildren;
}): VNode | null {
  const { children, point } = props;
  const [{ persona }] = usePreference();
  const { config } = useSessionContext();
  const isEnabled = getAvailableForPersona(persona ?? config.default_persona)[
    point
  ];
  if (props.showAnywayIf === true || isEnabled)
    return <Fragment>{children}</Fragment>;
  return null;
}
