/*
 This file is part of GNU Taler
 (C) 2022-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/>
 */
import {
  HttpStatusCode,
  TalerError,
  TalerExchangeApi,
  assertUnreachable,
} from "@gnu-taler/taler-util";
import {
  Attention,
  ErrorLoading,
  InputChoiceHorizontal,
  Loading,
  UIHandlerId,
  amlStateConverter,
  useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useEffect, useState } from "preact/hooks";
import { useCases } from "../hooks/useCases.js";

import { privatePages } from "../Routing.js";
import { FormErrors, RecursivePartial, useFormState } from "../hooks/form.js";
import { undefinedIfEmpty } from "./CreateAccount.js";
import { Officer } from "./Officer.js";

type FormType = {
  state: TalerExchangeApi.AmlState;
};

export function CasesUI({
  records,
  filter,
  onChangeFilter,
  onFirstPage,
  onNext,
}: {
  onFirstPage?: () => void;
  onNext?: () => void;
  filter: TalerExchangeApi.AmlState;
  onChangeFilter: (f: TalerExchangeApi.AmlState) => void;
  records: TalerExchangeApi.AmlRecord[];
}): VNode {
  const { i18n } = useTranslationContext();

  const [form, status] = useFormState<FormType>(
    [".state"] as Array<UIHandlerId>,
    {
      state: filter,
    },
    (state) => {
      const errors = undefinedIfEmpty<FormErrors<FormType>>({
        state: state.state === undefined ? i18n.str`required` : undefined,
      });
      if (errors === undefined) {
        const result: FormType = {
          state: state.state!,
        };
        return {
          status: "ok",
          result,
          errors,
        };
      }
      const result: RecursivePartial<FormType> = {
        state: state.state,
      };
      return {
        status: "fail",
        result,
        errors,
      };
    },
  );
  useEffect(() => {
    if (status.status === "ok" && filter !== status.result.state) {
      onChangeFilter(status.result.state);
    }
  }, [form?.state?.value]);

  return (
    <div>
      <div class="sm:flex sm:items-center">
        <div class="px-2 sm:flex-auto">
          <h1 class="text-base font-semibold leading-6 text-gray-900">
            <i18n.Translate>Cases</i18n.Translate>
          </h1>
          <p class="mt-2 text-sm text-gray-700 w-80">
            <i18n.Translate>
              A list of all the account with the status
            </i18n.Translate>
          </p>
        </div>
        <div class="px-2">
          <InputChoiceHorizontal<FormType, "state">
            name="state"
            label={i18n.str`Filter`}
            handler={form.state}
            converter={amlStateConverter}
            choices={[
              {
                label: i18n.str`Pending`,
                value: "pending",
              },
              {
                label: i18n.str`Frozen`,
                value: "frozen",
              },
              {
                label: i18n.str`Normal`,
                value: "normal",
              },
            ]}
          />
        </div>
      </div>
      <div class="mt-8 flow-root">
        <div class="overflow-x-auto">
          {!records.length ? (
            <div>empty result </div>
          ) : (
            <div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
              <table class="min-w-full divide-y divide-gray-300">
                <thead>
                  <tr>
                    <th
                      scope="col"
                      class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-80"
                    >
                      <i18n.Translate>Account Id</i18n.Translate>
                    </th>
                    <th
                      scope="col"
                      class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-40"
                    >
                      <i18n.Translate>Status</i18n.Translate>
                    </th>
                    <th
                      scope="col"
                      class="sm:hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-40"
                    >
                      <i18n.Translate>Threshold</i18n.Translate>
                    </th>
                  </tr>
                </thead>
                <tbody class="divide-y divide-gray-200 bg-white">
                  {records.map((r) => {
                    return (
                      <tr key={r.h_payto} class="hover:bg-gray-100 ">
                        <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-500 ">
                          <div class="text-gray-900">
                            <a
                              href={privatePages.caseDetails.url({
                                cid: r.h_payto,
                              })}
                              class="text-indigo-600 hover:text-indigo-900"
                            >
                              {r.h_payto.substring(0, 16)}...
                            </a>
                          </div>
                        </td>
                        <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-500">
                          {((state: TalerExchangeApi.AmlState): VNode => {
                            switch (state) {
                              case TalerExchangeApi.AmlState.normal: {
                                return (
                                  <span class="inline-flex items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20">
                                    Normal
                                  </span>
                                );
                              }
                              case TalerExchangeApi.AmlState.pending: {
                                return (
                                  <span class="inline-flex items-center rounded-md bg-yellow-50 px-2 py-1 text-xs font-medium text-yellow-700 ring-1 ring-inset ring-green-600/20">
                                    Pending
                                  </span>
                                );
                              }
                              case TalerExchangeApi.AmlState.frozen: {
                                return (
                                  <span class="inline-flex items-center rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-inset ring-green-600/20">
                                    Frozen
                                  </span>
                                );
                              }
                            }
                          })(r.current_state)}
                        </td>
                        <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-900">
                          {r.threshold}
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
              <Pagination onFirstPage={onFirstPage} onNext={onNext} />
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

export function Cases() {
  const [stateFilter, setStateFilter] = useState(
    TalerExchangeApi.AmlState.pending,
  );

  const list = useCases(stateFilter);
  const { i18n } = useTranslationContext();

  if (!list) {
    return <Loading />;
  }
  if (list instanceof TalerError) {
    return <ErrorLoading error={list} />;
  }

  if (list.type === "fail") {
    switch (list.case) {
      case HttpStatusCode.Forbidden: {
        return (
          <Fragment>
            <Attention type="danger" title={i18n.str`Operation denied`}>
              <i18n.Translate>
                This account doesn't have access. Request account activation
                sending your public key.
              </i18n.Translate>
            </Attention>
            <Officer />
          </Fragment>
        );
      }
      case HttpStatusCode.Unauthorized: {
        return (
          <Fragment>
            <Attention type="danger" title={i18n.str`Operation denied`}>
              <i18n.Translate>
                This account is not allowed to perform list the cases.
              </i18n.Translate>
            </Attention>
            <Officer />
          </Fragment>
        );
      }
      case HttpStatusCode.NotFound:
      case HttpStatusCode.Conflict:
        return <Officer />;
      default:
        assertUnreachable(list);
    }
  }

  return (
    <CasesUI
      records={list.body}
      onFirstPage={list.isFirstPage ? undefined : list.loadFirst}
      onNext={list.isLastPage ? undefined : list.loadNext}
      filter={stateFilter}
      onChangeFilter={(d) => {
        setStateFilter(d);
      }}
    />
  );
}

export const PeopleIcon = () => (
  <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="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z"
    />
  </svg>
);

export const HomeIcon = () => (
  <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="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25"
    />
  </svg>
);

function Pagination({
  onFirstPage,
  onNext,
}: {
  onFirstPage?: () => void;
  onNext?: () => void;
}) {
  const { i18n } = useTranslationContext();
  return (
    <nav
      class="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6 rounded-lg"
      aria-label="Pagination"
    >
      <div class="flex flex-1 justify-between sm:justify-end">
        <button
          class="relative disabled:bg-gray-100 disabled:text-gray-500 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0"
          disabled={!onFirstPage}
          onClick={onFirstPage}
        >
          <i18n.Translate>First page</i18n.Translate>
        </button>
        <button
          class="relative disabled:bg-gray-100 disabled:text-gray-500 ml-3 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0"
          disabled={!onNext}
          onClick={onNext}
        >
          <i18n.Translate>Next</i18n.Translate>
        </button>
      </div>
    </nav>
  );
}
