/*
 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 {
  assertUnreachable,
  HttpStatusCode,
  TalerError,
  TalerFormAttributes,
} from "@gnu-taler/taler-util";
import {
  Attention,
  ErrorLoading,
  FormMetadata,
  FormUI,
  Loading,
  preloadedForms,
  RouteDefinition,
  useFormMeta,
  useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
import { useAccountInformation } from "../hooks/account.js";
import { Profile } from "./Profile.js";

const TALER_SCREEN_ID = 110;

export function ShowCollectedInfo({
  routeToAccountById,
  account,
  routeToShowCollectedInfo,
  rowId,
}: {
  rowId: number;
  account: string;
  routeToShowCollectedInfo: RouteDefinition<{ cid: string; rowId: string }>;
  routeToAccountById: RouteDefinition<{ cid: string }>;
}): VNode {
  const { i18n } = useTranslationContext();

  const details = useAccountInformation(account);

  if (!details) {
    return <Loading />;
  }
  if (details instanceof TalerError) {
    return <ErrorLoading error={details} />;
  }
  if (details.type === "fail") {
    switch (details.case) {
      case HttpStatusCode.Forbidden:
        return (
          <Fragment>
            <Attention type="danger" title={i18n.str`Operation denied`}>
              <i18n.Translate>
                This account signature is invalid, contact administrator or
                create a new one.
              </i18n.Translate>
            </Attention>
            <Profile />
          </Fragment>
        );
      case HttpStatusCode.NotFound:
        return (
          <Fragment>
            <Attention type="danger" title={i18n.str`Operation denied`}>
              <i18n.Translate>
                The designated AML account is not known, contact administrator
                or create a new one.
              </i18n.Translate>
            </Attention>
            <Profile />
          </Fragment>
        );
      case HttpStatusCode.Conflict:
        return (
          <Fragment>
            <Attention type="danger" title={i18n.str`Operation denied`}>
              <i18n.Translate>
                The designated AML account is not enabled, contact administrator
                or create a new one.
              </i18n.Translate>
            </Attention>
            <Profile />
          </Fragment>
        );
      default:
        assertUnreachable(details);
    }
  }

  const { details: history } = details.body;
  const eventIndex = history.findIndex((h) => h.rowid === rowId);
  const event = eventIndex === -1 ? undefined : history[eventIndex];
  if (!event) {
    return <div>There is no collection event with id {rowId}</div>;
  }
  const hasNext = eventIndex < history.length - 1;
  const hasPrevious = eventIndex > 0;
  const previousId = hasPrevious ? history[eventIndex - 1].rowid : undefined;
  const nextId = hasNext ? history[eventIndex + 1].rowid : undefined;

  if (!event.attributes) {
    return (
      <div>the event referenced by rowId doesn't have any information</div>
    );
  }
  const FORM_ID = event.attributes[TalerFormAttributes.FORM_ID] as
    | string
    | undefined;
  const FORM_VERSION = event.attributes[TalerFormAttributes.FORM_VERSION] as
    | number
    | undefined;
  if (!FORM_ID) {
    return <div>no form id in the collected information</div>;
  }
  const forms = preloadedForms(i18n);

  const formsWithId = forms.filter((f) => f.id === FORM_ID);

  if (!formsWithId.length) {
    return <div>form not found with id {FORM_ID}</div>;
  }

  let lastVersion = -1;
  let lastForm: FormMetadata;
  let correctVersionForm: FormMetadata | undefined;
  formsWithId.forEach((f) => {
    if (f.version > lastVersion) {
      lastVersion = f.version;
      lastForm = f;
    }
    if (f.version === FORM_VERSION) {
      correctVersionForm = f;
    }
  });
  // list have at least one element, lastVerseion is initialized with -1
  // and version is always > 0
  const formToBeUsed =
    correctVersionForm === undefined ? lastForm! : correctVersionForm;

  return (
    <ShowForm
      key={eventIndex}
      form={formToBeUsed}
      account={account}
      data={event.attributes ?? {}}
      routeToAccountById={routeToAccountById}
      expectedVersion={FORM_VERSION}
      previousId={previousId}
      nextId={nextId}
      routeToShowCollectedInfo={routeToShowCollectedInfo}
    />
  );
}

function ShowForm({
  form,
  data,
  account,
  routeToAccountById,
  expectedVersion,
  previousId,
  routeToShowCollectedInfo,
  nextId,
}: {
  form: FormMetadata;
  data: object;
  account: string;
  routeToAccountById: RouteDefinition<{ cid: string }>;
  expectedVersion: number | undefined;
  routeToShowCollectedInfo: RouteDefinition<{ cid: string; rowId: string }>;
  previousId?: number;
  nextId?: number;
}): VNode {
  const { i18n } = useTranslationContext();
  const differentVersion = form.version !== expectedVersion;

  const formContext = "FORM_CONTEXT" in data ? data.FORM_CONTEXT : {};

  const { model, design } = useFormMeta(form, formContext, data);

  return (
    <Fragment>
      {differentVersion ? (
        expectedVersion === undefined ? (
          <Attention type="warning" title={i18n.str`Different form version`}>
            <i18n.Translate>
              The collected information don't have the form version used.
            </i18n.Translate>
          </Attention>
        ) : (
          <Attention type="warning" title={i18n.str`Different form version`}>
            <i18n.Translate>
              The collected information used the form version "{expectedVersion}
              " but is not available.
            </i18n.Translate>
          </Attention>
        )
      ) : undefined}
      <div class="my-4">
        <a
          href={routeToAccountById.url({ cid: account })}
          class="mt-3 inline-flex w-full items-center justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 sm:ml-3 sm:mt-0 sm:w-auto"
        >
          <i18n.Translate>Case details</i18n.Translate>
        </a>
        <a
          href={
            previousId === undefined
              ? undefined
              : routeToShowCollectedInfo.url({
                  cid: account,
                  rowId: String(previousId),
                })
          }
          data-disabled={previousId === undefined}
          class="mt-3 inline-flex w-full items-center justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 sm:ml-3 sm:mt-0 sm:w-auto data-[disabled=true]:bg-gray-500"
        >
          <i18n.Translate>Next event</i18n.Translate>
        </a>
        <a
          href={
            nextId === undefined
              ? undefined
              : routeToShowCollectedInfo.url({
                  cid: account,
                  rowId: String(nextId),
                })
          }
          data-disabled={nextId === undefined}
          class="mt-3 inline-flex w-full items-center justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 sm:ml-3 sm:mt-0 sm:w-auto data-[disabled=true]:bg-gray-500"
        >
          <i18n.Translate>Previous event</i18n.Translate>
        </a>
      </div>
      <FormUI design={design} model={model} disabled />
    </Fragment>
  );
}
