/*
 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 {
  AmlSpaDialect,
  assertUnreachable,
  EventReporting_TOPS_calculation,
  TalerError,
  TranslatedString,
} from "@gnu-taler/taler-util";
import {
  ErrorLoading,
  InternationalizationAPI,
  Loading,
  useExchangeApiContext,
  useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
import { HandleAccountNotReady } from "../components/HandleAccountNotReady.js";
import { useOfficer } from "../hooks/officer.js";
import { usePreferences } from "../hooks/preferences.js";
import { useTopsServerStatistics } from "../hooks/server-info.js";

export function Dashboard() {
  const officer = useOfficer();
  const { i18n } = useTranslationContext();

  if (officer.state !== "ready") {
    return <HandleAccountNotReady officer={officer} />;
  }

  return (
    <div>
      <h1 class="my-2 text-3xl font-bold tracking-tight text-gray-900 ">
        <i18n.Translate>Dashboard</i18n.Translate>
      </h1>
      <EventMetrics />
    </div>
  );
}

function EventMetrics(): VNode {
  const { i18n } = useTranslationContext();
  // const [metricType, setMetricType] =
  //   useState<TalerCorebankApi.MonitorTimeframeParam>(
  //     TalerCorebankApi.MonitorTimeframeParam.hour,
  //   );
  // const params = useMemo(
  //   () => getTimeframesForDate(now, metricType),
  //   [metricType],
  // );

  const [pref] = usePreferences();
  const { config } = useExchangeApiContext();

  const dialect =
    (pref.testingDialect ? undefined : config.config.aml_spa_dialect) ??
    AmlSpaDialect.TESTING;

  if (dialect === "gls") {
    return <div>No dashboard configured for dialect <code>gls</code>.</div>;
  }

  const resp = useTopsServerStatistics();

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

  return (
    <div class="px-4 mt-4">
      <div class="sm:flex sm:items-center mb-4">
        <div class="sm:flex-auto">
          <h1 class="text-base font-semibold leading-6 text-gray-900">
            <i18n.Translate>Statistics</i18n.Translate>
          </h1>
        </div>
      </div>

      {/* <SelectTimeframe timeframe={metricType} setTimeframe={setMetricType} /> */}

      {/* <div class="w-full flex justify-between">
        <h1 class="text-base text-gray-900 mt-5">
          {i18n.str`Events from ${getDateStringForTimeframe(
            params.current.start,
            metricType,
            dateLocale,
          )} to ${getDateStringForTimeframe(
            params.current.end,
            metricType,
            dateLocale,
          )}`}
        </h1>
      </div> */}

      <dl class="mt-5 grid grid-cols-1 md:grid-cols-4  divide-y divide-gray-200 overflow-hidden rounded-lg bg-white shadow-lg md:divide-x md:divide-y-0">
        {Object.entries(resp.body).map(([name, number], k) => {
          const label = labelForEvent(name, i18n, dialect);
          const desc = descriptionForEvent(name, i18n, dialect);
          return (
            <div class="px-4 py-5 sm:p-6" key={k}>
              <dt class="text-base font-normal text-gray-900">
                {label}
                {!desc ? undefined : (
                  <div class="text-xs text-gray-500">{desc}</div>
                )}
              </dt>
              <MetricValueNumber current={number} previous={undefined} />
            </div>
          );
        })}
      </dl>

      {/* <div class="flex justify-end mt-4">
        <a
          href={routeToDownloadStats.url({})}
          name="download stats"
          class="disabled:opacity-50 disabled:cursor-default cursor-pointer 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"
        >
          <i18n.Translate>Download stats as CSV</i18n.Translate>
        </a>
      </div> */}
    </div>
  );
}

function labelForEvent(
  name: string,
  i18n: InternationalizationAPI,
  dialect: AmlSpaDialect,
) {
  switch (dialect) {
    case AmlSpaDialect.TOPS:
      return labelForEvent_tops(
        // @ts-expect-error name is the field
        name,
        i18n,
      );
    case AmlSpaDialect.GLS:
      // return labelForEvent_gls(name as GLS_AmlEventsName, i18n);
      return labelForEvent_tops(
        // @ts-expect-error name is the field
        name,
        i18n,
      );
    case AmlSpaDialect.TESTING:
      return labelForEvent_tops(
        // @ts-expect-error name is the field
        name,
        i18n,
      );
    default: {
      assertUnreachable(dialect);
    }
  }
}
function labelForEvent_tops(
  name: keyof ReturnType<typeof EventReporting_TOPS_calculation>,
  i18n: InternationalizationAPI,
) {
  switch (name) {
    case "accounts_opened":
      return i18n.str`Accounts open`;

    case "new_gwg_files_last_year":
      return i18n.str`New files last year`;

    case "gwg_files_closed_last_year":
      return i18n.str`Closes files last year`;

    case "mros_reports_art9_last_year":
      return i18n.str`MROS substantaiated`;

    case "mros_reports_art305_last_year":
      return i18n.str`MROS simple`;

    case "gwg_files_high_risk":
      return i18n.str`High risk files`;

    case "gwg_files_pep":
      return i18n.str`PEP files`;

    case "accounts_involed_in_proceedings_last_year":
      return i18n.str`Under investiation`;

    default: {
      assertUnreachable(name);
    }
  }
}
// function labelForEvent_gls(
//   name: GLS_AmlEventsName,
//   i18n: InternationalizationAPI,
// ) {
//   switch (name) {
//     case GLS_AmlEventsName.ACCOUNT_OPENED:
//       return i18n.str`Account opened`;
//     case GLS_AmlEventsName.ACCOUNT_CLOSED:
//       return i18n.str`Account closed`;
//     default: {
//       assertUnreachable(name);
//     }
//   }
// }

