// SnapshotLineRow — single account line inside the snapshot editor.
//
// Two variants are dispatched by `account.category_kind`:
//
//  - `simple`  (Issue #146): a single value input keyed by `account_id`.
//  - `priced`  (Issue #140): three inputs — `quantity`, `unit_price` (both
//                            required), and a read-only `value` field that
//                            renders `quantity * unit_price` live as the
//                            user types. An attribution tag `[Manuel]`
//                            appears next to the row; the `[via Maximus]`
//                            tag is rendered by PriceFetchControl (Issue #158).
//
// We keep this component dumb on purpose: it receives strings from the
// parent (the editor stores raw strings to preserve partial input) and
// emits new strings on every change. Numeric validation happens at save
// time in `useSnapshotEditor.save` against the service's
// `validateLineKindInvariants` helper.

import { ChangeEvent, useMemo } from "react";
import { useTranslation } from "react-i18next";
import type { BalanceAccountWithCategory } from "../../shared/types";
import PriceFetchControl from "./PriceFetchControl";

interface BaseProps {
  account: BalanceAccountWithCategory;
  disabled?: boolean;
  /** Snapshot date (YYYY-MM-DD) — passed through to PriceFetchControl. */
  snapshotDate?: string;
}

interface SimpleProps extends BaseProps {
  value: string;
  onChange: (next: string) => void;
  /** Optional priced handlers for callers that wire both at once. */
  quantityValue?: string;
  unitPriceValue?: string;
  onQuantityChange?: (next: string) => void;
  onUnitPriceChange?: (next: string) => void;
}

type Props = SimpleProps;

/**
 * Parse a string like "12.34" or "12,34" into a finite number, or null
 * if invalid / empty. Used by the priced variant to compute the live
 * `value` preview.
 */
function parseDecimal(raw: string): number | null {
  if (!raw) return null;
  const trimmed = String(raw).trim().replace(",", ".");
  if (!trimmed) return null;
  const n = Number(trimmed);
  return Number.isFinite(n) ? n : null;
}

