/**
 * What-If — interactive Monte Carlo. Form on the left, fan chart on the
 * right. Hits POST /simulate (no DB write); ~1-3s for 5k paths.
 */
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';

import { api, type SimulateRequest, type SimulateResult } from '@/api/client';
import { FanChart } from '@/components/FanChart';
import { gbp, pct } from '@/lib/format';

const JURISDICTIONS = ['uk', 'cyprus', 'bulgaria', 'malaysia', 'thailand', 'uae', 'nomad'];
const STRATEGIES = ['trinity', 'guyton_klinger', 'vpw', 'vpw_floor'];
const GLIDES = ['rising', 'static_60_40'];

const DEFAULTS: SimulateRequest = {
  jurisdiction: 'cyprus',
  strategy: 'guyton_klinger',
  leave_uk_year: 2,
  glide_path: 'rising',
  spending_gbp: '60000',
  nw_seed_gbp: '1500000',
  savings_per_year_gbp: '0',
  horizon_years: 60,
  floor_gbp: null,
  n_paths: 5000,
  seed: 42,
};

export function WhatIf() {
  const [form, setForm] = useState<SimulateRequest>(DEFAULTS);
  const [nwAutoFilled, setNwAutoFilled] = useState(false);
  const navigate = useNavigate();
  const qc = useQueryClient();

  // Pre-fill NW seed from the latest Wealthfolio snapshot the first
  // time it loads, so opening /what-if always starts from real numbers.
  // The user can still edit; we won't clobber their input on later
  // refetches.
  const nw = useQuery({ queryKey: ['networth', 'current'], queryFn: api.networth.current });
  useEffect(() => {
    if (nwAutoFilled || !nw.data || nw.data.accounts.length === 0) return;
    // Round to whole pounds — pence from the API don't survive HTML5
    // step validation, and the user doesn't think in pence at this scale.
    const rounded = String(Math.round(Number(nw.data.total_gbp)));
    setForm((f) => ({ ...f, nw_seed_gbp: rounded }));
    setNwAutoFilled(true);
  }, [nw.data, nwAutoFilled]);

  const sim = useMutation({
    mutationFn: (req: SimulateRequest) => api.simulate(req),
  });

  const save = useMutation({
    mutationFn: (name: string) =>
      api.scenarios.create({
        name,
        jurisdiction: form.jurisdiction,
        strategy: form.strategy,
        leave_uk_year: form.leave_uk_year,
        glide_path: form.glide_path,
        spending_gbp: form.spending_gbp,
        nw_seed_gbp: form.nw_seed_gbp,
        savings_per_year_gbp: form.savings_per_year_gbp,
        horizon_years: form.horizon_years,
      }),
    onSuccess: (s) => {
      qc.invalidateQueries({ queryKey: ['scenarios'] });
      navigate(`/scenarios/${s.id}`);
    },
  });

  const onSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    sim.mutate({
      ...form,
      floor_gbp: form.strategy === 'vpw_floor' ? form.floor_gbp : null,
    });
  };

  const onSaveAs = () => {
    const suggested = `${form.jurisdiction}-${form.strategy}-leave-y${form.leave_uk_year}`;
    const name = prompt('Save as scenario — name:', suggested);
    if (!name?.trim()) return;
    save.mutate(name.trim());
  };

  const update = <K extends keyof SimulateRequest>(key: K, value: SimulateRequest[K]) =>
    setForm((f) => ({ ...f, [key]: value }));

  return (
    <section className="space-y-6">
      <header>
        <h1 className="text-3xl font-semibold tracking-tight">What if…</h1>
        <p className="text-sm text-slate-500">
          Run a single Monte Carlo against the engine. No data persisted.
        </p>
      </header>

      <div className="grid grid-cols-1 lg:grid-cols-[320px_1fr] gap-6 items-start">
        <form
          onSubmit={onSubmit}
          className="rounded-lg border border-slate-200 bg-white p-5 space-y-4 sticky top-4"
        >
          <Field label="Jurisdiction">
            <Select
              value={form.jurisdiction}
              onChange={(v) => update('jurisdiction', v)}
              options={JURISDICTIONS}
            />
          </Field>
          <Field label="Strategy">
            <Select
              value={form.strategy}
              onChange={(v) => update('strategy', v)}
              options={STRATEGIES}
            />
          </Field>
          <Field label="Glide path">
            <Select
              value={form.glide_path}
              onChange={(v) => update('glide_path', v)}
              options={GLIDES}
            />
          </Field>
          <Field label="Years until leaving UK">
            <NumberInput
              value={form.leave_uk_year}
              onChange={(v) => update('leave_uk_year', v)}
              min={0}
              max={60}
            />
          </Field>
          <Field label="Annual spending (£)">
            <NumberInput
              value={Number(form.spending_gbp)}
              onChange={(v) => update('spending_gbp', String(v))}
              min={0}
            />
          </Field>
          <Field label="NW seed (£)">
            <NumberInput
              value={Number(form.nw_seed_gbp)}
              onChange={(v) => update('nw_seed_gbp', String(v))}
              min={0}
            />
          </Field>
          <Field label="Annual savings (£)">
            <NumberInput
              value={Number(form.savings_per_year_gbp ?? 0)}
              onChange={(v) => update('savings_per_year_gbp', String(v))}
              min={0}
            />
          </Field>
          <Field label="Horizon (years)">
            <NumberInput
              value={form.horizon_years ?? 60}
              onChange={(v) => update('horizon_years', v)}
              min={5}
              max={100}
            />
          </Field>
          {form.strategy === 'vpw_floor' && (
            <Field label="Floor (£/yr)">
              <NumberInput
                value={Number(form.floor_gbp ?? 40000)}
                onChange={(v) => update('floor_gbp', String(v))}
                min={0}
              />
            </Field>
          )}
          <Field label="Monte Carlo paths">
            <NumberInput
              value={form.n_paths ?? 5000}
              onChange={(v) => update('n_paths', v)}
              min={100}
              max={50000}
              step={100}
            />
          </Field>

          <button
            type="submit"
            disabled={sim.isPending}
            className="w-full rounded-md bg-slate-900 text-white text-sm font-medium px-4 py-2 hover:bg-slate-800 disabled:opacity-60 disabled:cursor-not-allowed"
          >
            {sim.isPending ? 'Running…' : 'Run simulation'}
          </button>
        </form>

        <div className="space-y-4 min-w-0">
          {sim.isError && (
            <div className="rounded-md border border-red-200 bg-red-50 p-4 text-red-800 text-sm">
              {String((sim.error as Error)?.message ?? sim.error)}
            </div>
          )}
          {!sim.data && !sim.isPending && !sim.isError && (
            <div className="rounded-lg border border-slate-200 bg-white p-12 text-center text-slate-500">
              Set parameters on the left and run a simulation.
            </div>
          )}
          {sim.isPending && (
            <div className="rounded-lg border border-slate-200 bg-white p-12 text-center text-slate-500">
              Running Monte Carlo…
            </div>
          )}
          {sim.data && (
            <>
              <Results result={sim.data} horizon={form.horizon_years ?? 60} />
              <div className="flex items-center gap-3">
                <button
                  type="button"
                  onClick={onSaveAs}
                  disabled={save.isPending}
                  className="rounded-md border border-slate-300 bg-white text-sm px-4 py-2 hover:bg-slate-50 disabled:opacity-60"
                >
                  {save.isPending ? 'Saving…' : 'Save as scenario'}
                </button>
                {save.isError && (
                  <span className="text-xs text-red-700">
                    {String((save.error as Error)?.message ?? save.error)}
                  </span>
                )}
              </div>
            </>
          )}
        </div>
      </div>
    </section>
  );
}

