import { useMemo, useState } from 'react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useBacktestReport } from '../../hooks/useMarketRegime';
import { triggerJob } from '../../api/admin';
import type { BacktestTargetModel } from '../../api/admin';
import { Button } from '../ui/Button';
import { Callout } from '../ui/Callout';
import { Disclosure } from '../ui/Disclosure';
import { Dropdown } from '../ui/Dropdown';
import { Section } from '../ui/Section';
import { useToast } from '../ui/Toast';
import type { BacktestCurvePoint, BacktestPortfolioMonitorRun } from '../../lib/types';

function fmtR(v: number | null | undefined): string {
  if (v === null || v === undefined) return '—';
  return `${v > 0 ? '+' : ''}${v.toFixed(2)}R`;
}
function fmtPct(v: number | null): string {
  return v === null ? '—' : `${v.toFixed(1)}%`;
}
function fmtMoney(v: number | null | undefined): string {
  if (v === null || v === undefined) return '—';
  return v.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}
function fmtSignedPct(v: number | null | undefined): string {
  if (v === null || v === undefined) return '—';
  return `${v > 0 ? '+' : ''}${v.toFixed(1)}%`;
}
function fmtDrawdown(v: number | null | undefined): string {
  return v === null || v === undefined ? '—' : `-${Math.abs(v).toFixed(1)}%`;
}
function fmtDays(v: number | null | undefined): string {
  return v === null || v === undefined ? '—' : `${v.toFixed(1)}d`;
}
function rColor(v: number | null): string {
  if (v === null) return 'text-gray-400';
  if (v > 0) return 'text-emerald-400';
  if (v < 0) return 'text-red-400';
  return 'text-gray-300';
}

function timeAgo(iso: string): string {
  const mins = Math.floor((Date.now() - new Date(iso).getTime()) / 60_000);
  if (mins < 1) return 'just now';
  if (mins < 60) return `${mins}m ago`;
  const hrs = Math.floor(mins / 60);
  if (hrs < 24) return `${hrs}h ago`;
  return `${Math.floor(hrs / 24)}d ago`;
}

function Stat({ label, value, valueClass = 'text-gray-100', sub }: {
  label: string; value: string; valueClass?: string; sub?: string;
}) {
  return (
    <div className="glass p-4">
      <p className="section-index">{label}</p>
      <p className={`num mt-1.5 text-2xl font-semibold ${valueClass}`}>{value}</p>
      {sub && <p className="mt-1 text-xs text-gray-500">{sub}</p>}
    </div>
  );
}

function curvePath(
  points: BacktestCurvePoint[],
  min: number,
  max: number,
  w: number,
  h: number,
  pad: number,
  startMs: number,
  endMs: number,
): string {
  if (points.length < 2) return '';
  const span = Math.max(max - min, 1);
  const timeSpan = Math.max(endMs - startMs, 1);
  return points
    .map((p, i) => {
      const t = new Date(p.date).getTime();
      const x = pad + ((t - startMs) / timeSpan) * (w - pad * 2);
      const value = p.return_pct ?? 0;
      const y = pad + (1 - (value - min) / span) * (h - pad * 2);
      return `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}`;
    })
    .join(' ');
}

