"use client";

import { useState } from "react";
import { Trash2 } from "lucide-react";
import { AlertTriangle } from "lucide-react";
import { FieldLabel, MoneyField, NumberField, SelectField, TextField } from "@/components/FormField";
import { formatChf } from "@/lib/format";
import { api } from "@/lib/api-client";
import {
  buildRateWrites,
  changedRateFields,
  scopeQuestion,
  SCOPE_OPTIONS,
  type PhaseRef,
  type RateScope,
} from "@/lib/ratefields";
import { ahvAnnualPension, ahvMdje, type AhvCareer } from "@/lib/calculations";
import { CATEGORY_LABELS, num } from "@/lib/elements";
import {
  DEFAULT_CAPITAL_TAX_RATE,
  DEFAULT_PK_CONVERSION_RATE,
  DEFAULT_PROPERTY_GAINS_TAX_RATE,
  PILLAR_3A_MAX_ANNUAL,
} from "@/lib/constants";
import type {
  CashTransitionData,
  CashTransitionMode,
  ElementCategory,
  PhaseData,
  TransitionData,
} from "@/lib/elements";

export interface CellContext {
  kind: "phase" | "transition";
  phaseId: string; // bei transition: die fromPhaseId
  ownerWorking: boolean;
  isConsumption: boolean;
  durationYears: number;
  isRetirementTransition: boolean;
  carriedEndValue: number; // Endwert des Elements in der (Vor-)Phase, für Bezugs-Maxima
  carried: boolean; // Phase >= 2: Basiswert wird aus der Vorphase fortgeschrieben
  derivedStart: number; // fortgeschriebener Basiswert (read-only Anzeige)
  derivedMortgage: number; // nur Immobilie: fortgeschriebene Resthypothek zu Phasenbeginn
  mortgageEnd: number; // nur Immobilie: Resthypothek am Phasenende (für die Sonderamortisation)
  // nur Immobilie: modellierter VERKEHRSWERT am Phasenende (Eigenkapital + Resthypothek),
  // inkl. aufgelaufener Wertsteigerung. Vorbelegung und Vergleichswert für den Verkaufspreis.
  propertyValueEnd: number;
  deflatorStart: number; // Kaufkraft-Deflator zu Phasenbeginn (real <-> nominal, erstes Jahr)
  // Warnhinweis: Anzahl Phasen NACH dieser (Änderungen schreiben sich dorthin fort).
  laterPhaseCount: number;
  // AHV-Beitragskarriere des Element-Besitzers (für die Prüfung am Pensions-Übergang).
  ahvCareer: AhvCareer | null;
}

interface Props {
  element: { id: string; category: ElementCategory; name: string; ownerRole: string | null };
  context: CellContext;
  phaseData: PhaseData;
  transitionData: TransitionData;
  // Alle Phasen des Szenarios und die dort bereits erfassten Werte -- Grundlage für die
  // Übernahme einer geänderten Rate auf weitere Phasen (siehe SPEZIFIKATION 3.6.11).
  allPhases?: PhaseRef[];
  phaseDataByPhase?: Record<string, PhaseData>;
  onSaved: () => void;
  onDeleteElement: () => void;
}

// Warnhinweis beim Bearbeiten einer Phase, der noch Phasen folgen. Seit V3 werden Werte live
// fortgeschrieben (Endwert = Startwert der Folgephase) -- eine Änderung hier wirkt also bis
// ans Planende durch, was ohne Hinweis leicht übersehen wird.
export function CarryWarning({ laterPhaseCount }: { laterPhaseCount: number }) {
  if (laterPhaseCount <= 0) return null;
  const phasen = laterPhaseCount === 1 ? "die nachfolgende Lebensphase" : `die ${laterPhaseCount} nachfolgenden Lebensphasen`;
  return (
    <div className="col-span-full flex items-start gap-2 rounded-lg border border-danger bg-danger-soft px-3 py-2 text-xs text-danger">
      <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0" />
      <span>
        <strong>Achtung: Diese Lebensphase ist nicht die letzte.</strong> Werte werden fortgeschrieben
        (Endwert = Startwert der Folgephase). Eine Änderung hier wirkt sich auf {phasen} aus und
        verändert deren Startwerte, Kennzahlen sowie Endvermögen, Cash-Verlauf und Ruinalter.
      </span>
    </div>
  );
}

// Read-only Anzeige eines abgeleiteten (fortgeschriebenen) Wertes.
function DerivedField({ label, value, help }: { label: string; value: number; help?: string }) {
  return (
    <div>
      <FieldLabel label={label} help={help} />
      <div className="w-full rounded-lg border border-dashed border-border bg-surface-2 px-2.5 py-1.5 text-sm text-muted">
        {formatChf(value)}
      </div>
    </div>
  );
}

// PK/3a-Bezugs-Entscheid im normalen Übergang (Vorbezug): Kein Bezug / Bezug (+ Betrag +
// Kapitalbezugssteuer). Der Bezugsbetrag wird brutto dem Kapital entnommen; ins Cash fliesst
// der Betrag nach Abzug der Steuer.
function WithdrawalDecision({
  td,
  setT,
  max,
  label,
}: {
  td: TransitionData;
  setT: (patch: Partial<TransitionData>) => void;
  max: number;
  label: string;
}) {
  const mode = td.withdrawalMode ?? "NONE";
  const gross = num(td.withdrawal);
  const taxRate = num(td.capitalTaxRate, DEFAULT_CAPITAL_TAX_RATE);
  return (
    <>
      <SelectField
        label="Bezug?"
        value={mode}
        onChange={(v: "NONE" | "AMOUNT") => setT(v === "NONE" ? { withdrawalMode: v, withdrawal: 0 } : { withdrawalMode: v })}
        options={[
          { value: "NONE", label: "Kein Bezug" },
          { value: "AMOUNT", label: "Bezug" },
        ]}
      />
      {mode === "AMOUNT" && (
        <>
          <MoneyField
            label={label}
            help={`Bruttobetrag, dem Kapital entnommen. Maximal ${formatChf(max)} (Endwert der Vorphase).`}
            value={gross}
            max={max}
            onChange={(v) => setT({ withdrawal: v })}
          />
          <NumberField
            label="Kapitalbezugssteuer (%)"
            help="Ein Vorbezug ist wie der Bezug bei Pensionierung kapitalbezugssteuerpflichtig."
            step={0.5}
            value={taxRate}
            onChange={(v) => setT({ capitalTaxRate: v })}
          />
          <DerivedField
            label="Auszahlung netto (ins Cash)"
            value={Math.round(gross * (1 - taxRate / 100))}
            help="Bruttobezug abzüglich Kapitalbezugssteuer. Wird automatisch berechnet."
          />
        </>
      )}
    </>
  );
}