function descriptionForEvent(
  name: string,
  i18n: InternationalizationAPI,
  dialect: AmlSpaDialect,
): TranslatedString | undefined {
  switch (dialect) {
    case AmlSpaDialect.TOPS:
      return descriptionForEvent_tops(
        // @ts-expect-error name is the field
        name,
        i18n,
      );
    case AmlSpaDialect.GLS:
      return descriptionForEvent_tops(
        // @ts-expect-error name is the field
        name,
        i18n,
      );
    // return descriptionForEvent_gls(name as GLS_AmlEventsName, i18n);
    case AmlSpaDialect.TESTING:
      return descriptionForEvent_tops(
        // @ts-expect-error name is the field
        name,
        i18n,
      );
    default: {
      assertUnreachable(dialect);
    }
  }
}

function descriptionForEvent_tops(
  name: keyof ReturnType<typeof EventReporting_TOPS_calculation>,
  i18n: InternationalizationAPI,
): TranslatedString | undefined {
  switch (name) {
    case "accounts_opened":
      return i18n.str`Number of accounts that are opened`;

    case "new_gwg_files_last_year":
      return i18n.str`Number of new GwG files in the last year`;

    case "gwg_files_closed_last_year":
      return i18n.str`Number of GwG files closed in the last year`;

    case "mros_reports_art9_last_year":
      return i18n.str`Number of MROS reports based on Art 9 Abs. 1 GwG (per year)`;

    case "mros_reports_art305_last_year":
      return i18n.str`Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)`;

    case "gwg_files_high_risk":
      return i18n.str`Number of GwG files of high-risk customers`;

    case "gwg_files_pep":
      return i18n.str`Number of GwG files managed with “increased risk” due to PEP status`;

    case "accounts_involed_in_proceedings_last_year":
      return i18n.str`Number of customers involved in proceedings for which Art 6 GwG did apply`;

    default: {
      assertUnreachable(name);
    }
  }
}

// function descriptionForEvent_gls(
//   name: GLS_AmlEventsName,
//   i18n: InternationalizationAPI,
// ): TranslatedString | undefined {
//   switch (name) {
//     case GLS_AmlEventsName.ACCOUNT_OPENED:
//       return i18n.str`Account opened`;
//     case GLS_AmlEventsName.ACCOUNT_CLOSED:
//       return i18n.str`Account closed`;
//     default: {
//       assertUnreachable(name);
//     }
//   }
// }

function MetricValueNumber({
  current,
  previous,
}: {
  current: number | undefined;
  previous: number | undefined;
}): VNode {
  const { i18n } = useTranslationContext();

  const cmp = current && previous ? (current < previous ? -1 : 1) : 0;

  const rate =
    !current || Number.isNaN(current) || !previous || Number.isNaN(previous)
      ? 0
      : cmp === -1
        ? 1 - Math.round(current) / Math.round(previous)
        : cmp === 1
          ? Math.round(current) / Math.round(previous) - 1
          : 0;

  const negative = cmp === 0 ? undefined : cmp === -1;
  const rateStr = `${(Math.abs(rate) * 100).toFixed(2)}%`;
  return (
    <Fragment>
      <dd class="mt-1 block ">
        <div class="flex justify-start text-2xl items-baseline font-semibold text-indigo-600">
          {!current ? 0 : current}
        </div>
        <div class="flex flex-col">
          <div class="flex justify-end items-baseline text-2xl font-semibold text-indigo-600">
            {previous === undefined ? undefined : (
              <small class="ml-2 text-sm font-medium text-gray-500">
                <i18n.Translate>previous</i18n.Translate> {previous}
              </small>
            )}
          </div>
          {!!rate && (
            <span
              data-negative={negative}
              class="flex items-center gap-x-1.5 w-fit rounded-md bg-green-100 text-green-800 data-[negative=true]:bg-red-100 px-2 py-1 text-xs font-medium data-[negative=true]:text-red-700 whitespace-pre"
            >
              {negative ? (
                <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="M12 4.5v15m0 0l6.75-6.75M12 19.5l-6.75-6.75"
                  />
                </svg>
              ) : (
                <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="M12 19.5v-15m0 0l-6.75 6.75M12 4.5l6.75 6.75"
                  />
                </svg>
              )}

              {negative ? (
                <span class="sr-only">
                  <i18n.Translate>Decreased by</i18n.Translate>
                </span>
              ) : (
                <span class="sr-only">
                  <i18n.Translate>Increased by</i18n.Translate>
                </span>
              )}
              {rateStr}
            </span>
          )}
        </div>
      </dd>
    </Fragment>
  );
}
