import {
  AbsoluteTime,
  AmountJson,
  Amounts,
  PaytoString,
  TalerError,
  TranslatedString,
  assertUnreachable,
} from "@gnu-taler/taler-util";
import { ErrorLoading, Loading, useTranslationContext } from "@gnu-taler/web-util/browser";
import { ArrowDownCircleIcon, ClockIcon } from "@heroicons/react/20/solid";
import { format } from "date-fns";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { NiceForm } from "../NiceForm.js";
import { FlexibleForm } from "../forms/index.js";
import { UIFormField } from "../handlers/forms.js";
import { useCaseDetails } from "../hooks/useCaseDetails.js";
import { Pages } from "../pages.js";
import { AmlExchangeBackend } from "../types.js";

type AmlEvent = AmlFormEvent | KycCollectionEvent | KycExpirationEvent;
type AmlFormEvent = {
  type: "aml-form";
  when: AbsoluteTime;
  title: TranslatedString;
  state: AmlExchangeBackend.AmlState;
  threshold: AmountJson;
};
type KycCollectionEvent = {
  type: "kyc-collection";
  when: AbsoluteTime;
  title: TranslatedString;
  values: object;
  provider: string;
};
type KycExpirationEvent = {
  type: "kyc-expiration";
  when: AbsoluteTime;
  title: TranslatedString;
  fields: string[];
};

type WithTime = { when: AbsoluteTime };

function selectSooner(a: WithTime, b: WithTime) {
  return AbsoluteTime.cmp(a.when, b.when);
}

function getEventsFromAmlHistory(
  aml: AmlExchangeBackend.AmlDecisionDetail[],
  kyc: AmlExchangeBackend.KycDetail[],
): AmlEvent[] {
  const ae: AmlEvent[] = aml.map((a) => {
    return {
      type: "aml-form",
      state: a.new_state,
      threshold: Amounts.parseOrThrow(a.new_threshold),
      title: a.justification as TranslatedString,
      when: {
        t_ms:
          a.decision_time.t_s === "never"
            ? "never"
            : a.decision_time.t_s * 1000,
      },
    } as AmlEvent;
  });
  const ke = kyc.reduce((prev, k) => {
    prev.push({
      type: "kyc-collection",
      title: "collection" as TranslatedString,
      when: AbsoluteTime.fromProtocolTimestamp(k.collection_time),
      values: !k.attributes ? {} : k.attributes,
      provider: k.provider_section,
    });
    prev.push({
      type: "kyc-expiration",
      title: "expiration" as TranslatedString,
      when: AbsoluteTime.fromProtocolTimestamp(k.expiration_time),
      fields: !k.attributes ? [] : Object.keys(k.attributes),
    });
    return prev;
  }, [] as AmlEvent[]);
  return ae.concat(ke).sort(selectSooner);
}

export function CaseDetails({ account }: { account: string }) {
  const [selected, setSelected] = useState<AmlEvent | undefined>(undefined);

  const { i18n } = useTranslationContext();
  const details = useCaseDetails(account)
  if (!details) {
    return <Loading />
  }
  if (details instanceof TalerError) {
    return <ErrorLoading error={details} />
  }
  if (details.type === "fail") {
    switch (details.case) {
      case "unauthorized":
      case "officer-not-found":
      case "officer-disabled": return <div />
      default: assertUnreachable(details)
    }
  }
  const { aml_history, kyc_attributes } = details.body

  const events = getEventsFromAmlHistory(aml_history, kyc_attributes);

  return (
    <div>
      <a
        href={Pages.newFormEntry.url({ account })}
        class="m-4 block 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"
      >
        New AML form
      </a>

      <header class="flex items-center justify-between border-b border-white/5 px-4 py-4 sm:px-6 sm:py-6 lg:px-8">
        <h1 class="text-base font-semibold leading-7 text-black">
          Case history
        </h1>
      </header>
      <div class="flow-root">
        <ul role="list">
          {events.map((e, idx) => {
            const isLast = events.length - 1 === idx;
            return (
              <li
                class="hover:bg-gray-200 p-2 rounded cursor-pointer"
                onClick={() => {
                  setSelected(e);
                }}
              >
                <div class="relative pb-6">
                  {!isLast ? (
                    <span
                      class="absolute left-4 top-4 -ml-px h-full w-1 bg-gray-200"
                      aria-hidden="true"
                    ></span>
                  ) : undefined}
                  <div class="relative flex space-x-3">
                    {(() => {
                      switch (e.type) {
                        case "aml-form": {
                          switch (e.state) {
                            case AmlExchangeBackend.AmlState.normal: {
                              return (
                                <div>
                                  <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>
                                  <span class="inline-flex items-center  px-2 py-1 text-xs font-medium text-gray-700 ">
                                    {e.threshold.currency}{" "}
                                    {Amounts.stringifyValue(e.threshold)}
                                  </span>
                                </div>
                              );
                            }
                            case AmlExchangeBackend.AmlState.pending: {
                              return (
                                <div>
                                  <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>
                                  <span class="inline-flex items-center  px-2 py-1 text-xs font-medium text-gray-700 ">
                                    {e.threshold.currency}{" "}
                                    {Amounts.stringifyValue(e.threshold)}
                                  </span>
                                </div>
                              );
                            }
                            case AmlExchangeBackend.AmlState.frozen: {
                              return (
                                <div>
                                  <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>
                                  <span class="inline-flex items-center  px-2 py-1 text-xs font-medium text-gray-700 ">
                                    {e.threshold.currency}{" "}
                                    {Amounts.stringifyValue(e.threshold)}
                                  </span>
                                </div>
                              );
                            }
                          }
                        }
                        case "kyc-collection": {
                          return (
                            <ArrowDownCircleIcon class="h-8 w-8 text-green-700" />
                          );
                        }
                        case "kyc-expiration": {
                          return <ClockIcon class="h-8 w-8 text-gray-700" />;
                        }
                      }
                    })()}
                    <div class="flex min-w-0 flex-1 justify-between space-x-4 pt-1.5">
                      <div>
                        <p class="text-sm text-gray-900">{e.title}</p>
                      </div>
                      <div class="whitespace-nowrap text-right text-sm text-gray-500">
                        {e.when.t_ms === "never" ? (
                          "never"
                        ) : (
                          <time dateTime={format(e.when.t_ms, "dd MMM yyyy")}>
                            {format(e.when.t_ms, "dd MMM yyyy")}
                          </time>
                        )}
                      </div>
                    </div>
                  </div>
                </div>
              </li>
            );
          })}
        </ul>
      </div>
      {selected && <ShowEventDetails event={selected} />}
      {selected && <ShowConsolidated history={events} until={selected} />}
    </div>
  );
}