// Vorbelegung expliziter Entscheide, damit ein blosses "Speichern" den sichtbaren Default
// (Halten / Kein Bezug / Rente) auch tatsächlich persistiert.
// AHV-Prüfung am Pensions-Übergang: geplantes Durchschnittseinkommen aus dem Plan plus --
// nur falls der Plan nicht bis zum Beitragsbeginn (Alter 21) zurückreicht -- die Jahre davor.
export function AhvReviewFields({
  career,
  td,
  setT,
}: {
  career: AhvCareer;
  td: TransitionData;
  setT: (patch: Partial<TransitionData>) => void;
}) {
  const brauchtVorgeschichte = career.yearsBeforePlan > 0;
  // Vorbelegung mit dem geplanten Durchschnitt: besser als 0, wenn der Nutzer nichts weiss.
  const avgBefore =
    typeof td.avgIncomeBefore === "number" ? td.avgIncomeBefore : Math.round(career.plannedAvgGrossIncome);
  const gapBefore = Math.max(0, Math.round(num(td.gapYearsBefore)));
  const mdJE = ahvMdje(career, brauchtVorgeschichte ? avgBefore : 0, gapBefore);
  const rente = ahvAnnualPension(mdJE, career.gapYearsInPlan + gapBefore);

  return (
    <>
      <p className="col-span-full rounded-lg bg-surface-2 px-3 py-2 text-xs text-muted">
        Die AHV-Rente hängt vom <strong className="text-fg">massgebenden durchschnittlichen Jahreseinkommen</strong>{" "}
        über die ganze Beitragsdauer (ab Alter 21) ab. Massgebend ist der <strong className="text-fg">Bruttolohn</strong>;
        das Tool rechnet die im Plan erfassten Nettöinkommen dafür automatisch hoch. Alle Beträge sind
        REAL (heutige Kaufkraft) – die AHV wertet vergangene Einkommen auf und indexiert die Schwellen,
        was sich real weitgehend aufhebt.
      </p>

      <DerivedField
        label="Geplantes Bruttöinkommen (aus dem Plan)"
        value={Math.round(career.plannedAvgGrossIncome)}
        help={`Reales Mittel über ${career.planYears} Beitragsjahre der Erwerbsphasen dieses Plans, hochgerechnet vom Netto- auf den Bruttolohn. Nur Einkommen, die dieser Person zugeordnet sind.`}
      />
      <DerivedField
        label="Beitragsjahre im Plan"
        value={career.planYears}
        help="Dauer der Erwerbsphasen abzüglich der dort erfassten Ausfalljahre."
      />

      {brauchtVorgeschichte && (
        <>
          <p className="col-span-full rounded-lg border border-dashed border-border px-3 py-2 text-xs text-muted">
            Der Plan beginnt erst im Alter {career.yearsBeforePlan + 21}. Die {career.yearsBeforePlan} Beitragsjahre
            davor kennt das Tool nicht – bitte ergänzen.
          </p>
          <MoneyField
            label="Durchschnittliches Bruttöinkommen vor Planbeginn (real)"
            help="BRUTTO und in HEUTIGER Kaufkraft. Am besten aus der AHV-Rentenvorausberechnung übernehmen – dort ist die Aufwertung bereits enthalten. Die Rohbeträge im Kontoauszug sind historisch-nominal und daher zu tief."
            value={avgBefore}
            onChange={(v) => setT({ avgIncomeBefore: v })}
          />
          <NumberField
            label="Ausfalljahre vor Planbeginn"
            help="Jahre ohne AHV-Beiträge zwischen Alter 21 und Planbeginn (z. B. Ausland, Studium). Jedes kürzt die Rente um 1/44."
            value={gapBefore}
            min={0}
            max={career.yearsBeforePlan}
            onChange={(v) => setT({ gapYearsBefore: Math.max(0, Math.min(career.yearsBeforePlan, Math.round(v))) })}
          />
        </>
      )}

      <DerivedField
        label="Massgebendes durchschnittliches Jahreseinkommen"
        value={Math.round(mdJE)}
        help="Gewichtetes Mittel über alle Beitragsjahre (vor Planbeginn und im Plan). Ab 90'720 gibt es die Maximalrente."
      />
      <DerivedField
        label="Resultierende AHV-Rente pro Jahr"
        value={rente}
        help="Vollrente zum mdJE (Skala 44), inkl. 13. Altersrente, gekürzt um die Ausfalljahre. Bei Ehepaaren zusätzlich plafoniert."
      />
    </>
  );
}

export function withTransitionDefaults(category: ElementCategory, isRetirement: boolean, td: TransitionData): TransitionData {
  const out = { ...td };
  if (category === "AHV") {
    // Ein Speichern der Prüfung markiert sie als erledigt (gleiches Muster wie bei PK/3a).
    if (isRetirement && out.reviewed === undefined) out.reviewed = true;
  } else if (category === "REAL_ESTATE" || category === "OTHER_ASSET") {
    if (out.decision === undefined) out.decision = "HOLD";
  } else if (category === "PENSION_FUND") {
    if (isRetirement) {
      if (out.payoutMode === undefined) out.payoutMode = "PENSION";
    } else if (out.withdrawalMode === undefined) {
      out.withdrawalMode = "NONE";
    }
  } else if (category === "PILLAR_3A") {
    if (!isRetirement && out.withdrawalMode === undefined) out.withdrawalMode = "NONE";
  }
  return out;
}