function EquityCurveChart({ run }: { run: BacktestPortfolioMonitorRun }) {
  const portfolio = run.equity_curve ?? [];
  const benchmark = run.benchmark_curve ?? [];
  const values = [...portfolio, ...benchmark]
    .map((p) => p.return_pct)
    .filter((v): v is number => v !== null && v !== undefined);
  if (portfolio.length < 2 || values.length === 0) {
    return <Callout variant="empty">No equity curve points for this selection.</Callout>;
  }

  const min = Math.min(0, ...values);
  const max = Math.max(0, ...values);
  const times = [...portfolio, ...benchmark]
    .map((p) => new Date(p.date).getTime())
    .filter((v) => Number.isFinite(v));
  if (times.length === 0) {
    return <Callout variant="empty">No dated equity curve points for this selection.</Callout>;
  }
  const startMs = Math.min(...times);
  const endMs = Math.max(...times);
  const w = 720;
  const h = 240;
  const pad = 28;
  const portfolioPath = curvePath(portfolio, min, max, w, h, pad, startMs, endMs);
  const benchmarkPath = curvePath(benchmark, min, max, w, h, pad, startMs, endMs);
  const lastPortfolio = portfolio[portfolio.length - 1]?.return_pct ?? null;
  const lastBenchmark = benchmark[benchmark.length - 1]?.return_pct ?? run.spy_return_pct;

  return (
    <div className="glass overflow-hidden">
      <div className="flex flex-wrap items-center justify-between gap-3 border-b border-white/[0.05] px-4 py-3">
        <div>
          <p className="text-sm font-semibold text-gray-100">{run.label}</p>
          <p className="text-[11px] text-gray-500">{run.start_date} - {run.end_date}</p>
        </div>
        <div className="flex gap-4 text-xs">
          <span className="text-blue-300">Portfolio {fmtSignedPct(lastPortfolio)}</span>
          <span className="text-gray-400">S&P 500 {fmtSignedPct(lastBenchmark)}</span>
        </div>
      </div>
      <svg viewBox={`0 0 ${w} ${h}`} className="h-64 w-full" role="img" aria-label="Portfolio return compared with S&P 500">
        <line x1={pad} y1={h - pad} x2={w - pad} y2={h - pad} stroke="rgba(255,255,255,0.12)" />
        <line x1={pad} y1={pad} x2={pad} y2={h - pad} stroke="rgba(255,255,255,0.12)" />
        {benchmarkPath && (
          <path d={benchmarkPath} fill="none" stroke="rgba(156,163,175,0.9)" strokeWidth="2" strokeDasharray="5 5" />
        )}
        <path d={portfolioPath} fill="none" stroke="rgb(96,165,250)" strokeWidth="3" />
        <text x={pad} y={pad - 8} className="fill-gray-500 text-[10px]">{fmtSignedPct(max)}</text>
        <text x={pad} y={h - 8} className="fill-gray-500 text-[10px]">{fmtSignedPct(min)}</text>
      </svg>
    </div>
  );
}

