/*
 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 { canonicalizeBaseUrl } from "@gnu-taler/taler-util";
import {
  BrowserHashNavigationProvider,
  ExchangeApiProvider,
  Loading,
  TranslationProvider,
  UiForms,
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
import { useEffect, useState } from "preact/hooks";
import { SWRConfig } from "swr";
import { ExchangeAmlFrame } from "./ExchangeAmlFrame.js";
import { Routing } from "./Routing.js";
import { UiSettingsProvider } from "./context/ui-settings.js";
import { strings } from "./i18n/strings.js";
import "./scss/main.css";
import { UiSettings, fetchUiSettings } from "./context/ui-settings.js";
import { UiFormsProvider, fetchUiForms } from "./context/ui-forms.js";

const WITH_LOCAL_STORAGE_CACHE = false;

export function App(): VNode {
  const [settings, setSettings] = useState<UiSettings>();
  const [forms, setForms] = useState<UiForms>();
  useEffect(() => {
    fetchUiSettings(setSettings);
    fetchUiForms(setForms);
  }, []);
  if (!settings || !forms) return <Loading />;

  const baseUrl = getInitialBackendBaseURL(settings.backendBaseURL);
  return (
    <UiSettingsProvider value={settings}>
      <TranslationProvider
        source={strings}
        completeness={{
          es: strings["es"].completeness,
          de: strings["de"].completeness,
        }}
      >
        <ExchangeApiProvider
          baseUrl={new URL("/", baseUrl)}
          frameOnError={ExchangeAmlFrame}
        >
          <SWRConfig
            value={{
              provider: WITH_LOCAL_STORAGE_CACHE
                ? localStorageProvider
                : undefined,
              // normally, do not revalidate
              revalidateOnFocus: false,
              revalidateOnReconnect: false,
              revalidateIfStale: false,
              revalidateOnMount: undefined,
              focusThrottleInterval: undefined,

              // normally, do not refresh
              refreshInterval: undefined,
              dedupingInterval: 2000,
              refreshWhenHidden: false,
              refreshWhenOffline: false,

              // ignore errors
              shouldRetryOnError: false,
              errorRetryCount: 0,
              errorRetryInterval: undefined,

              // do not go to loading again if already has data
              keepPreviousData: true,
            }}
          >
            <BrowserHashNavigationProvider>
              <UiFormsProvider value={forms}>
                <Routing />
              </UiFormsProvider>
            </BrowserHashNavigationProvider>
          </SWRConfig>
        </ExchangeApiProvider>
      </TranslationProvider>
    </UiSettingsProvider>
  );
}

function localStorageProvider(): Map<unknown, unknown> {
  const map = new Map(JSON.parse(localStorage.getItem("app-cache") || "[]"));

  window.addEventListener("beforeunload", () => {
    const appCache = JSON.stringify(Array.from(map.entries()));
    localStorage.setItem("app-cache", appCache);
  });
  return map;
}

function getInitialBackendBaseURL(
  backendFromSettings: string | undefined,
): string {
  const overrideUrl =
    typeof localStorage !== "undefined"
      ? localStorage.getItem("exchange-base-url")
      : undefined;
  let result: string;

  if (!overrideUrl) {
    // normal path
    if (!backendFromSettings) {
      console.error(
        "ERROR: backendBaseURL was overridden by a setting file and missing. Setting value to 'window.origin'",
      );
      result = window.origin;
    } else {
      result = backendFromSettings;
    }
  } else {
    // testing/development path
    result = overrideUrl;
  }
  try {
    return canonicalizeBaseUrl(result);
  } catch (e) {
    // fall back
    return canonicalizeBaseUrl(window.origin);
  }
}