// --- Cash-Übergang: einmalige Sonderein-/ausgaben ---

export function withCashTransitionDefaults(ct: CashTransitionData): CashTransitionData {
  return ct.mode === undefined ? { ...ct, mode: "NONE" } : { ...ct };
}

export function isCashTransitionAnswered(ct: CashTransitionData): boolean {
  return ct.mode !== undefined;
}

// Kurzfassung für die Übergangszelle der Cash-Zeile.
export function cashTransitionSummary(ct: CashTransitionData): string {
  const mode = ct.mode;
  if (mode === undefined) return "?";
  const inn = `+${formatChf(num(ct.inflowAmount))}`;
  const out = `−${formatChf(num(ct.outflowAmount))}`;
  switch (mode) {
    case "INFLOW":
      return inn;
    case "OUTFLOW":
      return out;
    case "BOTH":
      return `${inn} / ${out}`;
    default:
      return "1:1";
  }
}

// Eingabefelder für den Cash-Entscheid. Erfassungs-Konventionen bewusst wie bei den
// laufenden Flows: Zufluss nominal (wie Einkommen), Kosten real (wie Ausgaben).
export function CashTransitionFields({
  ct,
  setC,
  deflatorEnd,
}: {
  ct: CashTransitionData;
  setC: (patch: Partial<CashTransitionData>) => void;
  deflatorEnd: number; // Bestands-Deflator an der Phasengrenze
}) {
  const mode = ct.mode ?? "NONE";
  const showIn = mode === "INFLOW" || mode === "BOTH";
  const showOut = mode === "OUTFLOW" || mode === "BOTH";
  const d = deflatorEnd || 1;
  const inflowGross = num(ct.inflowAmount);
  const taxRate = num(ct.inflowTaxRate, 0);
  const inflowNet = Math.round(inflowGross * (1 - taxRate / 100));

  return (
    <>
      <div className="sm:col-span-2">
        <SelectField
          label="Entscheid für das Cash-Konto"
          help="Was passiert beim Übergang in die nächste Lebensphase mit dem Cash-Bestand?"
          value={mode}
          onChange={(v: CashTransitionMode) =>
            setC(
              v === "NONE"
                ? { mode: v, inflowAmount: 0, outflowAmount: 0 }
                : v === "INFLOW"
                  ? { mode: v, outflowAmount: 0 }
                  : v === "OUTFLOW"
                    ? { mode: v, inflowAmount: 0 }
                    : { mode: v }
            )
          }
          options={[
            { value: "NONE", label: "1:1 übernehmen" },
            { value: "INFLOW", label: "Einmaliger Zufluss" },
            { value: "OUTFLOW", label: "Einmalige Kosten" },
            { value: "BOTH", label: "Zufluss und Kosten" },
          ]}
        />
      </div>

      {showIn && (
        <>
          <div className="sm:col-span-2 rounded-lg bg-surface-2 px-3 py-2 text-xs text-muted">
            <strong className="text-fg">Einmaliger Zufluss</strong> (z. B. Erbschaft). Wird NOMINAL erfasst –
            der Betrag, der zu diesem Zeitpunkt tatsächlich aufs Konto kommt.
          </div>
          <TextField
            label="Bezeichnung"
            value={ct.inflowLabel ?? ""}
            placeholder="z. B. Erbschaft"
            onChange={(v) => setC({ inflowLabel: v })}
          />
          <MoneyField
            label="Betrag NOMINAL (CHF)"
            value={inflowGross}
            onChange={(v) => setC({ inflowAmount: v })}
          />
          <NumberField
            label="Steuer (%)"
            help="Z. B. Erbschafts-/Schenkungssteuer. Direkte Nachkommen sind in den meisten Kantonen befreit – Default 0 %."
            step={0.5}
            value={taxRate}
            onChange={(v) => setC({ inflowTaxRate: v })}
          />
          <DerivedField
            label="≈ real (heutige Kaufkraft)"
            value={Math.round(inflowNet / d)}
            help="Netto-Zufluss nach Steuer, zurückgerechnet auf die Kaufkraft bei Planbeginn. Nur zur Info."
          />
          {taxRate > 0 && (
            <DerivedField
              label="Netto aufs Cash (nominal)"
              value={inflowNet}
              help="Betrag abzüglich Steuer. Wird automatisch berechnet."
            />
          )}
        </>
      )}

      {showOut && (
        <>
          <div className="sm:col-span-2 rounded-lg bg-surface-2 px-3 py-2 text-xs text-muted">
            <strong className="text-fg">Einmalige Kosten</strong> (z. B. Poolbau). Werden REAL erfasst –
            in heutiger Kaufkraft. Die Inflation rechnet daraus automatisch den nominalen Betrag.
          </div>
          <TextField
            label="Bezeichnung"
            value={ct.outflowLabel ?? ""}
            placeholder="z. B. Poolbau"
            onChange={(v) => setC({ outflowLabel: v })}
          />
          <MoneyField
            label="Betrag REAL (CHF, heutige Kaufkraft)"
            value={num(ct.outflowAmount)}
            onChange={(v) => setC({ outflowAmount: v })}
          />
          <DerivedField
            label="≈ nominal (zum Zeitpunkt)"
            value={Math.round(num(ct.outflowAmount) * d)}
            help="Der Betrag, der zu diesem Zeitpunkt tatsächlich fällig ist. Nur zur Info."
          />
        </>
      )}
    </>
  );
}

