// AccountForm — account or category variant.
//
// Mode = 'account' (Issue #138 / Bilan #1a): create / edit a balance_account
// row bound to an existing category.
// Mode = 'category' (Issue #140 / Bilan #2): create a balance_category row
// with a kind selector (`simple | priced`).
//
// Both variants live in the same component because they share the surrounding
// wiring (form layout, save / cancel buttons, validation feedback) and only
// the input fields differ.

import { FormEvent, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import type {
  BalanceAccount,
  BalanceAccountKind,
  BalanceAssetType,
  BalanceCategory,
  BalanceCategoryKind,
  BalanceVehicleType,
} from "../../shared/types";
import { BALANCE_VEHICLE_TYPES } from "../../shared/types";
import type {
  CreateBalanceAccountInput,
  CreateBalanceCategoryInput,
  UpdateBalanceAccountInput,
} from "../../services/balance.service";
import { renderCategoryLabelFromCategory } from "../../utils/renderCategoryLabel";

// -----------------------------------------------------------------------------
// Account variant types
// -----------------------------------------------------------------------------

export interface AccountFormValues {
  balance_category_id: number;
  name: string;
  symbol: string;
  notes: string;
  /** Fiscal envelope; "" means "no envelope" (→ null in the payload). */
  vehicle_type: BalanceVehicleType | "";
  /**
   * Entry mode (Issue #213). 'simple' = one scalar value; 'detailed' = a basket
   * of per-security holdings. Drives the symbol/price-fetch gating. For a NEW
   * account the category kind only *suggests* the default (priced → detailed);
   * the persisted mode is set on the account itself, and the detailed→simple
   * downgrade is forbidden once holdings exist (service backstop).
   */
  kind: BalanceAccountKind;
}

/** Map a category's kind to the suggested default account entry mode (#213). */
function defaultKindForCategory(
  category: BalanceCategory | undefined
): BalanceAccountKind {
  return category?.kind === "priced" ? "detailed" : "simple";
}

interface AccountVariantProps {
  mode: "account";
  /** When provided, the form is in edit mode; otherwise creation. */
  initialAccount?: BalanceAccount | null;
  categories: BalanceCategory[];
  isSaving: boolean;
  onSubmit: (
    values: CreateBalanceAccountInput | UpdateBalanceAccountInput
  ) => Promise<void> | void;
  onCancel: () => void;
}

// -----------------------------------------------------------------------------
// Category variant types (Issue #140)
// -----------------------------------------------------------------------------

export interface CategoryFormValues {
  key: string;
  /**
   * User-facing label (Issue #203). Written to `custom_label`, never to
   * `i18n_key` — consistent with the rename flow and the bug-I fix. The
   * service derives `i18n_key` from the key for user-created categories.
   */
  custom_label: string;
  kind: BalanceCategoryKind;
  /** Required when kind === 'priced' (Issue #169). NULL otherwise. */
  asset_type: BalanceAssetType | null;
}

interface CategoryVariantProps {
  mode: "category";
  isSaving: boolean;
  onSubmit: (values: CreateBalanceCategoryInput) => Promise<void> | void;
  onCancel: () => void;
}

type Props = AccountVariantProps | CategoryVariantProps;

function defaultAccountValues(
  initial: BalanceAccount | null | undefined,
  categories: BalanceCategory[]
): AccountFormValues {
  if (initial) {
    return {
      balance_category_id: initial.balance_category_id,
      name: initial.name,
      symbol: initial.symbol ?? "",
      notes: initial.notes ?? "",
      vehicle_type: initial.vehicle_type ?? "",
      // Editing: the account's stored entry mode is authoritative.
      kind: initial.kind,
    };
  }
  // First active category as a sane default
  const first = categories.find((c) => c.is_active) ?? categories[0];
  return {
    balance_category_id: first?.id ?? 0,
    name: "",
    symbol: "",
    notes: "",
    vehicle_type: "",
    // New account: suggest the category-mapped default entry mode.
    kind: defaultKindForCategory(first),
  };
}

export default function AccountForm(props: Props) {
  if (props.mode === "category") {
    return <CategoryVariant {...props} />;
  }
  return <AccountVariant {...props} />;
}

// -----------------------------------------------------------------------------
// Account variant
// -----------------------------------------------------------------------------

function AccountVariant({
  initialAccount,
  categories,
  isSaving,
  onSubmit,
  onCancel,
}: AccountVariantProps) {
  const { t } = useTranslation();
  const [values, setValues] = useState<AccountFormValues>(() =>
    defaultAccountValues(initialAccount, categories)
  );
  const [touched, setTouched] = useState(false);

  // Reset form when target account changes (edit different row).
  useEffect(() => {
    setValues(defaultAccountValues(initialAccount, categories));
    setTouched(false);
  }, [initialAccount, categories]);

  const isEditing = !!initialAccount;
  // Symbol / price-fetch gating now keys on the ACCOUNT's entry mode (#213),
  // not the category kind. `category.kind` only seeds the default below.
  const isDetailed = values.kind === "detailed";
  const trimmedName = values.name.trim();
  const trimmedSymbol = values.symbol.trim();
  const nameInvalid = touched && trimmedName.length === 0;
  // Symbol is optional even for priced categories (Issue #199). It only
  // gates the price-fetch button — manual valuation (quantity × unit price)
  // never needs it. So no symbol-required validation here.

  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault();
    setTouched(true);
    if (!trimmedName) return;

    // "" in the select means "no envelope" → null on the wire.
    const vehicleType: BalanceVehicleType | null =
      values.vehicle_type === "" ? null : values.vehicle_type;

    const payload: CreateBalanceAccountInput = {
      balance_category_id: values.balance_category_id,
      name: trimmedName,
      symbol: trimmedSymbol || null,
      notes: values.notes.trim() || null,
      vehicle_type: vehicleType,
    };

    if (isEditing) {
      const updatePayload: UpdateBalanceAccountInput = {
        balance_category_id: payload.balance_category_id,
        name: payload.name,
        symbol: payload.symbol,
        notes: payload.notes,
        vehicle_type: vehicleType,
      };
      // Forward the entry mode only when it actually changed (avoids a no-op
      // downgrade attempt; the detailed → simple direction is service-guarded
      // and the selector is locked for detailed accounts anyway). A simple →
      // detailed upgrade here flags the account for per-title entry; the pivot
      // date wizard (#215) will own setting `detailed_since`.
      if (initialAccount && values.kind !== initialAccount.kind) {
        updatePayload.kind = values.kind;
      }
      await onSubmit(updatePayload);
    } else {
      // NEW accounts persist as the DB default ('simple') —
      // `CreateBalanceAccountInput` carries no `kind`. Converting a fresh
      // account to detailed happens via the dedicated flow (#215); the
      // selector above only previews the suggested mode + gating.
      await onSubmit(payload);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="flex flex-col gap-4">
      <div>
        <label className="block text-sm font-medium mb-1" htmlFor="account-category">
          {t("balance.account.form.category")}
        </label>
        <select
          id="account-category"
          value={values.balance_category_id}
          onChange={(e) => {
            const nextId = Number(e.target.value);
            const nextCat = categories.find((c) => c.id === nextId);
            setValues((prev) => ({
              ...prev,
              balance_category_id: nextId,
              // For a NEW account, re-suggest the entry mode from the chosen
              // category. When editing, the stored kind stays put.
              kind: isEditing ? prev.kind : defaultKindForCategory(nextCat),
            }));
          }}
          className="w-full px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--card)] text-sm focus:outline-none focus:ring-1 focus:ring-[var(--primary)]"
        >
          {categories.length === 0 ? (
            <option value={0}>{t("balance.account.form.noCategory")}</option>
          ) : (
            categories.map((cat) => (
              <option key={cat.id} value={cat.id}>
                {renderCategoryLabelFromCategory(cat, t)}
              </option>
            ))
          )}
        </select>
      </div>

      <div>
        <label className="block text-sm font-medium mb-1" htmlFor="account-name">
          {t("balance.account.form.name")}
        </label>
        <input
          id="account-name"
          type="text"
          value={values.name}
          onChange={(e) => setValues({ ...values, name: e.target.value })}
          onBlur={() => setTouched(true)}
          className={`w-full px-3 py-2 rounded-lg border bg-[var(--card)] text-sm focus:outline-none focus:ring-1 focus:ring-[var(--primary)] ${
            nameInvalid
              ? "border-[var(--negative)]"
              : "border-[var(--border)]"
          }`}
          autoFocus
          autoComplete="off"
        />
        {nameInvalid && (
          <p className="mt-1 text-xs text-[var(--negative)]">
            {t("balance.account.form.nameRequired")}
          </p>
        )}
      </div>

      <div>
        <label className="block text-sm font-medium mb-1" htmlFor="account-symbol">
          {t("balance.account.form.symbol")}
          {isDetailed && (
            <span className="ml-1 text-xs text-[var(--muted-foreground)]">
              ({t("balance.account.form.symbolPricedHint")})
            </span>
          )}
        </label>
        <input
          id="account-symbol"
          type="text"
          value={values.symbol}
          onChange={(e) => setValues({ ...values, symbol: e.target.value })}
          onBlur={() => setTouched(true)}
          placeholder={
            isDetailed
              ? t("balance.account.form.symbolPlaceholderPriced")
              : t("balance.account.form.symbolPlaceholderSimple")
          }
          className="w-full px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--card)] text-sm focus:outline-none focus:ring-1 focus:ring-[var(--primary)]"
          autoComplete="off"
        />
      </div>

      <div>
        <label
          className="block text-sm font-medium mb-1"
          htmlFor="account-kind"
        >
          {t("balance.account.form.kind.label")}
        </label>
        <select
          id="account-kind"
          value={values.kind}
          // Downgrading detailed → simple is forbidden once holdings exist
          // (service backstop). The form can't see holdings, so editing a
          // detailed account locks the selector; conversion lives in its own
          // flow (#215). A new account can pick either mode.
          disabled={isEditing && initialAccount?.kind === "detailed"}
          onChange={(e) =>
            setValues({
              ...values,
              kind: e.target.value as BalanceAccountKind,
            })
          }
          className="w-full px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--card)] text-sm focus:outline-none focus:ring-1 focus:ring-[var(--primary)] disabled:opacity-60"
        >
          <option value="simple">{t("balance.account.form.kind.simple")}</option>
          <option value="detailed">
            {t("balance.account.form.kind.detailed")}
          </option>
        </select>
        <p className="mt-1 text-xs text-[var(--muted-foreground)]">
          {t("balance.account.form.kind.hint")}
          {!isEditing && values.kind === "detailed" && (
            <>
              {" "}
              {t("balance.account.form.kind.detailedCreateHint")}
            </>
          )}
        </p>
      </div>

      <div>
        <label className="block text-sm font-medium mb-1" htmlFor="account-notes">
          {t("balance.account.form.notes")}
        </label>
        <textarea
          id="account-notes"
          value={values.notes}
          onChange={(e) => setValues({ ...values, notes: e.target.value })}
          rows={2}
          className="w-full px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--card)] text-sm focus:outline-none focus:ring-1 focus:ring-[var(--primary)] resize-none"
        />
      </div>

      <div>
        <label
          className="block text-sm font-medium mb-1"
          htmlFor="account-vehicle-type"
        >
          {t("balance.account.form.vehicleType.label")}
        </label>
        <select
          id="account-vehicle-type"
          value={values.vehicle_type}
          onChange={(e) =>
            setValues({
              ...values,
              vehicle_type: e.target.value as BalanceVehicleType | "",
            })
          }
          className="w-full px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--card)] text-sm focus:outline-none focus:ring-1 focus:ring-[var(--primary)]"
        >
          <option value="">{t("balance.account.form.vehicleType.none")}</option>
          {BALANCE_VEHICLE_TYPES.map((vt) => (
            <option key={vt} value={vt}>
              {t(`balance.account.form.vehicleType.${vt}`)}
            </option>
          ))}
        </select>
        <p className="mt-1 text-xs text-[var(--muted-foreground)]">
          {t("balance.account.form.vehicleType.hint")}
        </p>
      </div>

      <p className="text-xs text-[var(--muted-foreground)]">
        {t("balance.account.form.currencyMvpNotice")}
      </p>

      <div className="flex justify-end gap-2">
        <button
          type="button"
          onClick={onCancel}
          disabled={isSaving}
          className="px-4 py-2 rounded-lg border border-[var(--border)] text-sm hover:bg-[var(--muted)] disabled:opacity-50"
        >
          {t("common.cancel")}
        </button>
        <button
          type="submit"
          disabled={isSaving || !trimmedName || categories.length === 0}
          className="px-4 py-2 rounded-lg bg-[var(--primary)] text-white text-sm font-medium hover:opacity-90 disabled:opacity-50"
        >
          {isEditing
            ? t("balance.account.form.save")
            : t("balance.account.form.create")}
        </button>
      </div>
    </form>
  );
}

// -----------------------------------------------------------------------------
// Category variant (Issue #140)
// -----------------------------------------------------------------------------

function CategoryVariant({
  isSaving,
  onSubmit,
  onCancel,
}: CategoryVariantProps) {
  const { t } = useTranslation();
  const [values, setValues] = useState<CategoryFormValues>({
    key: "",
    custom_label: "",
    kind: "simple",
    asset_type: null,
  });
  const [touched, setTouched] = useState(false);

  const trimmedKey = values.key.trim();
  const trimmedLabel = values.custom_label.trim();
  const keyInvalid = touched && trimmedKey.length === 0;
  const assetTypeMissing =
    touched && values.kind === "priced" && !values.asset_type;
  const submitDisabled =
    isSaving ||
    !trimmedKey ||
    (values.kind === "priced" && !values.asset_type);

  const handleKindChange = (next: BalanceCategoryKind) => {
    // Switching priced → simple resets asset_type so the NULL invariant for
    // simple kind is preserved (the service would coerce it anyway).
    setValues((prev) => ({
      ...prev,
      kind: next,
      asset_type: next === "priced" ? prev.asset_type : null,
    }));
  };

  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault();
    setTouched(true);
    if (!trimmedKey) return;
    if (values.kind === "priced" && !values.asset_type) return;
    // User-created categories have no bundled translation: anchor `i18n_key`
    // on the key (stable lookup, no free text) and carry the human label in
    // `custom_label` — same mechanism as renaming (Issue #203 / bug I).
    await onSubmit({
      key: trimmedKey,
      i18n_key: `balance.category.${trimmedKey}`,
      kind: values.kind,
      sort_order: 100, // user-created categories sort after seeded ones
      asset_type: values.kind === "priced" ? values.asset_type : null,
      custom_label: trimmedLabel || null,
    });
  };

  return (
    <form onSubmit={handleSubmit} className="flex flex-col gap-4">
      <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
        <div>
          <label
            className="block text-sm font-medium mb-1"
            htmlFor="category-key"
          >
            {t("balance.category.form.key")}
          </label>
          <input
            id="category-key"
            type="text"
            value={values.key}
            onChange={(e) =>
              setValues({ ...values, key: e.target.value })
            }
            onBlur={() => setTouched(true)}
            placeholder={t("balance.category.form.keyPlaceholder")}
            className={`w-full px-3 py-2 rounded-lg border bg-[var(--card)] text-sm focus:outline-none focus:ring-1 focus:ring-[var(--primary)] ${
              keyInvalid
                ? "border-[var(--negative)]"
                : "border-[var(--border)]"
            }`}
            autoComplete="off"
            autoFocus
          />
          {keyInvalid && (
            <p className="mt-1 text-xs text-[var(--negative)]">
              {t("balance.account.form.nameRequired")}
            </p>
          )}
        </div>
        <div>
          <label
            className="block text-sm font-medium mb-1"
            htmlFor="category-custom-label"
          >
            {t("balance.category.form.customLabel")}
          </label>
          <input
            id="category-custom-label"
            type="text"
            value={values.custom_label}
            onChange={(e) =>
              setValues({ ...values, custom_label: e.target.value })
            }
            placeholder={t("balance.category.form.customLabelPlaceholder")}
            className="w-full px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--card)] text-sm focus:outline-none focus:ring-1 focus:ring-[var(--primary)]"
            autoComplete="off"
          />
          <p className="mt-1 text-xs text-[var(--muted-foreground)]">
            {t("balance.category.form.customLabelHint")}
          </p>
        </div>
      </div>

      <div>
        <label
          className="block text-sm font-medium mb-1"
          htmlFor="category-kind"
        >
          {t("balance.category.form.kindLabel")}
        </label>
        <select
          id="category-kind"
          value={values.kind}
          onChange={(e) =>
            handleKindChange(e.target.value as BalanceCategoryKind)
          }
          className="w-full px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--card)] text-sm focus:outline-none focus:ring-1 focus:ring-[var(--primary)]"
        >
          <option value="simple">{t("balance.category.kind.simple")}</option>
          <option value="priced">{t("balance.category.kind.priced")}</option>
        </select>
        <p className="mt-1 text-xs text-[var(--muted-foreground)]">
          {values.kind === "priced"
            ? t("balance.category.form.kindHintPriced")
            : t("balance.category.form.kindHintSimple")}
        </p>
      </div>

      {values.kind === "priced" && (
        <div>
          <label
            className="block text-sm font-medium mb-1"
            htmlFor="category-asset-type"
          >
            {t("balance.category.assetType.label")}
          </label>
          <select
            id="category-asset-type"
            value={values.asset_type ?? ""}
            onChange={(e) =>
              setValues({
                ...values,
                asset_type:
                  e.target.value === ""
                    ? null
                    : (e.target.value as BalanceAssetType),
              })
            }
            onBlur={() => setTouched(true)}
            className={`w-full px-3 py-2 rounded-lg border bg-[var(--card)] text-sm focus:outline-none focus:ring-1 focus:ring-[var(--primary)] ${
              assetTypeMissing
                ? "border-[var(--negative)]"
                : "border-[var(--border)]"
            }`}
          >
            <option value="">{t("balance.category.assetType.required")}</option>
            <option value="stock">
              {t("balance.category.assetType.stock")}
            </option>
            <option value="crypto">
              {t("balance.category.assetType.crypto")}
            </option>
          </select>
          {assetTypeMissing && (
            <p className="mt-1 text-xs text-[var(--negative)]">
              {t("balance.category.assetType.required")}
            </p>
          )}
        </div>
      )}

      <div className="flex justify-end gap-2">
        <button
          type="button"
          onClick={onCancel}
          disabled={isSaving}
          className="px-4 py-2 rounded-lg border border-[var(--border)] text-sm hover:bg-[var(--muted)] disabled:opacity-50"
        >
          {t("common.cancel")}
        </button>
        <button
          type="submit"
          disabled={submitDisabled}
          className="px-4 py-2 rounded-lg bg-[var(--primary)] text-white text-sm font-medium hover:opacity-90 disabled:opacity-50"
        >
          {t("balance.category.form.create")}
        </button>
      </div>
    </form>
  );
}
