/*
 This file is part of GNU Taler
 (C) 2022-2025 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/>
 */
import {
  AbsoluteTime,
  AccountProperties,
  assertUnreachable,
  HttpStatusCode,
  TalerError,
  TalerExchangeApi,
  TalerFormAttributes,
} from "@gnu-taler/taler-util";
import {
  Attention,
  CopyButton,
  ErrorLoading,
  Loading,
  RouteDefinition,
  useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { format } from "date-fns";
import { h, VNode } from "preact";
import { Fragment } from "preact/jsx-runtime";
import { ShowDecisionLimitInfo } from "../components/ShowDecisionLimitInfo.js";
import { ShowDefaultRules } from "../components/ShowDefaultRules.js";
import { ShowLegistimizationInfo } from "../components/ShowLegitimizationInfo.js";
import { useAccountInformation } from "../hooks/account.js";
import { DecisionRequest } from "../hooks/decision-request.js";
import { useAccountDecisions } from "../hooks/decisions.js";
import { useCurrentLegitimizations } from "../hooks/legitimizations.js";
import { useServerMeasures } from "../hooks/server-info.js";
import { BANK_RULES, WALLET_RULES } from "./decision/Rules.js";

export function ShowProperties(props: {
  properties?: AccountProperties;
}): VNode {
  const { properties } = props;
  const keys = Object.keys(properties ?? {});
  if (!properties || keys.length == 0) {
    return <span>No properties defined for this account.</span>;
  }
  return (
    <>
      {keys.map((x) => {
        if (properties[x] == null) {
          return null;
        }
        return (
          <p>
            {x}: {properties[x]}
          </p>
        );
      })}
    </>
  );
}

export function AccountDetails({
  account,
  routeToShowCollectedInfo,
  onNewDecision,
  routeToShowTransfers,
}: {
  onNewDecision: (d: Partial<DecisionRequest>) => void;
  routeToShowCollectedInfo: RouteDefinition<{ cid: string; rowId: string }>;
  account: string;
  routeToShowTransfers: RouteDefinition<{ cid: string }>;
}) {
  const { i18n } = useTranslationContext();
  const details = useAccountInformation(account);
  const history = useAccountDecisions(account);
  const legistimizations = useCurrentLegitimizations(account);

  const measures = useServerMeasures();

  if (!details || !history || !legistimizations) {
    return <Loading />;
  }
  if (details instanceof TalerError) {
    return <ErrorLoading error={details} />;
  }
  if (details.type === "fail") {
    switch (details.case) {
      case HttpStatusCode.Forbidden:
      case HttpStatusCode.NotFound:
      case HttpStatusCode.Conflict:
        return <div />;
      default:
        assertUnreachable(details);
    }
  }
  if (history instanceof TalerError) {
    return <ErrorLoading error={history} />;
  }
  if (history.type === "fail") {
    switch (history.case) {
      case HttpStatusCode.Forbidden:
      case HttpStatusCode.NotFound:
      case HttpStatusCode.Conflict:
        return <div />;
      default:
        assertUnreachable(history);
    }
  }
  if (legistimizations instanceof TalerError) {
    return <ErrorLoading error={legistimizations} />;
  }

  const collectionEvents = details.body.details;

  collectionEvents.sort((a, b) =>
    AbsoluteTime.cmp(
      AbsoluteTime.fromProtocolTimestamp(a.collection_time),
      AbsoluteTime.fromProtocolTimestamp(b.collection_time),
    ),
  );

  const activeDecision = history.body.find((d) => d.is_active);
  const restDecisions = !activeDecision
    ? history.body
    : history.body.filter((d) => d.rowid !== activeDecision.rowid);

  function ShortcutActionButtons(): VNode {
    return (
      <div>
        <button
          onClick={async () => {
            // the wizard should not require checking the account state
            // instead here all the values from the current decision should be
            // loaded into the new decision request, like we are doing with e
            // custom measures
            // FIXME-do-this add properties, limits, investigation state
            onNewDecision({
              original: activeDecision,
              custom_measures: activeDecision?.limits.custom_measures,
            });
          }}
          class="m-4  rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
        >
          <i18n.Translate>New decision</i18n.Translate>
        </button>
        <a
          href={routeToShowTransfers.url({
            cid: account,
          })}
          class="m-4  rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
        >
          <i18n.Translate>Show transfers</i18n.Translate>
        </a>
      </div>
    );
  }

  const defaultRules =
    !measures || measures instanceof TalerError || measures.type === "fail"
      ? []
      : measures.body.default_rules;

  const serverMeasures =
    !measures || measures instanceof TalerError || measures.type === "fail"
      ? undefined
      : measures.body;

  const filteredRulesByType = !activeDecision
    ? defaultRules
    : defaultRules.filter((r) => {
        return activeDecision.is_wallet
          ? WALLET_RULES.includes(r.operation_type)
          : BANK_RULES.includes(r.operation_type);
      });

  return (
    <div class="min-w-60">
      <header class="flex flex-col justify-between border-b border-white/5 px-4 py-4 sm:px-6 sm:py-6 lg:px-8 gap-2">
        <h1 class="text-base font-semibold leading-7 text-black">
          <i18n.Translate>Case history for selected account</i18n.Translate>
        </h1>
        <div>
          <p>
            <span class="font-bold">
              <i18n.Translate>ID:</i18n.Translate>
            </span>{" "}
            {account} <CopyButton class="" getContent={() => account} />
          </p>
          <p>
            <span class="font-bold">
              <i18n.Translate>Payto:</i18n.Translate>
            </span>{" "}
            {activeDecision?.full_payto ?? "N/A"}{" "}
            <CopyButton
              class=""
              getContent={() => activeDecision?.full_payto ?? "N/A"}
            />
          </p>
        </div>
      </header>

      {!activeDecision || !activeDecision.to_investigate ? undefined : (
        <Attention title={i18n.str`Under investigation`} type="warning">
          <i18n.Translate>
            This account requires a manual review and is waiting for a decision
            to be made.
          </i18n.Translate>
        </Attention>
      )}

      <ShortcutActionButtons />

      <div class="p-4">
        <h1 class="text-base font-semibold leading-6 text-black">
          <i18n.Translate>Collected information</i18n.Translate>
        </h1>
        <p class="mt-1 text-sm leading-6 text-gray-600">
          <i18n.Translate>
            Every attribute collection event (via form upload or KYC provider).
          </i18n.Translate>
        </p>
      </div>
      {collectionEvents.length === 0 ? (
        <Attention title={i18n.str`The event list is empty`} type="warning" />
      ) : (
        <ShowTimeline
          account={account}
          history={collectionEvents}
          routeToShowCollectedInfo={routeToShowCollectedInfo}
        />
      )}

      <h1 class="mb-4 text-base font-semibold leading-6 text-black">
        <i18n.Translate>Current account properties</i18n.Translate>
      </h1>

      <ShowProperties properties={activeDecision?.properties} />

      {!activeDecision ? (
        <Fragment>
          <Attention title={i18n.str`No active decision found`} type="warning">
            <i18n.Translate>
              There is no decision for this account yet. The account is limited
              by the default rules.
            </i18n.Translate>
          </Attention>
          <ShowDefaultRules rules={filteredRulesByType} />
        </Fragment>
      ) : (
        <div class="my-4">
          <h1 class="mb-4 text-base font-semibold leading-6 text-black">
            <i18n.Translate>Current active rules</i18n.Translate>
          </h1>
          <ShowDecisionLimitInfo
            since={AbsoluteTime.fromProtocolTimestamp(
              activeDecision.decision_time,
            )}
            until={AbsoluteTime.fromProtocolTimestamp(
              activeDecision.limits.expiration_time,
            )}
            justification={activeDecision.justification}
            rules={activeDecision.limits.rules}
            startOpen
            measure={activeDecision.limits.successor_measure ?? ""}
          />
        </div>
      )}
      {restDecisions.length > 0 ? (
        <div class="my-4 grid gap-y-4">
          <h1 class="text-base font-semibold leading-6 text-black">
            <i18n.Translate>Previous AML decisions</i18n.Translate>
          </h1>
          {restDecisions.map((d, k) => {
            return (
              <ShowDecisionLimitInfo
                key={k}
                since={AbsoluteTime.fromProtocolTimestamp(d.decision_time)}
                until={AbsoluteTime.fromProtocolTimestamp(
                  d.limits.expiration_time,
                )}
                justification={d.justification}
                rules={d.limits.rules}
                measure={d.limits.successor_measure ?? ""}
              />
            );
          })}
        </div>
      ) : !activeDecision ? (
        <div class="ty-4">
          <Attention title={i18n.str`No aml history found`} type="warning" />
        </div>
      ) : undefined}
      {legistimizations.body.length > 0 ? (
        <div class="my-4 grid gap-y-4">
          <h1 class="text-base font-semibold leading-6 text-black">
            <i18n.Translate>Current active measures</i18n.Translate>
          </h1>
          {legistimizations.body.map((d) => {
            return (
              <ShowLegistimizationInfo
                since={AbsoluteTime.fromProtocolTimestamp(d.start_time)}
                completed={d.is_finished}
                legitimization={d.measures}
                serverMeasures={serverMeasures}
              />
            );
          })}
        </div>
      ) : (
        <Fragment />
      )}
    </div>
  );
}

function ShowTimeline({
  history,
  account,
  routeToShowCollectedInfo,
}: {
  account: string;
  routeToShowCollectedInfo: RouteDefinition<{ cid: string; rowId: string }>;
  history: TalerExchangeApi.KycAttributeCollectionEvent[];
}): VNode {
  const { i18n } = useTranslationContext();
  return (
    <div class="flow-root">
      <ul role="list">
        {history.map((e, idx) => {
          const values = e.attributes ?? {};
          const formId = values[TalerFormAttributes.FORM_ID] as
            | string
            | undefined;

          return (
            <a
              key={idx}
              href={routeToShowCollectedInfo.url({
                cid: account,
                rowId: String(e.rowid),
              })}
            >
              <li key={idx} class="hover:bg-gray-200 p-2 rounded">
                <div class="relative pb-3">
                  <span class="absolute left-3 top-5 -ml-px h-full w-1 bg-gray-200"></span>
                  <div class="relative flex space-x-3">
                    {/* <ArrowDownCircleIcon class="h-8 w-8 text-green-700" /> */}
                    <svg
                      xmlns="http://www.w3.org/2000/svg"
                      fill="none"
                      viewBox="0 0 24 24"
                      stroke-width="1.5"
                      stroke="currentColor"
                      class="w-6 h-6"
                    >
                      <path
                        stroke-linecap="round"
                        stroke-linejoin="round"
                        d="M9 12.75l3 3m0 0l3-3m-3 3v-7.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
                      />
                    </svg>
                    {!formId ? undefined : (
                      <div>
                        <svg
                          xmlns="http://www.w3.org/2000/svg"
                          fill="none"
                          viewBox="0 0 24 24"
                          stroke-width="1.5"
                          stroke="currentColor"
                          class="size-6"
                        >
                          <path
                            stroke-linecap="round"
                            stroke-linejoin="round"
                            d="M12 7.5h1.5m-1.5 3h1.5m-7.5 3h7.5m-7.5 3h7.5m3-9h3.375c.621 0 1.125.504 1.125 1.125V18a2.25 2.25 0 0 1-2.25 2.25M16.5 7.5V18a2.25 2.25 0 0 0 2.25 2.25M16.5 7.5V4.875c0-.621-.504-1.125-1.125-1.125H4.125C3.504 3.75 3 4.254 3 4.875V18a2.25 2.25 0 0 0 2.25 2.25h13.5M6 7.5h3v3H6v-3Z"
                          />
                        </svg>
                        <span>{formId}</span>
                      </div>
                    )}
                    <div class="flex min-w-0 flex-1 justify-between space-x-4 pt-1.5">
                      <div class="whitespace-nowrap text-right text-sm text-gray-500">
                        {e.collection_time.t_s === "never" ? (
                          "never"
                        ) : (
                          <time
                            dateTime={format(
                              e.collection_time.t_s * 1000,
                              "dd MMM yyyy",
                            )}
                          >
                            {format(
                              e.collection_time.t_s * 1000,
                              "dd MMM yyyy HH:mm:ss",
                            )}
                          </time>
                        )}
                      </div>
                    </div>
                  </div>
                </div>
              </li>
            </a>
          );
        })}
        <li class="hover:bg-gray-200 p-2 rounded">
          <div class="flex min-w-0 flex-1 justify-between space-x-4 pt-1.5">
            <svg
              xmlns="http://www.w3.org/2000/svg"
              fill="none"
              viewBox="0 0 24 24"
              stroke-width="1.5"
              stroke="currentColor"
              class="size-6 w-6 h-6"
            >
              <path
                stroke-linecap="round"
                stroke-linejoin="round"
                d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
              />
            </svg>
            <p class="text-sm text-gray-900">
              <i18n.Translate>Now</i18n.Translate>
            </p>
          </div>
        </li>
      </ul>
    </div>
  );
}