// "Beantwortet" = ein konkreter Entscheid liegt vor (kein offenes Fragezeichen).
export function isTransitionAnswered(category: ElementCategory, isRetirement: boolean, td: TransitionData): boolean {
  switch (category) {
    case "AHV":
      // Nur bei der Pensionierung ist eine Prüfung der Beitragskarriere nötig.
      return isRetirement ? td.reviewed === true : true;
    case "REAL_ESTATE":
    case "OTHER_ASSET":
      return td.decision !== undefined;
    case "PENSION_FUND":
      return isRetirement ? td.payoutMode !== undefined : td.withdrawalMode !== undefined;
    case "PILLAR_3A":
      return isRetirement ? true : td.withdrawalMode !== undefined;
    default:
      return true;
  }
}

// --- Wiederverwendbare Feldgruppen (Detail-Panel, Erstell-Popup, Übergangs-Review) ---

export function ElementPhaseFields({
  element,
  context,
  pd,
  setP,
}: {
  element: { category: ElementCategory };
  context: CellContext;
  pd: PhaseData;
  setP: (patch: Partial<PhaseData>) => void;
}) {
  const carried = context.carried;
  switch (element.category) {
    case "INCOME":
    case "EXPENSE": {
      const isIncome = element.category === "INCOME";
      // Basiswert (erstes Jahr). Ab Phase 2 mit dem fortgeschriebenen Wert der Vorphase
      // vorbelegt, aber bewusst änderbar (Teilzeit, Beförderung, Jobwechsel …).
      const baseValue = typeof pd.amount === "number" ? pd.amount : carried ? context.derivedStart : 0;
      const rate = num(pd.teuerungsausgleich, 0);
      const d = context.deflatorStart || 1;
      // Info-Gegenwert im ersten Jahr: Einkommen -> real; Ausgaben -> nominal.
      const otherValue = isIncome ? Math.round(baseValue / d) : Math.round(baseValue * d);
      return (
        <>
          <p className="col-span-2 rounded-lg bg-surface-2 px-3 py-2 text-xs text-muted">
            {isIncome
              ? "Bitte das NETTO-Einkommen erfassen: der Betrag, der nach allen Lohnabzügen (AHV/ALV, Pensionskasse, NBU) tatsächlich aufs Konto kommt – nicht der Bruttolohn. Erfasst wird NOMINAL; der reale Wert (heutige Kaufkraft) erscheint nur zur Info. Für die AHV-Rente rechnet das Tool intern auf den Bruttolohn zurück."
              : "Ausgaben werden REAL erfasst (in heutiger Kaufkraft). Die Inflation (plan-weit) rechnet daraus automatisch die nominalen Ausgaben – nur zur Info."}
          </p>
          <MoneyField
            label={isIncome ? "Jahreseinkommen NETTO, nominal (erstes Jahr)" : "Jahresausgaben REAL (erstes Jahr, heutige Kaufkraft)"}
            help={carried ? "Vorbelegt mit dem fortgeschriebenen Wert der Vorphase; hier bewusst änderbar." : undefined}
            value={baseValue}
            onChange={(v) => setP({ amount: v })}
          />
          <DerivedField
            label={isIncome ? "≈ real (heutige Kaufkraft)" : "≈ nominal (in diesem Jahr)"}
            value={otherValue}
            help="Nur zur Info, wird automatisch berechnet."
          />
          <NumberField
            label={isIncome ? "Nominale Lohnerhöhung (%/Jahr)" : "Reale Mehrausgaben (%/Jahr)"}
            help={
              isIncome
                ? "Geschätzte jährliche Lohnerhöhung. 0% = Lohn bleibt nominal gleich und verliert real an Kaufkraft."
                : "Zusätzliche reale Mehrausgaben pro Jahr (z. B. weil man sich mehr gönnt). Die Inflation kommt separat automatisch dazu. 0% = gleicher Lebensstandard."
            }
            step={0.1}
            value={rate}
            onChange={(v) => setP({ teuerungsausgleich: v })}
          />
        </>
      );
    }
    case "AHV":
      if (!context.ownerWorking) {
        // Sonderfall: bei Planbeginn bereits pensioniert -> es gibt keinen Pensions-Übergang,
        // an dem die Karriere geprüft werden könnte. Dann hier erfassen (nur erste Phase).
        if (!carried && context.ahvCareer && context.ahvCareer.planYears === 0) {
          return (
            <>
              <p className="col-span-2 rounded-lg bg-surface-2 px-3 py-2 text-xs text-muted">
                Diese Person ist bei Planbeginn bereits pensioniert. Die AHV-Rente hängt vom
                massgebenden durchschnittlichen Jahreseinkommen über die ganze Beitragsdauer ab –
                bitte hier erfassen (REAL, heutige Kaufkraft).
              </p>
              <MoneyField
                label="Durchschnittliches Bruttöinkommen der Beitragsjahre (real)"
                help="BRUTTO und in heutiger Kaufkraft. Am besten aus der AHV-Rentenvorausberechnung bzw. der Rentenverfügung. Ab 90'720 gibt es die Maximalrente."
                value={num(pd.avgIncomeBefore)}
                onChange={(v) => setP({ avgIncomeBefore: v })}
              />
              <NumberField
                label="Ausfalljahre total"
                help="Jahre ohne AHV-Beiträge. Jedes kürzt die Rente um 1/44."
                value={num(pd.gapYearsBefore)}
                min={0}
                onChange={(v) => setP({ gapYearsBefore: Math.max(0, Math.round(v)) })}
              />
              <DerivedField
                label="Resultierende AHV-Rente pro Jahr"
                value={ahvAnnualPension(num(pd.avgIncomeBefore), num(pd.gapYearsBefore))}
                help="Inkl. 13. Altersrente. Bei Ehepaaren zusätzlich plafoniert."
              />
            </>
          );
        }
        return (
          <p className="col-span-2 text-sm text-muted">
            Die AHV-Rente wird aus der beim Pensions-Übergang geprüften Beitragskarriere berechnet
            (massgebendes Durchschnittseinkommen und Ausfalljahre). Bei Ehepaaren greift die
            Plafonierung auf 150% der Maximalrente.
          </p>
        );
      }
      return (
        <NumberField
          label="Geplante Ausfalljahre"
          help="Jahre ohne AHV-Beiträge in dieser Phase. Jedes Ausfalljahr kürzt die spätere Rente um 1/44."
          value={num(pd.gapYears)}
          min={0}
          max={context.durationYears}
          onChange={(v) => setP({ gapYears: Math.max(0, Math.min(context.durationYears, Math.round(v))) })}
        />
      );
    case "PENSION_FUND":
      if (!context.ownerWorking) {
        return (
          <p className="col-span-2 text-sm text-muted">
            Die PK-Rente wird aus dem beim Pensions-Übergang gewählten Umwandlungssatz berechnet (siehe
            Kennzahl). Bei reinem Kapitalbezug erscheint hier &quot;Vollständig bezogen&quot;.
          </p>
        );
      }
      return (
        <>
          {carried ? (
            <>
              <DerivedField label="Startwert (fortgeschrieben)" value={context.derivedStart} help="Endwert der Vorphase, fortgeschrieben." />
              <MoneyField
                label="Zusatzeinlage aus Kapital (CHF)"
                help="Aufstockung aus dem verfügbaren Kapital dieser Phase."
                value={num(pd.additionalInvestment)}
               
                onChange={(v) => setP({ additionalInvestment: v })}
              />
            </>
          ) : (
            <MoneyField label="Aktueller PK-Wert (CHF)" value={num(pd.currentValue)} onChange={(v) => setP({ currentValue: v })} />
          )}
          <MoneyField
            label="Jährliche Einzahlung (CHF)"
            help="Arbeitnehmer- und Arbeitgeberbeiträge. Fliesst NICHT in die Sparquote ein (bereits in den Ausgaben berücksichtigt)."
            value={num(pd.annualContribution)}
            onChange={(v) => setP({ annualContribution: v })}
          />
          <NumberField label="Erwartete Rendite (%/Jahr)" step={0.1} value={num(pd.expectedReturn)} onChange={(v) => setP({ expectedReturn: v })} />
        </>
      );
    case "PILLAR_3A":
      if (!context.ownerWorking) {
        return <p className="col-span-2 text-sm text-muted">Die Säule 3a wird beim Pensions-Übergang vollständig bezogen.</p>;
      }
      return (
        <>
          {carried ? (
            <>
              <DerivedField label="Startwert (fortgeschrieben)" value={context.derivedStart} help="Endwert der Vorphase, fortgeschrieben." />
              <MoneyField
                label="Zusatzeinlage aus Kapital (CHF)"
                help="Aufstockung aus dem verfügbaren Kapital dieser Phase."
                value={num(pd.additionalInvestment)}
               
                onChange={(v) => setP({ additionalInvestment: v })}
              />
            </>
          ) : (
            <MoneyField label="Aktueller 3a-Wert (CHF)" value={num(pd.currentValue)} onChange={(v) => setP({ currentValue: v })} />
          )}
          <MoneyField
            label="Jährliche Einzahlung (CHF)"
            help={`Maximal CHF ${PILLAR_3A_MAX_ANNUAL.toLocaleString("de-CH")} (2026, mit PK) und höchstens die Sparquote. Wird von der Sparquote abgezogen.`}
            value={num(pd.annualContribution)}
            max={PILLAR_3A_MAX_ANNUAL}
            onChange={(v) => setP({ annualContribution: v })}
          />
          <NumberField label="Erwartete Rendite (%/Jahr)" step={0.1} value={num(pd.expectedReturn)} onChange={(v) => setP({ expectedReturn: v })} />
        </>
      );
    case "REAL_ESTATE": {
      // Zinsbetrag zu Phasenbeginn und -ende: die Restschuld sinkt mit der Amortisation,
      // der Zinsbetrag also mit. Am Nullpunkt gekappt (analog zur Berechnung).
      const hypStart = carried ? context.derivedMortgage : num(pd.mortgage);
      const hypEnde = Math.max(0, hypStart - num(pd.amortization) * context.durationYears);
      const zinsStart = Math.round((hypStart * num(pd.interestRate)) / 100);
      const zinsEnde = Math.round((hypEnde * num(pd.interestRate)) / 100);
      const handling = pd.interestHandling ?? "INCLUDED";
      return (
        <>
          {carried ? (
            <>
              <DerivedField
                label="Startwert Netto (fortgeschrieben)"
                value={context.derivedStart}
                help="Verkehrswert (inkl. bisheriger Wertsteigerung) minus fortgeschriebene Resthypothek."
              />
              <DerivedField label="Resthypothek (fortgeschrieben)" value={hypStart} help="Aus der Vorphase fortgeschrieben." />
            </>
          ) : (
            <>
              <MoneyField label="Kaufpreis (CHF)" value={num(pd.purchasePrice)} onChange={(v) => setP({ purchasePrice: v })} />
              <MoneyField label="Hypothek (CHF)" value={num(pd.mortgage)} onChange={(v) => setP({ mortgage: v })} />
            </>
          )}
          <MoneyField
            label="Amortisation (CHF/Jahr)"
            help="Jährliche Reduktion der Hypothek. Zählt gegen die Sparquote und endet, sobald die Hypothek abbezahlt ist."
            value={num(pd.amortization)}
            onChange={(v) => setP({ amortization: v })}
          />
          <NumberField
            label="Hypothekarzins (%/Jahr)"
            help="Zinssatz auf der Restschuld. Der Zinsbetrag sinkt automatisch mit der Amortisation."
            step={0.1}
            value={num(pd.interestRate)}
            onChange={(v) => setP({ interestRate: v })}
          />
          <div>
            <FieldLabel
              label="Hypothekarzins-Betrag (Beginn → Ende)"
              help="Restschuld x Zinssatz, im ersten und im letzten Jahr dieser Phase. Wird automatisch berechnet."
            />
            <div className="w-full rounded-lg border border-dashed border-border bg-surface-2 px-2.5 py-1.5 text-sm text-muted">
              {formatChf(zinsStart)} <span className="text-faint">→</span> {formatChf(zinsEnde)}
            </div>
          </div>
          <NumberField
            label="Geschätzte Wertsteigerung (%/Jahr)"
            help="Wirkt auf den Wert der LIEGENSCHAFT, nicht auf das Eigenkapital. 1% von 1 Mio sind 10'000 pro Jahr – bei 100'000 Eigenkapital also 10% darauf (Hebel)."
            step={0.1}
            value={num(pd.valueGrowth)}
            onChange={(v) => setP({ valueGrowth: v })}
          />
          <div className="sm:col-span-2">
            <SelectField
              label="Sind die Hypothekarzinsen bereits in den Ausgaben enthalten?"
              help="Damit die Zinsen nicht doppelt zählen. Standard: bereits enthalten – so verhalten sich bestehende Pläne unverändert."
              value={handling}
              onChange={(v: "INCLUDED" | "ADD") => setP({ interestHandling: v })}
              options={[
                { value: "INCLUDED", label: "Ja – bereits im Ausgaben-Element berücksichtigt" },
                { value: "ADD", label: "Nein – bitte zu den Ausgaben dazuzählen" },
              ]}
            />
          </div>
        </>
      );
    }
    case "OTHER_ASSET":
      return (
        <>
          {carried ? (
            <>
              <DerivedField label="Startwert (fortgeschrieben)" value={context.derivedStart} help="Endwert der Vorphase, fortgeschrieben." />
              <MoneyField
                label="Zusatzinvestition aus Kapital (CHF)"
                help="Neuinvestition aus dem verfügbaren Kapital dieser Phase."
                value={num(pd.additionalInvestment)}
               
                onChange={(v) => setP({ additionalInvestment: v })}
              />
            </>
          ) : (
            <MoneyField label="Startwert (CHF)" value={num(pd.startValue)} onChange={(v) => setP({ startValue: v })} />
          )}
          <NumberField label="Erwartete Rendite (%/Jahr)" step={0.1} value={num(pd.expectedReturn)} onChange={(v) => setP({ expectedReturn: v })} />
          <MoneyField
            label="Jährlicher Sparbeitrag (CHF)"
            help="Flacher Jahresbetrag, der ins Vermögen fliesst und vom Cash abgezogen wird (geplante Sparrate)."
            value={num(pd.annualContribution)}
            onChange={(v) => setP({ annualContribution: v })}
          />
          <MoneyField
            label="Jährliche Bezugsrate (CHF)"
            help="Entnahme aus dem Vermögen (z. B. laufende Renten-Entnahme im Alter). Mindert das Vermögen und fliesst jährlich ins Cash (geplante Verzehrrate)."
            value={num(pd.annualWithdrawal)}
            onChange={(v) => setP({ annualWithdrawal: v })}
          />
        </>
      );
    case "OTHER_DEBT":
      return (
        <>
          {carried ? (
            <DerivedField label="Restschuld (fortgeschrieben)" value={Math.abs(context.derivedStart)} help="Fortgeschriebene Restschuld aus der Vorphase." />
          ) : (
            <MoneyField label="Restschuld (CHF)" value={num(pd.startValue)} onChange={(v) => setP({ startValue: v })} />
          )}
          <MoneyField
            label="Jährliche Tilgung (CHF)"
            help="Zählt gegen die Sparquote (max. die Sparquote)."
            value={num(pd.annualRepayment)}
           
            onChange={(v) => setP({ annualRepayment: v })}
          />
        </>
      );
  }
}