export default function SnapshotLineRow({
  account,
  value,
  onChange,
  disabled,
  quantityValue,
  unitPriceValue,
  onQuantityChange,
  onUnitPriceChange,
  snapshotDate,
}: Props) {
  const { t } = useTranslation();
  const isPriced = account.category_kind === "priced";

  // Compute the live value preview for priced rows. Returns null when
  // either input cannot yet be parsed (so we display a placeholder).
  const computedPricedValue = useMemo(() => {
    if (!isPriced) return null;
    const qty = parseDecimal(quantityValue ?? "");
    const price = parseDecimal(unitPriceValue ?? "");
    if (qty === null || price === null) return null;
    return qty * price;
  }, [isPriced, quantityValue, unitPriceValue]);

  if (isPriced) {
    const handleQty = (e: ChangeEvent<HTMLInputElement>) =>
      onQuantityChange?.(e.target.value);
    const handlePrice = (e: ChangeEvent<HTMLInputElement>) =>
      onUnitPriceChange?.(e.target.value);

    return (
      <div className="flex flex-col sm:flex-row sm:items-center gap-3 py-2 border-b border-[var(--border)] last:border-b-0">
        <div className="flex-1 min-w-0">
          <div className="flex items-center gap-2">
            <span className="text-sm font-medium truncate">{account.name}</span>
            <span
              className="text-[10px] uppercase tracking-wide px-1.5 py-0.5 rounded bg-[var(--muted)] text-[var(--muted-foreground)]"
              title={t("balance.snapshot.priced.attributionManualHint")}
            >
              {t("balance.snapshot.priced.attributionManual")}
            </span>
          </div>
          {account.symbol && (
            <div className="text-xs text-[var(--muted-foreground)]">
              {account.symbol}
            </div>
          )}
        </div>
        <div className="flex flex-wrap items-center gap-2">
          <div className="flex flex-col gap-0.5">
            <input
              type="text"
              inputMode="decimal"
              value={quantityValue ?? ""}
              onChange={handleQty}
              disabled={disabled}
              placeholder={t("balance.snapshot.priced.quantityPlaceholder")}
              className="w-24 px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--card)] text-sm text-right focus:outline-none focus:ring-1 focus:ring-[var(--primary)] disabled:opacity-50"
              aria-label={t("balance.snapshot.priced.quantityLabel", {
                account: account.name,
              })}
            />
            <span className="text-[10px] text-[var(--muted-foreground)] text-right">
              {t("balance.snapshot.priced.quantity")}
            </span>
          </div>
          <span className="text-sm text-[var(--muted-foreground)] hidden sm:inline">
            ×
          </span>
          <div className="flex flex-col gap-0.5">
            <input
              type="text"
              inputMode="decimal"
              value={unitPriceValue ?? ""}
              onChange={handlePrice}
              disabled={disabled}
              placeholder={t("balance.snapshot.priced.unitPricePlaceholder")}
              className="w-28 px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--card)] text-sm text-right focus:outline-none focus:ring-1 focus:ring-[var(--primary)] disabled:opacity-50"
              aria-label={t("balance.snapshot.priced.unitPriceLabel", {
                account: account.name,
              })}
            />
            <span className="text-[10px] text-[var(--muted-foreground)] text-right">
              {t("balance.snapshot.priced.unitPrice")}
            </span>
          </div>
          <span className="text-sm text-[var(--muted-foreground)] hidden sm:inline">
            =
          </span>
          <div className="flex flex-col gap-0.5">
            <input
              type="text"
              value={
                computedPricedValue === null
                  ? ""
                  : computedPricedValue.toFixed(2)
              }
              readOnly
              disabled
              placeholder={t("balance.snapshot.priced.computedValuePlaceholder")}
              className="w-32 px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--muted)]/40 text-sm text-right text-[var(--muted-foreground)] focus:outline-none cursor-not-allowed"
              aria-label={t("balance.snapshot.priced.computedValueLabel", {
                account: account.name,
              })}
              aria-readonly="true"
            />
            <span className="text-[10px] text-[var(--muted-foreground)] text-right">
              {t("balance.snapshot.priced.computedValue")}
            </span>
          </div>
          <span className="text-xs text-[var(--muted-foreground)] w-10">
            {account.currency}
          </span>
          {/* PriceFetchControl — wired next to the unit_price input (Issue #158).
              onPriceFetched updates unit_price only; quantity stays as-is.
              TODO: asset_type from category schema (see decisions-log.md MEDIUM) */}
          {account.symbol && (
            <PriceFetchControl
              symbol={account.symbol}
              date={snapshotDate ?? ""}
              categoryKind={account.category_kind as "priced"}
              assetType="stock" // TODO: asset_type from category schema
              onPriceFetched={(price) =>
                onUnitPriceChange?.(String(price))
              }
            />
          )}
        </div>
      </div>
    );
  }

  // Simple variant — unchanged from #146.
  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    onChange(e.target.value);
  };

  return (
    <div className="flex items-center gap-3 py-2 border-b border-[var(--border)] last:border-b-0">
      <div className="flex-1 min-w-0">
        <div className="text-sm font-medium truncate">{account.name}</div>
        {account.symbol && (
          <div className="text-xs text-[var(--muted-foreground)]">
            {account.symbol}
          </div>
        )}
      </div>
      <div className="flex items-center gap-2">
        <input
          type="text"
          inputMode="decimal"
          value={value}
          onChange={handleChange}
          disabled={disabled}
          placeholder={t("balance.snapshot.line.valuePlaceholder")}
          className="w-32 px-3 py-2 rounded-lg border border-[var(--border)] bg-[var(--card)] text-sm text-right focus:outline-none focus:ring-1 focus:ring-[var(--primary)] disabled:opacity-50"
          aria-label={t("balance.snapshot.line.valueLabel", {
            account: account.name,
          })}
        />
        <span className="text-xs text-[var(--muted-foreground)] w-10">
          {account.currency}
        </span>
      </div>
    </div>
  );
}
