/*
 This file is part of GNU Taler
 (C) 2021-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/>
 */

/**
 *
 * @author Sebastian Javier Marchano (sebasjm)
 * @author Nicola Eigel
 */

import {TranslatedString} from "@gnu-taler/taler-util";
import {
    useTranslationContext,
} from "@gnu-taler/web-util/browser";
import {VNode, h} from "preact";
import {Route, Router, route} from "preact-router";
import {useEffect, useErrorBoundary, useMemo, useState} from "preact/hooks";
import {Menu, NotificationCard} from "./components/menu/index.js";
import {EntityContextProvider} from "./context/entity.js";
import {Notification} from "./utils/types.js";
import NotFoundPage from "./paths/notfound/index.js";
import {Settings} from "./paths/settings/index.js";
import DefaultList from "./paths/default/index.js";
import {
    AuditorBackend,
} from "./declaration.js";
import FinanceDashboard from "./paths/finance/index.js";
import DetailsDashboard from "./paths/details/index.js";
import OperationsDashboard from "./paths/operations/index.js";
import SecurityDashboard from "./paths/security/index.js";

export enum Paths {
    error = "/error",
    settings = "/settings",

    key_figures = "/key-figures",
    critical_errors = "/critical-errors",
    operating_status = "/operating-status",
    detail_view = "/detail-view",

    amount_arithmethic_inconsistency_list = "/amount-arithmetic-inconsistencies",

    bad_sig_losses_list = "/bad-sig-losses",

    balance_list = "/balance",

    closure_lag_list = "/closure-lags",

    coin_inconsistency_list = "/coin-inconsistencies",

    denomination_key_validity_withdraw_inconsistency_list = "/denomination-key-validity-withdraw-inconsistencies",

    denomination_pending_list = "/denominations-pending",

    denomination_without_sig_list = "/denominations-without-sig",

    deposit_confirmation_list = "/deposit-confirmations",
    deposit_confirmation_update = "/deposit-confirmation/:rowid/update",

    emergency_list = "/emergencies",

    emergency_by_count_list = "/emergencies-by-count",

    exchange_signkey_list = "/exchange-sign-keys",

    fee_time_inconsistency_list = "/fee-time-inconsistencies",

    historic_denomination_revenue_list = "/historic-denomination-revenues",

    misattribution_in_inconsistency_list = "/misattribution-in-inconsistencies",

    progress_list = "/progress",

    purse_not_closed_inconsistency_list = "/purse-not-closed-inconsistencies",

    purse_list = "/purses",

    refresh_hanging_list = "/refreshes-hanging",

    reserve_balance_insufficient_inconsistency_list = "/reserve-balance-insufficient-inconsistencies",

    reserve_balance_summary_wrong_inconsistency_list = "/reserve-balance-summary-wrong-inconsistencies",

    reserve_in_inconsistency_list = "/reserve-in-inconsistencies",

    reserve_not_closed_inconsistency_list = "/reserve-not-closed-inconsistencies",

    reserves_list = "/reserves",

    row_inconsistency_list = "/row-inconsistencies",

    row_minor_inconsistency_list = "/row-minor-inconsistencies",

    wire_format_inconsistency_list = "/wire-format-inconsistencies",

    wire_out_inconsistency_list = "/wire-out-inconsistencies"
}

interface TestProps {
    title: string;
    endpoint: string;
    entity: any;
}