function ShowEventDetails({ event }: { event: AmlEvent }): VNode {
  return <div>type {event.type}</div>;
}

function ShowConsolidated({
  history,
  until,
}: {
  history: AmlEvent[];
  until: AmlEvent;
}): VNode {
  const cons = getConsolidated(history, until.when);

  const form: FlexibleForm<Consolidated> = {
    versionId: "1",
    behavior: (form) => {
      return {
        aml: {
          threshold: {
            hidden: !form.aml
          },
          since: {
            hidden: !form.aml
          },
          state: {
            hidden: !form.aml
          }
        }
      };
    },
    design: [
      {
        title: "AML" as TranslatedString,
        fields: [
          {
            type: "amount",
            props: {
              label: "Threshold" as TranslatedString,
              name: "aml.threshold",
            },
          },
          {
            type: "choiceHorizontal",
            props: {
              label: "State" as TranslatedString,
              name: "aml.state",
              converter: amlStateConverter,
              choices: [
                {
                  label: "Frozen" as TranslatedString,
                  value: AmlExchangeBackend.AmlState.frozen,
                },
                {
                  label: "Pending" as TranslatedString,
                  value: AmlExchangeBackend.AmlState.pending,
                },
                {
                  label: "Normal" as TranslatedString,
                  value: AmlExchangeBackend.AmlState.normal,
                },
              ],
            },
          },
        ],
      },
      Object.entries(cons.kyc).length > 0
        ? {
          title: "KYC" as TranslatedString,
          fields: Object.entries(cons.kyc).map(([key, field]) => {
            const result: UIFormField = {
              type: "text",
              props: {
                label: key as TranslatedString,
                name: `kyc.${key}.value`,
                help: `${field.provider} since ${field.since.t_ms === "never"
                  ? "never"
                  : format(field.since.t_ms, "dd/MM/yyyy")
                  }` as TranslatedString,
              },
            };
            return result;
          }),
        }
        : undefined,
    ],
  };
  return (
    <Fragment>
      <h1 class="text-base font-semibold leading-7 text-black">
        Consolidated information after{" "}
        {until.when.t_ms === "never"
          ? "never"
          : format(until.when.t_ms, "dd MMMM yyyy")}
      </h1>
      <NiceForm
        key={`${String(Date.now())}`}
        form={form}
        initial={cons}
        onUpdate={() => { }}
      />
    </Fragment>
  );
}

interface Consolidated {
  aml: {
    state: AmlExchangeBackend.AmlState;
    threshold: AmountJson;
    since: AbsoluteTime;
  };
  kyc: {
    [field: string]: {
      value: any;
      provider: string;
      since: AbsoluteTime;
    };
  };
}

function getConsolidated(
  history: AmlEvent[],
  when: AbsoluteTime,
): Consolidated {
  const initial: Consolidated = {
    aml: {
      state: AmlExchangeBackend.AmlState.normal,
      threshold: {
        currency: "ARS",
        value: 1000,
        fraction: 0,
      },
      since: AbsoluteTime.never()
    },
    kyc: {},
  };
  return history.reduce((prev, cur) => {
    if (AbsoluteTime.cmp(when, cur.when) < 0) {
      return prev;
    }
    switch (cur.type) {
      case "kyc-expiration": {
        cur.fields.forEach((field) => {
          delete prev.kyc[field];
        });
        break;
      }
      case "aml-form": {
        prev.aml = {
          since: cur.when,
          state: cur.state,
          threshold: cur.threshold
        }
        break;
      }
      case "kyc-collection": {
        Object.keys(cur.values).forEach((field) => {
          prev.kyc[field] = {
            value: (cur.values as any)[field],
            provider: cur.provider,
            since: cur.when,
          };
        });
        break;
      }
    }
    return prev;
  }, initial);
}

export const amlStateConverter = {
  toStringUI: stringifyAmlState,
  fromStringUI: parseAmlState,
};

function stringifyAmlState(s: AmlExchangeBackend.AmlState | undefined): string {
  if (s === undefined) return "";
  switch (s) {
    case AmlExchangeBackend.AmlState.normal:
      return "normal";
    case AmlExchangeBackend.AmlState.pending:
      return "pending";
    case AmlExchangeBackend.AmlState.frozen:
      return "frozen";
  }
}

function parseAmlState(s: string | undefined): AmlExchangeBackend.AmlState {
  switch (s) {
    case "normal":
      return AmlExchangeBackend.AmlState.normal;
    case "pending":
      return AmlExchangeBackend.AmlState.pending;
    case "frozen":
      return AmlExchangeBackend.AmlState.frozen;
    default:
      throw Error(`unknown AML state: ${s}`);
  }
}
