/*
 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)
 */

import { TalerMerchantApi } from "@gnu-taler/taler-util";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
import { StateUpdater, useEffect, useState } from "preact/hooks";
import { useSessionContext } from "../../../context/session.js";

const TALER_SCREEN_ID = 27;

interface Props {
  instances: TalerMerchantApi.Instance[];
  onUpdate: (id: string) => void;
  onChangePassword: (id: string) => void;
  onDelete: (id: TalerMerchantApi.Instance) => void;
  onPurge: (id: TalerMerchantApi.Instance) => void;
  onCreate: () => void;
  selected?: boolean;
}

export function CardTable({
  instances,
  onCreate,
  onUpdate,
  onPurge,
  onDelete,
  onChangePassword,
  selected,
}: Props): VNode {
  const [actionQueue, actionQueueHandler] = useState<Actions[]>([]);
  const [rowSelection, rowSelectionHandler] = useState<string[]>([]);

  useEffect(() => {
    if (
      actionQueue.length > 0 &&
      !selected &&
      actionQueue[0].type == "DELETE"
    ) {
      onDelete(actionQueue[0].element);
      actionQueueHandler(actionQueue.slice(1));
    }
  }, [actionQueue, selected, onDelete]);

  useEffect(() => {
    if (
      actionQueue.length > 0 &&
      !selected &&
      actionQueue[0].type == "UPDATE"
    ) {
      onUpdate(actionQueue[0].element.id);
      actionQueueHandler(actionQueue.slice(1));
    }
  }, [actionQueue, selected, onUpdate]);

  const { i18n } = useTranslationContext();

  return (
    <div class="card has-table">
      <header class="card-header">
        <p class="card-header-title">
          <span class="icon">
            <i class="mdi mdi-desktop-mac" />
          </span>
          <i18n.Translate>Instances</i18n.Translate>
        </p>

        <div class="card-header-icon" aria-label="more options">
          <button
            class={rowSelection.length > 0 ? "button is-danger" : "is-hidden"}
            type="button"
            onClick={(): void =>
              actionQueueHandler(
                buildActions(instances, rowSelection, "DELETE"),
              )
            }
          >
            <i18n.Translate>Delete</i18n.Translate>
          </button>
        </div>
        <div class="card-header-icon" aria-label="more options">
          <span
            class="has-tooltip-left"
            data-tooltip={i18n.str`Add new instance`}
          >
            <button
              class="button is-info"
              type="button"
              accessKey="+"
              onClick={onCreate}
            >
              <span class="icon is-small">
                <i class="mdi mdi-plus mdi-36px" />
              </span>
            </button>
          </span>
        </div>
      </header>
      <div class="card-content">
        <div class="b-table has-pagination">
          <div class="table-wrapper has-mobile-cards">
            {instances.length > 0 ? (
              <Table
                instances={instances}
                onPurge={onPurge}
                onUpdate={onUpdate}
                onDelete={onDelete}
                onChangePassword={onChangePassword}
                rowSelection={rowSelection}
                rowSelectionHandler={rowSelectionHandler}
              />
            ) : (
              <EmptyTable />
            )}
          </div>
        </div>
      </div>
    </div>
  );
}
interface TableProps {
  rowSelection: string[];
  instances: TalerMerchantApi.Instance[];
  onUpdate: (id: string) => void;
  onChangePassword: (id: string) => void;
  onDelete: (id: TalerMerchantApi.Instance) => void;
  onPurge: (id: TalerMerchantApi.Instance) => void;
  rowSelectionHandler: StateUpdater<string[]>;
}

function toggleSelected<T>(id: T): (prev: T[]) => T[] {
  return (prev: T[]): T[] =>
    prev.indexOf(id) == -1 ? [...prev, id] : prev.filter((e) => e != id);
}

/**
 * FIXME: put this on UI settings
 */
const HIDE_EDIT_INSTANCE = true;

function Table({
  rowSelection,
  rowSelectionHandler,
  instances,
  onUpdate,
  onChangePassword,
  onDelete,
  onPurge,
}: TableProps): VNode {
  const { i18n } = useTranslationContext();
  const { lib, impersonate } = useSessionContext();
  return (
    <div class="table-container">
      <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
        <thead>
          <tr>
            <th class="is-checkbox-cell">
              <label class="b-checkbox checkbox">
                <input
                  type="checkbox"
                  checked={rowSelection.length === instances.length}
                  onClick={(): void =>
                    rowSelectionHandler(
                      rowSelection.length === instances.length
                        ? []
                        : instances.map((i) => i.id),
                    )
                  }
                />
                <span class="check" />
              </label>
            </th>
            <th>
              <i18n.Translate>ID</i18n.Translate>
            </th>
            <th>
              <i18n.Translate>Name</i18n.Translate>
            </th>
            <th />
          </tr>
        </thead>
        <tbody>
          {instances.map((i) => {
            return (
              <tr key={i.id}>
                <td class="is-checkbox-cell">
                  <label class="b-checkbox checkbox">
                    <input
                      type="checkbox"
                      checked={rowSelection.indexOf(i.id) != -1}
                      onClick={(): void =>
                        rowSelectionHandler(toggleSelected(i.id))
                      }
                    />
                    <span class="check" />
                  </label>
                </td>
                <td>
                  <a
                    href={`#/orders`}
                    onClick={async (_e) => {
                      // e.preventDefault();
                      const newInstanceApi = lib.subInstanceApi(i.id);
                      //not checking /config since this comes from instance list
                      impersonate(new URL(newInstanceApi.instance.baseUrl));
                    }}
                  >
                    {i.id}
                  </a>
                </td>
                <td>{i.name}</td>
                <td class="is-actions-cell right-sticky">
                  <div class="buttons is-right">
                    {HIDE_EDIT_INSTANCE ? undefined : (
                      <button
                        class="button is-small is-success jb-modal"
                        type="button"
                        onClick={(): void => onUpdate(i.id)}
                      >
                        <i18n.Translate>Edit</i18n.Translate>
                      </button>
                    )}
                    <button
                      class="button is-small is-success jb-modal"
                      type="button"
                      onClick={(): void => onChangePassword(i.id)}
                    >
                      <i18n.Translate>Change password</i18n.Translate>
                    </button>
                    {!i.deleted && (
                      <button
                        class="button is-small is-danger jb-modal is-outlined"
                        type="button"
                        onClick={(): void => onDelete(i)}
                      >
                        <i18n.Translate>Delete</i18n.Translate>
                      </button>
                    )}
                    {i.deleted && (
                      <button
                        class="button is-small is-danger jb-modal"
                        type="button"
                        onClick={(): void => onPurge(i)}
                      >
                        <i18n.Translate>Purge</i18n.Translate>
                      </button>
                    )}
                  </div>
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

function EmptyTable(): VNode {
  const { i18n } = useTranslationContext();
  return (
    <div class="content has-text-grey has-text-centered">
      <p>
        <span class="icon is-large">
          <i class="mdi mdi-magnify mdi-48px" />
        </span>
      </p>
      <p>
        <i18n.Translate>
          There are no instances yet. Add one by pressing the '+' sign.
        </i18n.Translate>
      </p>
    </div>
  );
}

interface Actions {
  element: TalerMerchantApi.Instance;
  type: "DELETE" | "UPDATE";
}

function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
  return value !== null && value !== undefined;
}

function buildActions(
  instances: TalerMerchantApi.Instance[],
  selected: string[],
  action: "DELETE",
): Actions[] {
  return selected
    .map((id) => instances.find((i) => i.id === id))
    .filter(notEmpty)
    .map((id) => ({ element: id, type: action }));
}
