// AccountsPage — CRUD UI for balance accounts and balance categories.
//
// Issue #138 (Bilan #1a) ships the route `/balance/accounts` with two tabs:
//   - Comptes  : full CRUD over balance_accounts (create/edit/archive)
//   - Catégories : list of seeded + user-created categories. Users can add
//                  simple-kind categories (the priced toggle lands in #140),
//                  rename them, and delete the ones they created (the seeded
//                  ones are protected at the service layer).
//
// The sidebar entry "Bilan" is intentionally NOT added here — per spec-plan
// v2 it lands in Issue #141 (Bilan #3) when the `/balance` overview page
// becomes navigable. Until then the route is reachable directly via URL.

import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { ArchiveRestore, Edit2, Plus, Trash2, Wallet } from "lucide-react";
import type {
  BalanceAccountWithCategory,
  BalanceCategory,
} from "../shared/types";
import { useBalanceAccounts } from "../hooks/useBalanceAccounts";
import AccountForm from "../components/balance/AccountForm";
import type { CreateBalanceCategoryInput } from "../services/balance.service";
import {
  renderCategoryLabelFromAccount,
  renderCategoryLabelFromCategory,
} from "../utils/renderCategoryLabel";

type Tab = "accounts" | "categories";

export default function AccountsPage() {
  const { t } = useTranslation();
  const {
    state,
    setIncludeArchived,
    addAccount,
    editAccount,
    archiveAccount,
    unarchiveAccount,
    addCategory,
    editCategory,
    removeCategory,
  } = useBalanceAccounts();

  const [activeTab, setActiveTab] = useState<Tab>("accounts");
  const [showAccountForm, setShowAccountForm] = useState(false);
  const [editingAccount, setEditingAccount] =
    useState<BalanceAccountWithCategory | null>(null);

  const [showCategoryForm, setShowCategoryForm] = useState(false);
  /** Local error string for category deletion guard (count + names of linked accounts). */
  const [categoryDeleteError, setCategoryDeleteError] = useState<string | null>(
    null
  );

  const activeCategories = useMemo(
    () => state.categories.filter((c) => c.is_active),
    [state.categories]
  );

  /** Map category id → array of accounts linked to it (active + archived). */
  const accountsByCategory = useMemo(() => {
    const m = new Map<number, BalanceAccountWithCategory[]>();
    for (const acc of state.accounts) {
      const list = m.get(acc.balance_category_id) ?? [];
      list.push(acc);
      m.set(acc.balance_category_id, list);
    }
    return m;
  }, [state.accounts]);

  const renderCategoryLabel = (cat: BalanceCategory) =>
    renderCategoryLabelFromCategory(cat, t);

  const closeAccountForm = () => {
    setShowAccountForm(false);
    setEditingAccount(null);
  };

  const handleAccountSubmit = async (
    payload:
      | Parameters<typeof addAccount>[0]
      | Parameters<typeof editAccount>[1]
  ) => {
    try {
      if (editingAccount) {
        await editAccount(editingAccount.id, payload as Parameters<typeof editAccount>[1]);
      } else {
        await addAccount(payload as Parameters<typeof addAccount>[0]);
      }
      closeAccountForm();
    } catch {
      // Error already surfaced via state.error
    }
  };

  const handleCategorySubmit = async (input: CreateBalanceCategoryInput) => {
    try {
      await addCategory(input);
      setShowCategoryForm(false);
    } catch {
      // Error already surfaced via state.error
    }
  };

  /**
   * Delete-guard for categories. The service refuses to delete a seeded
   * category or one with linked accounts, but we pre-check at the UI to
   * surface a richer message that lists the linked-account names.
   */
  const handleDeleteCategory = (cat: BalanceCategory) => {
    setCategoryDeleteError(null);
    if (cat.is_seed) return;
    const linked = accountsByCategory.get(cat.id) ?? [];
    if (linked.length > 0) {
      const sample = linked.slice(0, 3).map((a) => a.name).join(", ");
      const more = linked.length > 3 ? ", …" : "";
      setCategoryDeleteError(
        t("balance.category.error.has_accounts", {
          count: linked.length,
          names: `${sample}${more}`,
        })
      );
      return;
    }
    if (!window.confirm(t("balance.category.actions.deleteConfirm"))) return;
    removeCategory(cat.id);
  };

  return (
    <div className={state.isLoading ? "opacity-50 pointer-events-none" : ""}>
      <div className="flex items-center gap-3 mb-6">
        <Wallet size={24} className="text-[var(--primary)]" />
        <h1 className="text-2xl font-bold">{t("balance.accountsPage.title")}</h1>
      </div>

      {state.error && (
        <div className="mb-4 p-3 rounded-lg bg-[var(--negative)]/10 text-[var(--negative)] text-sm border border-[var(--negative)]/20">
          {state.errorCode
            ? t(`balance.errors.${state.errorCode}`, {
                defaultValue: state.error,
              })
            : state.error}
        </div>
      )}

      <div className="flex border-b border-[var(--border)] mb-6">
        <button
          type="button"
          onClick={() => setActiveTab("accounts")}
          className={`px-4 py-2 text-sm font-medium border-b-2 -mb-px ${
            activeTab === "accounts"
              ? "border-[var(--primary)] text-[var(--primary)]"
              : "border-transparent text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
          }`}
        >
          {t("balance.accountsPage.tabs.accounts")}
        </button>
        <button
          type="button"
          onClick={() => setActiveTab("categories")}
          className={`px-4 py-2 text-sm font-medium border-b-2 -mb-px ${
            activeTab === "categories"
              ? "border-[var(--primary)] text-[var(--primary)]"
              : "border-transparent text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
          }`}
        >
          {t("balance.accountsPage.tabs.categories")}
        </button>
      </div>

      {activeTab === "accounts" && (
        <div>
          <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 mb-4">
            <label className="flex items-center gap-2 text-sm">
              <input
                type="checkbox"
                checked={state.includeArchived}
                onChange={(e) => setIncludeArchived(e.target.checked)}
              />
              {t("balance.accountsPage.includeArchived")}
            </label>
            <button
              type="button"
              onClick={() => {
                setEditingAccount(null);
                setShowAccountForm(true);
              }}
              disabled={activeCategories.length === 0}
              className="flex items-center gap-2 px-4 py-2 rounded-lg bg-[var(--primary)] text-white text-sm font-medium hover:opacity-90 disabled:opacity-50"
            >
              <Plus size={16} />
              {t("balance.accountsPage.newAccount")}
            </button>
          </div>

          {showAccountForm ? (
            <div className="bg-[var(--card)] rounded-xl border border-[var(--border)] p-4 mb-6">
              <h2 className="text-lg font-semibold mb-4">
                {editingAccount
                  ? t("balance.account.form.editTitle")
                  : t("balance.account.form.createTitle")}
              </h2>
              <AccountForm
                mode="account"
                initialAccount={editingAccount ?? null}
                categories={activeCategories}
                isSaving={state.isSaving}
                onSubmit={handleAccountSubmit}
                onCancel={closeAccountForm}
              />
            </div>
          ) : null}

          {state.accounts.length === 0 ? (
            <div className="bg-[var(--card)] rounded-xl border border-[var(--border)] p-8 text-center text-[var(--muted-foreground)]">
              {t("balance.accountsPage.empty")}
            </div>
          ) : (
            <div className="bg-[var(--card)] rounded-xl border border-[var(--border)] overflow-hidden">
              <table className="w-full text-sm">
                <thead className="bg-[var(--muted)]">
                  <tr>
                    <th className="text-left px-4 py-2 font-medium">
                      {t("balance.account.fields.name")}
                    </th>
                    <th className="text-left px-4 py-2 font-medium">
                      {t("balance.account.fields.category")}
                    </th>
                    <th className="text-left px-4 py-2 font-medium">
                      {t("balance.account.fields.symbol")}
                    </th>
                    <th className="text-left px-4 py-2 font-medium">
                      {t("balance.account.fields.currency")}
                    </th>
                    <th className="text-left px-4 py-2 font-medium">
                      {t("balance.account.fields.status")}
                    </th>
                    <th className="text-right px-4 py-2 font-medium">
                      {t("balance.account.fields.actions")}
                    </th>
                  </tr>
                </thead>
                <tbody>
                  {state.accounts.map((acc) => {
                    const isArchived = !!acc.archived_at;
                    return (
                      <tr
                        key={acc.id}
                        className="border-t border-[var(--border)]"
                      >
                        <td className="px-4 py-2">
                          <span className={isArchived ? "opacity-60" : ""}>
                            {acc.name}
                          </span>
                        </td>
                        <td className="px-4 py-2">
                          {renderCategoryLabelFromAccount(acc, t)}
                        </td>
                        <td className="px-4 py-2 text-[var(--muted-foreground)]">
                          {acc.symbol ?? "—"}
                        </td>
                        <td className="px-4 py-2 text-[var(--muted-foreground)]">
                          {acc.currency}
                        </td>
                        <td className="px-4 py-2">
                          {isArchived ? (
                            <span className="text-xs px-2 py-0.5 rounded-full bg-[var(--muted)] text-[var(--muted-foreground)]">
                              {t("balance.account.status.archived")}
                            </span>
                          ) : (
                            <span className="text-xs px-2 py-0.5 rounded-full bg-[var(--positive)]/10 text-[var(--positive)]">
                              {t("balance.account.status.active")}
                            </span>
                          )}
                        </td>
                        <td className="px-4 py-2 text-right">
                          <div className="inline-flex items-center gap-1">
                            <button
                              type="button"
                              onClick={() => {
                                setEditingAccount(acc);
                                setShowAccountForm(true);
                              }}
                              className="p-1.5 rounded hover:bg-[var(--muted)] text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
                              title={t("common.edit")}
                            >
                              <Edit2 size={14} />
                            </button>
                            {isArchived ? (
                              <button
                                type="button"
                                onClick={() => unarchiveAccount(acc.id)}
                                className="p-1.5 rounded hover:bg-[var(--muted)] text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
                                title={t("balance.account.actions.unarchive")}
                              >
                                <ArchiveRestore size={14} />
                              </button>
                            ) : (
                              <button
                                type="button"
                                onClick={() => archiveAccount(acc.id)}
                                className="p-1.5 rounded hover:bg-[var(--muted)] text-[var(--muted-foreground)] hover:text-[var(--negative)]"
                                title={t("balance.account.actions.archive")}
                              >
                                <Trash2 size={14} />
                              </button>
                            )}
                          </div>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          )}
        </div>
      )}

      {activeTab === "categories" && (
        <div>
          <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 mb-4">
            <p className="text-sm text-[var(--muted-foreground)]">
              {t("balance.category.intro")}
            </p>
            <button
              type="button"
              onClick={() => setShowCategoryForm((prev) => !prev)}
              className="flex items-center gap-2 px-4 py-2 rounded-lg bg-[var(--primary)] text-white text-sm font-medium hover:opacity-90"
            >
              <Plus size={16} />
              {t("balance.category.actions.create")}
            </button>
          </div>

          {showCategoryForm && (
            <div className="bg-[var(--card)] rounded-xl border border-[var(--border)] p-4 mb-6">
              <h2 className="text-lg font-semibold mb-4">
                {t("balance.category.form.createTitle")}
              </h2>
              <AccountForm
                mode="category"
                isSaving={state.isSaving}
                onSubmit={handleCategorySubmit}
                onCancel={() => setShowCategoryForm(false)}
              />
            </div>
          )}

          {categoryDeleteError && (
            <div className="mb-4 p-3 rounded-lg bg-[var(--negative)]/10 text-[var(--negative)] text-sm border border-[var(--negative)]/20 flex items-start justify-between gap-2">
              <span>{categoryDeleteError}</span>
              <button
                type="button"
                onClick={() => setCategoryDeleteError(null)}
                className="text-xs underline shrink-0"
              >
                {t("common.dismiss", { defaultValue: "OK" })}
              </button>
            </div>
          )}

          <div className="bg-[var(--card)] rounded-xl border border-[var(--border)] overflow-hidden">
            <table className="w-full text-sm">
              <thead className="bg-[var(--muted)]">
                <tr>
                  <th className="text-left px-4 py-2 font-medium">
                    {t("balance.category.fields.name")}
                  </th>
                  <th className="text-left px-4 py-2 font-medium">
                    {t("balance.category.fields.key")}
                  </th>
                  <th className="text-left px-4 py-2 font-medium">
                    {t("balance.category.fields.kind")}
                  </th>
                  <th className="text-left px-4 py-2 font-medium">
                    {t("balance.category.fields.origin")}
                  </th>
                  <th className="text-right px-4 py-2 font-medium">
                    {t("balance.category.fields.actions")}
                  </th>
                </tr>
              </thead>
              <tbody>
                {state.categories.map((cat) => (
                  <tr key={cat.id} className="border-t border-[var(--border)]">
                    <td className="px-4 py-2">{renderCategoryLabel(cat)}</td>
                    <td className="px-4 py-2 text-[var(--muted-foreground)]">
                      <code className="text-xs">{cat.key}</code>
                    </td>
                    <td className="px-4 py-2">
                      <span className="text-xs px-2 py-0.5 rounded-full bg-[var(--muted)]">
                        {t(`balance.category.kind.${cat.kind}`)}
                      </span>
                    </td>
                    <td className="px-4 py-2">
                      {cat.is_seed ? (
                        <span className="text-xs text-[var(--muted-foreground)]">
                          {t("balance.category.origin.seeded")}
                        </span>
                      ) : (
                        <span className="text-xs text-[var(--muted-foreground)]">
                          {t("balance.category.origin.user")}
                        </span>
                      )}
                    </td>
                    <td className="px-4 py-2 text-right">
                      <div className="inline-flex items-center gap-1">
                        <button
                          type="button"
                          onClick={() => {
                            const next = window.prompt(
                              t("balance.category.actions.renamePrompt"),
                              renderCategoryLabel(cat)
                            );
                            // Write the human label to custom_label, never to
                            // i18n_key — preserves the bundled translation
                            // (fixes bug I). A blank/empty answer clears the
                            // override and falls back to t(i18n_key).
                            if (next !== null) {
                              editCategory(cat.id, {
                                custom_label: next.trim() || null,
                              });
                            }
                          }}
                          className="p-1.5 rounded hover:bg-[var(--muted)] text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
                          title={t("common.edit")}
                        >
                          <Edit2 size={14} />
                        </button>
                        {(() => {
                          const linkedCount =
                            accountsByCategory.get(cat.id)?.length ?? 0;
                          const blocked = cat.is_seed || linkedCount > 0;
                          const titleKey = cat.is_seed
                            ? t("balance.category.actions.deleteSeedHint")
                            : linkedCount > 0
                              ? t("balance.category.actions.deleteHasAccountsHint", {
                                  count: linkedCount,
                                })
                              : t("common.delete");
                          return (
                            <button
                              type="button"
                              onClick={() => handleDeleteCategory(cat)}
                              disabled={blocked}
                              title={titleKey}
                              className="p-1.5 rounded hover:bg-[var(--muted)] text-[var(--muted-foreground)] hover:text-[var(--negative)] disabled:opacity-30 disabled:cursor-not-allowed"
                            >
                              <Trash2 size={14} />
                            </button>
                          );
                        })()}
                      </div>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}
    </div>
  );
}
