/*
 This file is part of GNU Taler
 (C) 2022 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 {
  HttpResponsePaginated,
  useTranslationContext,
} from "@gnu-taler/web-util/lib/index.browser";
import { createHashHistory } from "history";
import { h, VNode } from "preact";
import Router, { route, Route } from "preact-router";
import { useEffect } from "preact/hooks";
import { Loading } from "../components/Loading.js";
import { PageStateType, usePageContext } from "../context/pageState.js";
import { HomePage } from "./HomePage.js";
import { BankFrame } from "./BankFrame.js";
import { PublicHistoriesPage } from "./PublicHistoriesPage.js";
import { RegistrationPage } from "./RegistrationPage.js";
import { BusinessAccount } from "./BusinessAccount.js";

function handleNotOkResult(
  safe: string,
  saveError: (state: PageStateType["error"]) => void,
  i18n: ReturnType<typeof useTranslationContext>["i18n"],
): <T, E>(result: HttpResponsePaginated<T, E>) => VNode {
  return function handleNotOkResult2<T, E>(
    result: HttpResponsePaginated<T, E>,
  ): VNode {
    if (result.clientError && result.isUnauthorized) {
      route(safe);
      return <Loading />;
    }
    if (result.clientError && result.isNotfound) {
      route(safe);
      return (
        <div>Page not found, you are going to be redirected to {safe}</div>
      );
    }
    if (result.loading) return <Loading />;
    if (!result.ok) {
      saveError({
        title: i18n.str`The backend reported a problem: HTTP status #${result.status}`,
        description: i18n.str`Diagnostic from ${result.info?.url} is "${result.message}"`,
        debug: JSON.stringify(result.error),
      });
      route(safe);
    }
    return <div />;
  };
}

export function Routing(): VNode {
  const history = createHashHistory();
  const { pageStateSetter } = usePageContext();

  function saveError(error: PageStateType["error"]): void {
    pageStateSetter((prev) => ({ ...prev, error }));
  }
  const { i18n } = useTranslationContext();
  return (
    <Router history={history}>
      <Route
        path="/public-accounts"
        component={() => (
          <BankFrame>
            <PublicHistoriesPage
              onLoadNotOk={handleNotOkResult("/account", saveError, i18n)}
            />
          </BankFrame>
        )}
      />
      <Route
        path="/register"
        component={() => (
          <BankFrame>
            <RegistrationPage
              onError={saveError}
              onComplete={() => {
                route("/account");
              }}
            />
          </BankFrame>
        )}
      />
      <Route
        path="/account"
        component={() => (
          <BankFrame
            goToBusinessAccount={() => {
              route("/business");
            }}
          >
            <HomePage
              onRegister={() => {
                route("/register");
              }}
            />
          </BankFrame>
        )}
      />
      <Route
        path="/business"
        component={() => (
          <BankFrame>
            <BusinessAccount
              onClose={() => {
                route("/account");
              }}
              onRegister={() => {
                route("/register");
              }}
              onLoadNotOk={handleNotOkResult("/account", saveError, i18n)}
            />
          </BankFrame>
        )}
      />
      <Route default component={Redirect} to="/account" />
    </Router>
  );
}

function Redirect({ to }: { to: string }): VNode {
  useEffect(() => {
    route(to, true);
  }, []);
  return <div>being redirected to {to}</div>;
}