export function ElementTransitionFields({
  element,
  context,
  td,
  setT,
}: {
  element: { category: ElementCategory };
  context: CellContext;
  td: TransitionData;
  setT: (patch: Partial<TransitionData>) => void;
}) {
  switch (element.category) {
    case "INCOME":
    case "EXPENSE":
      return (
        <p className="col-span-2 text-sm text-muted">
          Für diese Kategorie gibt es im Übergang keine Eingaben. Die Werte werden 1:1 in die nächste
          Lebensphase übernommen und können dort angepasst werden.
        </p>
      );
    case "AHV":
      if (context.isRetirementTransition && context.ahvCareer) {
        return <AhvReviewFields career={context.ahvCareer} td={td} setT={setT} />;
      }
      return (
        <p className="col-span-2 text-sm text-muted">
          Die Beitragskarriere wird erst beim Übergang in die Pensionierung geprüft.
        </p>
      );
    case "PENSION_FUND":
      if (context.isRetirementTransition) {
        const mode = td.payoutMode ?? "PENSION";
        return (
          <>
            <SelectField
              label="Bezugsart bei Pensionierung"
              value={mode}
              onChange={(v: "CAPITAL" | "PENSION" | "COMBI") => setT({ payoutMode: v })}
              options={[
                { value: "PENSION", label: "Rente" },
                { value: "CAPITAL", label: "Kapitalbezug" },
                { value: "COMBI", label: "Kombination" },
              ]}
            />
            {(mode === "PENSION" || mode === "COMBI") && (
              <NumberField
                label="Umwandlungssatz (%)"
                help="Jährliche Rente = verrentetes Kapital x Umwandlungssatz."
                step={0.1}
                value={num(td.conversionRate, DEFAULT_PK_CONVERSION_RATE)}
                onChange={(v) => setT({ conversionRate: v })}
              />
            )}
            {(mode === "CAPITAL" || mode === "COMBI") && (
              <NumberField label="Kapitalbezugssteuer (%)" step={0.5} value={num(td.capitalTaxRate, DEFAULT_CAPITAL_TAX_RATE)} onChange={(v) => setT({ capitalTaxRate: v })} />
            )}
            {mode === "COMBI" && (
              <MoneyField
                label="Davon Kapitalbezug (CHF)"
                help={`Der Rest wird verrentet. Maximal ${formatChf(context.carriedEndValue)}.`}
                value={num(td.capitalAmount)}
                max={context.carriedEndValue}
                onChange={(v) => setT({ capitalAmount: v })}
              />
            )}
          </>
        );
      }
      return <WithdrawalDecision td={td} setT={setT} max={context.carriedEndValue} label="PK-Bezug (CHF)" />;
    case "PILLAR_3A":
      if (context.isRetirementTransition) {
        return (
          <NumberField
            label="Kapitalbezugssteuer (%)"
            help="Die Säule 3a wird bei Pensionierung vollständig bezogen."
            step={0.5}
            value={num(td.capitalTaxRate, DEFAULT_CAPITAL_TAX_RATE)}
            onChange={(v) => setT({ capitalTaxRate: v })}
          />
        );
      }
      return <WithdrawalDecision td={td} setT={setT} max={context.carriedEndValue} label="3a-Bezug (CHF)" />;
    case "REAL_ESTATE": {
      const decision = td.decision ?? "HOLD";
      const marktwert = Math.round(context.propertyValueEnd);
      const preis = num(td.salePrice);
      // Abweichung zwischen erfasstem Verkaufspreis und modelliertem Verkehrswert. Beide
      // Grössen sind unabhängig erfassbar -- ohne diesen Vergleich könnte man 2 %
      // Wertsteigerung annehmen und trotzdem zum Kaufpreis verkaufen, ohne es zu merken.
      const abweichung = preis - marktwert;
      const abweichungPct = marktwert > 0 ? (abweichung / marktwert) * 100 : 0;
      const deutlich = marktwert > 0 && Math.abs(abweichungPct) >= 10;
      return (
        <>
          <SelectField
            label="Entscheidung"
            value={decision === "SELL" ? "SELL" : "HOLD"}
            onChange={(v: "HOLD" | "SELL") =>
              // Beim Wechsel auf "Verkaufen" den Verkaufspreis mit dem modellierten
              // Verkehrswert vorbelegen -- aber nur, wenn noch keiner erfasst ist.
              setT(v === "SELL" && td.salePrice === undefined ? { decision: v, salePrice: marktwert } : { decision: v })
            }
            options={[
              { value: "HOLD", label: "Halten" },
              { value: "SELL", label: "Verkaufen" },
            ]}
          />
          {decision === "SELL" && (
            <>
              <MoneyField
                label="Verkaufspreis (CHF)"
                help="Vorbelegt mit dem modellierten Verkehrswert am Phasenende. Bewusst änderbar – der erfasste Preis ist massgebend, nicht der modellierte Wert."
                value={preis}
                onChange={(v) => setT({ salePrice: v })}
              />
              <DerivedField
                label="Modellierter Verkehrswert (Phasenende)"
                value={marktwert}
                help="Kaufpreis zuzüglich der bis hierhin aufgelaufenen Wertsteigerung. Nur zum Vergleich – für den Erlös zählt der oben erfasste Verkaufspreis."
              />
              {marktwert > 0 && (
                <p
                  className={`col-span-full rounded-lg px-3 py-2 text-xs ${
                    deutlich ? "border border-danger bg-danger-soft text-danger" : "bg-surface-2 text-muted"
                  }`}
                >
                  {Math.abs(abweichung) < 1 ? (
                    <>Verkaufspreis und modellierter Verkehrswert stimmen überein.</>
                  ) : (
                    <>
                      Der Verkaufspreis liegt <strong>{formatChf(Math.abs(abweichung))} CHF</strong> (
                      {abweichung > 0 ? "+" : "−"}
                      {Math.abs(Math.round(abweichungPct * 10) / 10)} %) {abweichung > 0 ? "über" : "unter"} dem
                      modellierten Verkehrswert.
                      {deutlich && (
                        <>
                          {" "}
                          Das ist eine deutliche Abweichung – prüfe, ob sie gewollt ist oder ob die angenommene
                          Wertsteigerung nicht zum erwarteten Verkaufspreis passt.
                        </>
                      )}
                    </>
                  )}
                </p>
              )}
              <NumberField label="Grundstückgewinnsteuer (%)" step={1} value={num(td.saleTaxRate, DEFAULT_PROPERTY_GAINS_TAX_RATE)} onChange={(v) => setT({ saleTaxRate: v })} />
            </>
          )}
          {decision !== "SELL" && context.mortgageEnd > 0 && (
            <MoneyField
              label="Sonderamortisation (CHF)"
              help={`Einmaltilgung der Hypothek aus dem Cash der nächsten Phase (z. B. aus einem 3a-Bezug). Senkt Restschuld und künftige Zinsen. Maximal ${formatChf(context.mortgageEnd)} (Resthypothek am Phasenende).`}
              value={num(td.extraAmortization)}
              max={context.mortgageEnd}
              onChange={(v) => setT({ extraAmortization: v })}
            />
          )}
        </>
      );
    }
    case "OTHER_ASSET": {
      const decision = td.decision ?? "HOLD";
      return (
        <>
          <SelectField
            label="Entscheidung"
            value={decision}
            onChange={(v: "HOLD" | "SELL" | "PARTIAL") => setT({ decision: v })}
            options={[
              { value: "HOLD", label: "Halten" },
              { value: "SELL", label: "Verkaufen (ganz)" },
              { value: "PARTIAL", label: "Teilverkauf" },
            ]}
          />
          {decision === "PARTIAL" && (
            <MoneyField
              label="Teilverkauf (CHF)"
              help={`Betrag, der am Übergang ins Cash fliesst. Der Rest bleibt investiert. Maximal ${formatChf(context.carriedEndValue)} (Endwert der Vorphase).`}
              value={num(td.partialSaleAmount)}
              max={context.carriedEndValue}
              onChange={(v) => setT({ partialSaleAmount: v })}
            />
          )}
        </>
      );
    }
    case "OTHER_DEBT":
      return (
        <MoneyField
          label="Sofortige Tilgung (CHF)"
          help="Wird sofort getilgt und vom verfügbaren Kapital der nächsten Phase abgezogen."
          value={num(td.immediateRepayment)}
          onChange={(v) => setT({ immediateRepayment: v })}
        />
      );
  }
}