export function BacktestPanel() {
  const { data: report, isLoading } = useBacktestReport();
  const queryClient = useQueryClient();
  const toast = useToast();
  const [selectedStrategy, setSelectedStrategy] = useState('');
  const [selectedLookback, setSelectedLookback] = useState('');
  const [targetModel, setTargetModel] = useState<BacktestTargetModel>('production_gtl');

  const monitor = report?.portfolio_monitor ?? null;
  const activeStrategy =
    selectedStrategy || monitor?.production_strategy || monitor?.strategies[0]?.strategy || '';
  const activeLookback =
    selectedLookback || (monitor?.lookbacks.some((l) => l.lookback === '3y') ? '3y' : monitor?.lookbacks[0]?.lookback) || '';
  const monitorRun = useMemo(
    () =>
      monitor?.runs.find((row) => row.strategy === activeStrategy && row.lookback === activeLookback) ??
      monitor?.runs.find((row) => row.strategy === activeStrategy) ??
      monitor?.runs[0] ??
      null,
    [monitor, activeStrategy, activeLookback],
  );

  const run = useMutation({
    mutationFn: () => triggerJob('backtest', { target_model: targetModel }),
    onSuccess: (res) => {
      if (res.status === 'triggered') {
        const label = targetModel === 'production_gtl' ? 'Live GTL' : 'Structural S/R comparison';
        toast.addToast('success', `${label} backtest started — results appear when it finishes.`);
        setTimeout(() => queryClient.invalidateQueries({ queryKey: ['backtest-report'] }), 8000);
      } else {
        toast.addToast('info', res.message || 'Could not start backtest');
      }
    },
    onError: () => toast.addToast('error', 'Failed to start backtest'),
  });

  return (
    <Section title="Is the strategy working?" hint="portfolio simulation of the promoted strategy vs S&P 500">
      <div className="space-y-4">
        <div className="flex flex-wrap items-start justify-between gap-3">
          <Disclosure summary="How this is measured">
            <p className="max-w-2xl text-xs text-gray-400">
              The backtest replays the current config weekly through history — at each point the setup is
              rebuilt using only data up to that day (no lookahead) and the following ~30 trading days decide
              its outcome — then simulates one capital-constrained book against the S&P 500. Sentiment and
              fundamentals are held neutral (no point-in-time history). ~6 months is roughly one market regime,
              so read it as directional.
            </p>
          </Disclosure>
          <div className="flex w-full flex-col gap-3 sm:w-auto sm:items-end">
            <fieldset className="grid w-full grid-cols-1 gap-2 sm:w-[34rem] sm:grid-cols-2">
              <legend className="mb-1 text-[11px] font-medium uppercase tracking-wider text-gray-500">
                Target model for this run
              </legend>
              <label
                className={`cursor-pointer rounded-lg border px-3 py-2 transition-colors focus-within:ring-2 focus-within:ring-blue-400/60 ${
                  targetModel === 'production_gtl'
                    ? 'border-blue-400/60 bg-blue-500/10'
                    : 'border-white/10 bg-white/[0.03] hover:border-white/20'
                }`}
              >
                <input
                  className="sr-only"
                  type="radio"
                  name="backtest-target-model"
                  value="production_gtl"
                  checked={targetModel === 'production_gtl'}
                  onChange={() => setTargetModel('production_gtl')}
                />
                <span className="flex items-center justify-between gap-2 text-sm font-medium text-gray-100">
                  Live GTL
                  <span className="rounded-full border border-blue-400/40 bg-blue-400/10 px-2 py-0.5 text-[9px] font-semibold uppercase tracking-widest text-blue-300">
                    Production
                  </span>
                </span>
                <span className="mt-1 block text-[11px] leading-4 text-gray-500">
                  Exact target path used by the live scanner and scheduled backtest.
                </span>
              </label>
              <label
                className={`cursor-pointer rounded-lg border px-3 py-2 transition-colors focus-within:ring-2 focus-within:ring-amber-400/60 ${
                  targetModel === 'structural_sr'
                    ? 'border-amber-400/50 bg-amber-500/10'
                    : 'border-white/10 bg-white/[0.03] hover:border-white/20'
                }`}
              >
                <input
                  className="sr-only"
                  type="radio"
                  name="backtest-target-model"
                  value="structural_sr"
                  checked={targetModel === 'structural_sr'}
                  onChange={() => setTargetModel('structural_sr')}
                />
                <span className="text-sm font-medium text-gray-200">Structural S/R</span>
                <span className="mt-1 block text-[11px] leading-4 text-gray-500">
                  Comparison only; uses chart structure as the target source.
                </span>
              </label>
            </fieldset>
            <Button onClick={() => run.mutate()} loading={run.isPending} className="shrink-0">
              {run.isPending ? 'Starting…' : report ? 'Re-run backtest' : 'Run backtest'}
            </Button>
          </div>
        </div>

        {isLoading && <Callout variant="empty">Loading…</Callout>}

        {!isLoading && !report && (
          <Callout variant="empty">
            No backtest yet. Click “Run backtest” (or trigger it in Admin → Jobs) — it replays every ticker
            over history and takes a minute or two.
          </Callout>
        )}

        {report && (
          <>
            <p className="text-[11px] text-gray-500">
              Ran {timeAgo(report.generated_at)} · {report.tickers} tickers · {report.candidates} setups
              ({report.qualified} qualified) · weekly cadence, {report.params.horizon_days}-day horizon
              {report.params.cost_per_side_pct != null && (
                <> · net of {report.params.cost_per_side_pct}%/side costs</>
              )}
              {' '}· target model:{' '}
              <span className={report.params.is_production_target_model === false ? 'text-amber-300' : 'text-blue-300'}>
                {report.params.target_model_label ?? 'Unknown (legacy report)'}
              </span>
            </p>

            {monitor && monitorRun ? (
              <div className="space-y-3">
                <div className="flex flex-wrap items-end justify-between gap-3">
                  <div>
                    <p className="section-index">Portfolio monitor</p>
                    <p className="mt-1 text-xs text-gray-500">
                      Simulated book for the selected strategy and lookback, compared with the S&P 500.
                    </p>
                  </div>
                  <div className="flex flex-wrap gap-2">
                    <div className="flex flex-col gap-1 text-[11px] uppercase tracking-wider text-gray-500">
                      <label htmlFor="monitor-strategy">Strategy</label>
                      <Dropdown
                        id="monitor-strategy"
                        className="w-64 normal-case tracking-normal"
                        value={activeStrategy}
                        onChange={setSelectedStrategy}
                        options={monitor.strategies.map((s) => ({
                          value: s.strategy,
                          label: `${s.is_production ? 'Production: ' : ''}${s.label}`,
                        }))}
                      />
                    </div>
                    <div className="flex flex-col gap-1 text-[11px] uppercase tracking-wider text-gray-500">
                      <label htmlFor="monitor-lookback">Lookback</label>
                      <Dropdown
                        id="monitor-lookback"
                        className="w-36 normal-case tracking-normal"
                        value={activeLookback}
                        onChange={setSelectedLookback}
                        options={monitor.lookbacks.map((l) => ({ value: l.lookback, label: l.label }))}
                      />
                    </div>
                  </div>
                </div>

                <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-5">
                  <Stat label="CAGR" value={fmtSignedPct(monitorRun.cagr_pct)} valueClass={rColor(monitorRun.cagr_pct)} />
                  <Stat label="Sharpe" value={monitorRun.sharpe == null ? '—' : monitorRun.sharpe.toFixed(2)} />
                  <Stat label="Max Drawdown" value={fmtDrawdown(monitorRun.max_drawdown_pct)} valueClass="text-amber-400" />
                  <Stat
                    label="Total Return"
                    value={fmtSignedPct(monitorRun.total_return_pct)}
                    valueClass={rColor(monitorRun.total_return_pct)}
                    sub={`vs S&P 500 ${fmtSignedPct(monitorRun.spy_return_pct)}`}
                  />
                  <Stat label="Trades" value={String(monitorRun.trades)} sub={`${fmtPct(monitorRun.win_rate)} win rate`} />
                </div>

                <EquityCurveChart run={monitorRun} />

                <p className="text-[11px] text-gray-500">
                  Avg hold {fmtDays(monitorRun.avg_hold_days)} · Best {fmtR(monitorRun.best_trade_r)} / Worst{' '}
                  {fmtR(monitorRun.worst_trade_r)} · Avg P&amp;L per trade {fmtMoney(monitorRun.avg_trade_pnl)}
                </p>

                {monitorRun.yearly_returns && monitorRun.yearly_returns.length > 0 && (
                  <div className="glass overflow-x-auto p-4">
                    <p className="section-index mb-2">Per-year returns</p>
                    <div className="flex flex-wrap gap-2">
                      {monitorRun.yearly_returns.map((y) => (
                        <div key={y.year} className="rounded border border-white/10 px-3 py-1.5">
                          <span className="num text-xs text-gray-500">{y.year}</span>{' '}
                          <span className={`num text-sm font-semibold ${rColor(y.return_pct)}`}>
                            {fmtSignedPct(y.return_pct)}
                          </span>
                        </div>
                      ))}
                    </div>
                  </div>
                )}

                {monitor.note && <p className="text-[11px] text-gray-600">{monitor.note}</p>}
              </div>
            ) : (
              <Callout variant="empty">
                This report predates the portfolio monitor — re-run the backtest to populate it.
              </Callout>
            )}

            {report.recommendation && report.recommendation.items.length > 0 && (
              <div className="glass border border-blue-400/20 p-4">
                <p className="section-index">What this backtest recommends</p>
                {report.recommendation.headline && (
                  <p className="mt-1.5 text-sm font-semibold text-gray-100">
                    {report.recommendation.headline}
                  </p>
                )}
                <ul className="mt-2 space-y-1">
                  {report.recommendation.items.map((item) => (
                    <li
                      key={item.topic + item.text}
                      className={`text-xs ${item.text.includes('WARNING') || item.text.includes('LAGS') ? 'text-amber-400' : 'text-gray-400'}`}
                    >
                      {item.text}
                    </li>
                  ))}
                </ul>
                {report.recommendation.note && (
                  <p className="mt-2 text-[11px] text-gray-600">{report.recommendation.note}</p>
                )}
              </div>
            )}

            <p className="text-[11px] text-gray-600">
              Strategy research — gate tuning, exit sweeps, factor rank-IC — now runs locally against a
              database snapshot (see README). This page keeps only what says whether the promoted strategy
              is worth trading; your realized results up top show what it is actually delivering.
            </p>
          </>
        )}
      </div>
    </Section>
  );
}