function getInstanceTitle(path: string): TestProps {
    switch (path) {
        case Paths.key_figures:
            return {title: `Key figures`, endpoint: "helper", entity: null};
        case Paths.critical_errors:
            return {title: `Critical errors`, endpoint: "helper", entity: null};
        case Paths.operating_status:
            return {title: `Operating status`, endpoint: "helper", entity: null};
        case Paths.detail_view:
            return {title: `Inconsistencies`, endpoint: "helper", entity: null};
        case Paths.amount_arithmethic_inconsistency_list:
            let amountArithmeticInconsistency: AuditorBackend.AmountArithmeticInconsistency.ClassAmountArithmeticInconsistency = {} as AuditorBackend.AmountArithmeticInconsistency.ClassAmountArithmeticInconsistency;
            return {
                title: `Amount arithmetic inconsistencies`,
                endpoint: "amount-arithmetic-inconsistency",
                entity: amountArithmeticInconsistency
            };
        case Paths.bad_sig_losses_list:
            return {title: `Bad Sig Losses`, endpoint: "bad-sig-losses", entity: null};
        case Paths.balance_list:
            return {title: "Balances", endpoint: "balances", entity: null};
        case Paths.closure_lag_list:
            return {title: `Closure Lags`, endpoint: "closure-lags", entity: null};
        case Paths.coin_inconsistency_list:
            return {title: `Coin inconsistencies`, endpoint: "coin-inconsistency", entity: null};
        case Paths.denomination_key_validity_withdraw_inconsistency_list:
            return {title: `Denomination key validity withdraw inconsistency`, endpoint: "denomination-key-validity-withdraw-inconsistency", entity: null};
        case Paths.denomination_pending_list:
            return {title: `Denominations pending`, endpoint: "denomination-pending", entity: null};
        case Paths.denomination_without_sig_list:
            return {title: `Denominations without sigs`, endpoint: "denominations-without-sigs", entity: null};
        case Paths.deposit_confirmation_list:
            return {title: "Deposit Confirmations", endpoint: "deposit-confirmation", entity: null};
        case Paths.emergency_list:
            return {title: "Emergencies", endpoint: "emergency", entity: null};
        case Paths.emergency_by_count_list:
            return {title: "Emergencies by count", endpoint: "emergency-by-count", entity: null};
        case Paths.fee_time_inconsistency_list:
            return {title: "Fee time inconsistencies", endpoint: "fee-time-inconsistency", entity: null};
        case Paths.historic_denomination_revenue_list:
            return {title: "Historic denomination revenue", endpoint: "historic-denomination-revenue", entity: null};
        case Paths.misattribution_in_inconsistency_list:
            return {title: "Misattribution in inconsistencies", endpoint: "misattribution-in-inconsistency", entity: null};
        case Paths.progress_list:
            return {title: "Progress", endpoint: "progress", entity: null};
        case Paths.purse_not_closed_inconsistency_list:
            return {title: "Purse not closed inconsistencies", endpoint: "purse-not-closed-inconsistencies", entity: null};
        case Paths.purse_list:
            return {title: "Purses", endpoint: "purses", entity: null};
        case Paths.refresh_hanging_list:
            return {title: "Refreshes hanging", endpoint: "refreshes-hanging", entity: null};
        case Paths.reserves_list:
            return {title: "Reserves", endpoint: "reserves  ", entity: null};
        case Paths.reserve_balance_insufficient_inconsistency_list:
            return {title: "Reserve balance insufficient inconsistencies", endpoint: "reserve-balance-insufficient-inconsistency", entity: null};
        case Paths.reserve_balance_summary_wrong_inconsistency_list:
            return {title: "Reserve balance summary wrong inconsistencies", endpoint: "reserve-balance-summary-wrong-inconsistency", entity: null};
        case Paths.reserve_in_inconsistency_list:
            return {title: "Reserves in inconsistencies", endpoint: "reserve-in-inconsistency", entity: null};
        case Paths.reserve_not_closed_inconsistency_list:
            return {title: "Reserves not closed inconsistencies", endpoint: "reserve-not-closed-inconsistency", entity: null};
        case Paths.row_inconsistency_list:
            return {title: "Row inconsistencies", endpoint: "row-inconsistency", entity: null};
        case Paths.row_minor_inconsistency_list:
            return {title: "Row minor inconsistencies", endpoint: "row-minor-inconsistencies", entity: null};
        case Paths.wire_format_inconsistency_list:
            let wireFormatInconsistency: AuditorBackend.WireFormatInconsistency.ClassWireFormatInconsistency = {} as AuditorBackend.WireFormatInconsistency.ClassWireFormatInconsistency;
            return {title: "Wire format inconsistencies", endpoint: "wire-format-inconsistency", entity: wireFormatInconsistency};
        case Paths.wire_out_inconsistency_list:
            return {title: "Wire out inconsistencies", endpoint: "wire-out-inconsistency", entity: null};
        case Paths.settings:
            return {title: `Settings`, endpoint: "settings", entity: null};
        default:
            return {title: "", endpoint: "", entity: null};
    }
}

export interface Props {
    path: string;
}