export function ElementDetail({
  element,
  context,
  phaseData,
  transitionData,
  allPhases = [],
  phaseDataByPhase = {},
  onSaved,
  onDeleteElement,
}: Props) {
  const [pd, setPd] = useState<PhaseData>({ ...phaseData });
  const [td, setTd] = useState<TransitionData>({ ...transitionData });
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);
  // Reichweite einer geänderten Rate. Vorgabe ist das bisherige Verhalten: nur diese Phase.
  const [scope, setScope] = useState<RateScope>("THIS");

  const isTransition = context.kind === "transition";

  // Welche Ratenfelder hat der Nutzer verändert? Nur dann wird überhaupt gefragt.
  const changedRates = isTransition ? [] : changedRateFields(element.category, phaseData, pd);
  const showScope = changedRates.length > 0 && allPhases.length > 1;

  async function save() {
    setSaving(true);
    setError(null);
    try {
      if (isTransition) {
        await api.put(`/api/elements/${element.id}/transition/${context.phaseId}`, td);
      } else {
        const payload: PhaseData = { ...pd };
        // Einkommen/Ausgaben ab Phase 2: entspricht der Basiswert dem fortgeschriebenen Wert
        // der Vorphase, KEINEN Override speichern -> Wert bleibt live vererbt (Änderungen in
        // früheren Phasen wirken sich weiter aus). Nur ein bewusst abweichender Wert wird fix.
        if (
          (element.category === "INCOME" || element.category === "EXPENSE") &&
          context.carried &&
          typeof payload.amount === "number" &&
          payload.amount === Math.round(context.derivedStart)
        ) {
          delete payload.amount;
        }
        await api.put(`/api/elements/${element.id}/phase/${context.phaseId}`, payload);

        // Geänderte Raten auf die gewählten weiteren Phasen übertragen. Die bestehenden
        // Werte der Zielphasen bleiben erhalten -- übernommen wird ausschliesslich die Rate.
        // Alle Schreibvorgänge fallen in dieselbe Bearbeitungssitzung und ergeben daher
        // EINE Nebenversion, nicht eine je Phase (siehe 3.8.1).
        for (const w of buildRateWrites(
          allPhases,
          context.phaseId,
          scope,
          changedRates,
          pd,
          phaseDataByPhase
        )) {
          await api.put(`/api/elements/${element.id}/phase/${w.phaseId}`, w.data);
        }
      }
      onSaved();
    } catch (e) {
      setError(e instanceof Error ? e.message : "Speichern fehlgeschlagen.");
    } finally {
      setSaving(false);
    }
  }

  function setP(patch: Partial<PhaseData>) {
    setPd((prev) => ({ ...prev, ...patch }));
  }
  function setT(patch: Partial<TransitionData>) {
    setTd((prev) => ({ ...prev, ...patch }));
  }

  return (
    <div className="flex flex-col gap-4">
      <div className="flex items-start justify-between gap-2">
        <div>
          <div className="text-xs font-semibold uppercase tracking-wide text-accent-soft-fg">
            {CATEGORY_LABELS[element.category]}
            {isTransition ? " · Übergang" : ""}
          </div>
          <div className="text-base font-semibold text-fg">{element.name}</div>
        </div>
        <button
          type="button"
          onClick={onDeleteElement}
          className="flex items-center gap-1 rounded-lg border border-border px-2 py-1 text-xs text-muted hover:border-danger hover:bg-danger-soft hover:text-danger"
        >
          <Trash2 className="h-3.5 w-3.5" /> Element löschen
        </button>
      </div>

      <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
        {/* Punkt 4: Warnung, dass Änderungen sich in die Folgephasen fortschreiben. */}
        {!isTransition && <CarryWarning laterPhaseCount={context.laterPhaseCount} />}
        {isTransition ? (
          <ElementTransitionFields element={element} context={context} td={td} setT={setT} />
        ) : (
          <ElementPhaseFields element={element} context={context} pd={pd} setP={setP} />
        )}
      </div>

      {/* Rückfrage zur Reichweite. Erscheint erst, wenn eine Rate tatsächlich verändert
          wurde -- und bewusst hier statt als Modal beim Tippen: Das Zahlenfeld löst bei
          jedem Tastendruck aus, ein Dialog erschiene bei «5.2» viermal. */}
      {showScope && (
        <div className="rounded-xl border border-attention bg-attention-soft p-3">
          <p className="mb-2 text-xs text-attention-soft-fg">
            {scopeQuestion(changedRates, allPhases.length)}
          </p>
          <div className="inline-flex flex-wrap gap-0.5 rounded-lg border border-border bg-surface p-0.5 text-xs">
            {SCOPE_OPTIONS.map((o) => (
              <button
                key={o.value}
                type="button"
                onClick={() => setScope(o.value)}
                className={`rounded-md px-2.5 py-1 font-medium transition-colors ${
                  scope === o.value ? "bg-accent text-accent-fg" : "text-muted hover:text-fg"
                }`}
              >
                {o.label}
              </button>
            ))}
          </div>
          <p className="mt-1.5 text-[11px] text-attention-soft-fg/80">
            {scope === "THIS"
              ? "Andere Phasen bleiben unverändert."
              : `Wird beim Speichern in ${
                  buildRateWrites(allPhases, context.phaseId, scope, changedRates, pd, phaseDataByPhase).length
                } weitere Phase(n) übertragen. Beträge und Raten dort bleiben erhalten – nur der geänderte Wert wird gesetzt.`}
          </p>
        </div>
      )}

      {error && <p className="text-sm text-danger">{error}</p>}
      <div>
        <button
          type="button"
          disabled={saving}
          onClick={save}
          className="rounded-lg bg-accent px-4 py-2 text-sm font-medium text-accent-fg shadow-sm hover:bg-accent-hover disabled:opacity-50"
        >
          {saving ? "Speichern..." : "Speichern"}
        </button>
      </div>
    </div>
  );
}