function Results({ result, horizon }: { result: SimulateResult; horizon: number }) {
  return (
    <>
      <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
        <Stat label="Success rate" value={pct(result.success_rate)} accent />
        <Stat label="Median ending NW" value={gbp(result.p50_ending_gbp)} />
        <Stat label="P10 ending" value={gbp(result.p10_ending_gbp)} />
        <Stat label="P90 ending" value={gbp(result.p90_ending_gbp)} />
        <Stat label="Median lifetime tax" value={gbp(result.median_lifetime_tax_gbp)} />
        <Stat
          label="Median years to ruin"
          value={result.median_years_to_ruin ?? 'never'}
        />
        <Stat label="Horizon" value={`${horizon} years`} />
        <Stat label="Engine time" value={`${result.elapsed_seconds}s`} />
      </div>
      <div className="rounded-lg border border-slate-200 bg-white p-5">
        <h2 className="text-lg font-semibold mb-2">Portfolio fan</h2>
        <FanChart yearly={result.yearly} height={420} showWithdrawal />
      </div>
    </>
  );
}

function Stat({
  label,
  value,
  accent,
}: {
  label: string;
  value: string | number;
  accent?: boolean;
}) {
  return (
    <div className="rounded-md border border-slate-200 bg-white p-3">
      <div className="text-xs uppercase tracking-wide text-slate-500">{label}</div>
      <div
        className={`text-xl font-semibold tabular-nums mt-1 ${
          accent ? 'text-emerald-700' : ''
        }`}
      >
        {value}
      </div>
    </div>
  );
}

function Field({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <label className="block">
      <span className="text-xs uppercase tracking-wide text-slate-500">{label}</span>
      <div className="mt-1">{children}</div>
    </label>
  );
}

function Select({
  value,
  onChange,
  options,
}: {
  value: string;
  onChange: (v: string) => void;
  options: string[];
}) {
  return (
    <select
      value={value}
      onChange={(e) => onChange(e.target.value)}
      className="w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-slate-400"
    >
      {options.map((o) => (
        <option key={o} value={o}>
          {o}
        </option>
      ))}
    </select>
  );
}

function NumberInput({
  value,
  onChange,
  min,
  max,
  step = 1,
}: {
  value: number;
  onChange: (v: number) => void;
  min?: number;
  max?: number;
  step?: number;
}) {
  return (
    <input
      type="number"
      value={value}
      min={min}
      max={max}
      step={step}
      onChange={(e) => {
        const n = Number(e.target.value);
        if (Number.isFinite(n)) onChange(n);
      }}
      className="w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-sm tabular-nums focus:outline-none focus:ring-2 focus:ring-slate-400"
    />
  );
}