export function InstanceRoutes({
                                   //  id,
                                   path,
                                   //  setInstanceName
                               }: Props): VNode {
    const {i18n} = useTranslationContext();

    type GlobalNotifState = (Notification & { to: string | undefined }) | undefined;
    const [globalNotification, setGlobalNotification] =
        useState<GlobalNotifState>(undefined);

    const [error] = useErrorBoundary();
    const {title, endpoint, entity} = getInstanceTitle(path.replace("app/#", ""));

    const value = useMemo(
        () => ({title, path, endpoint, entity}),
        [title, path, endpoint, entity],
    );

    //TODO add if needed
    /*function ServerErrorRedirectTo(to: Paths) {
      return function ServerErrorRedirectToImpl(
        error: HttpError<AuditorBackend.ErrorDetail>,
      ) {
        if (error.type === ErrorType.TIMEOUT) {
          setGlobalNotification({
            message: `The request to the backend take too long and was cancelled`,
            description: `Diagnostic from ${error.info.url} is "${error.message}"`,
            type: "ERROR",
            to,
          });
        } else {
          setGlobalNotification({
            message: `The backend reported a problem: HTTP status #${error.status}`,
            description: `Diagnostic from ${error.info.url} is '${error.message}'`,
            details:
              error.type === ErrorType.CLIENT || error.type === ErrorType.SERVER
                ? error.payload.detail
                : undefined,
            type: "ERROR",
            to,
          });
        }
        return <Redirect to={to} />;
      };
    }*/


    return (
        <EntityContextProvider value={value}>
            <Menu
                //    instance={id}
                path={path}
                title={"Settings"}
                onShowSettings={() => {
                    route(Paths.settings);
                }}/>
            <NotificationCard notification={globalNotification}/>
            {error &&
                <NotificationCard notification={{
                    message: "Internal error, please report",
                    type: "ERROR",
                    description: <pre>
            {(error instanceof Error ? error.stack : String(error)) as TranslatedString}
          </pre>,
                }}/>
            }
            <Router
                onChange={(e) => {
                    const movingOutFromNotification =
                        globalNotification && e.url !== globalNotification.to;
                    if (movingOutFromNotification) {
                        setGlobalNotification(undefined);
                    }
                }}
            >
                <Route path="/" component={Redirect} to={Paths.key_figures}/>

                <Route
                    path={Paths.key_figures}
                    component={FinanceDashboard}
                    onNotFound={NotFoundPage}
                    //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                    path={Paths.critical_errors}
                    component={SecurityDashboard}
                    onNotFound={NotFoundPage}
                    //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                    path={Paths.operating_status}
                    component={OperationsDashboard}
                    onNotFound={NotFoundPage}
                    //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                    path={Paths.detail_view}
                    component={DetailsDashboard}
                    onNotFound={NotFoundPage}
                    //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                  path={Paths.amount_arithmethic_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                  //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                  path={Paths.bad_sig_losses_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                  //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                    path={Paths.balance_list}
                    component={DefaultList}
                    onNotFound={NotFoundPage}
                    //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                  path={Paths.closure_lag_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                  //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                  path={Paths.coin_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                  //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                  path={Paths.denomination_key_validity_withdraw_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                  //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                  path={Paths.denomination_pending_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                  //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                  path={Paths.denomination_without_sig_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                  //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                  path={Paths.deposit_confirmation_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                  //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                  path={Paths.emergency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                  //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                <Route
                  path={Paths.emergency_by_count_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                  //onLoadError={ServerErrorRedirectTo(Paths.balance_list)}
                />
                {<Route
                    path={Paths.exchange_signkey_list}
                    component={DefaultList}
                    onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.fee_time_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.historic_denomination_revenue_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.misattribution_in_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.progress_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.purse_not_closed_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.purse_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.refresh_hanging_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.reserve_balance_insufficient_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.reserve_balance_summary_wrong_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.reserve_in_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.reserve_not_closed_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.reserves_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.row_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.row_minor_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.wire_out_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                {<Route
                  path={Paths.wire_format_inconsistency_list}
                  component={DefaultList}
                  onNotFound={NotFoundPage}
                />}
                <Route
                  path={Paths.settings}
                  component={Settings}
                />

                {//TODO add if needed
                 /**
                 * Example pages
                 */}
                {/*             <Route path="/loading" component={Loading}/>
                <Route default component={NotFoundPage}/>*/}
            </Router>
        </EntityContextProvider>
    );
}

export function Redirect({to}: { to: string }): null {
    useEffect(() => {
        route(to, true);
    });
    return null;
}