import { useEffect, useMemo, useState } from 'react'
import { Anchor, RotateCcw, Compass } from 'lucide-react'
import {
  simulate,
  breakEvenSweep,
  distrokidCrossover,
  type CatalogInputs,
  type RevenueInputs,
} from './model'
import { PARVAGUES_CATALOG, MODEST_REVENUE } from './data'
import { Slider, Stepper, Group, Toggle } from './Control'
import { OptionRow } from './OptionRow'
import { BreakEvenChart } from './BreakEvenChart'
import { money, compact } from './format'

const STORE = 'sextant_inputs_v3'

interface State {
  cat: CatalogInputs
  rev: RevenueInputs
}

function load(): State {
  try {
    const s = JSON.parse(localStorage.getItem(STORE) || '')
    if (s?.cat && s?.rev) return s
  } catch {
    /* fall through to defaults */
  }
  return { cat: { ...PARVAGUES_CATALOG }, rev: { ...MODEST_REVENUE } }
}

export default function Sextant() {
  const [{ cat, rev }, setState] = useState<State>(load)
  useEffect(() => {
    localStorage.setItem(STORE, JSON.stringify({ cat, rev }))
  }, [cat, rev])

  const setCat = (patch: Partial<CatalogInputs>) => setState((s) => ({ ...s, cat: { ...s.cat, ...patch } }))
  const setRev = (patch: Partial<RevenueInputs>) => setState((s) => ({ ...s, rev: { ...s.rev, ...patch } }))
  const reset = () => setState({ cat: { ...PARVAGUES_CATALOG }, rev: { ...MODEST_REVENUE } })

  const { results, counts, bcRevenue } = useMemo(() => simulate(cat, rev), [cat, rev])
  const sweep = useMemo(() => breakEvenSweep(cat), [cat])
  const crossover = useMemo(() => distrokidCrossover(cat), [cat])

  const ranked = useMemo(() => [...results].sort((a, b) => b.profit - a.profit), [results])
  const winner = ranked[0]
  // Scale cost bars to the non-premium options. RouteNote Premium is a 5–10×
  // outlier; letting it set the scale would crush every other bar to a sliver.
  const maxCost = Math.max(...results.filter((r) => r.opt.id !== 'routenote-premium').map((r) => r.cost.total), 1)
  const maxProfit = Math.max(...results.map((r) => r.profit), 1)
  const cdbaby = results.find((r) => r.opt.id === 'cdbaby')!
  const distrokid = results.find((r) => r.opt.id === 'distrokid')!

  const aheadOfCDBaby = cat.cadencePerYear >= (crossover ?? Infinity)

  return (
    <div className="mx-auto min-h-svh max-w-7xl px-4 py-5 lg:px-6">
      <header className="flex flex-wrap items-end justify-between gap-3 border-b border-hairline pb-4">
        <div>
          <p className="flex items-center gap-1.5 text-[11px] uppercase tracking-widest text-ink-faint">
            <Anchor size={12} /> L&apos;Armada · manifeste
          </p>
          <h1 className="flex items-center gap-2 text-2xl font-semibold tracking-tight">
            <Compass size={22} className="text-ink-muted" /> Le Sextant
          </h1>
          <p className="mt-0.5 max-w-prose text-xs text-ink-faint">
            Where should the catalog live? Tune the catalog, cadence, and what a stream is worth. Every
            cost and cut is a sourced fact; every play count is your assumption.
          </p>
        </div>
        <button
          onClick={reset}
          className="flex items-center gap-1.5 rounded-md bg-raised px-3 py-1.5 text-xs font-medium
                     text-ink-muted transition-colors hover:bg-overlay hover:text-ink"
        >
          <RotateCcw size={13} /> Reset to ParVagues
        </button>
      </header>

      {/* Verdict strip */}
      <div className="mt-5 grid gap-3 sm:grid-cols-3">
        <div className="rounded-lg border border-magenta/40 bg-magenta/[0.05] p-4">
          <div className="text-[11px] uppercase tracking-wide text-ink-faint">Best net over {cat.horizonYears} yr</div>
          <div className="mt-0.5 text-lg font-semibold text-ink">{winner.opt.name}</div>
          <div className="mt-1 font-mono text-sm text-ready tnum">
            {money(winner.profit)} net · {money(winner.cost.total)} cost
          </div>
          {bcRevenue > 0 && (
            <div className="mt-1 text-[11px] text-ink-faint">
              incl. {money(bcRevenue)} Bandcamp layer — added to every option alike
            </div>
          )}
        </div>
        <div className="rounded-lg border border-hairline bg-raised p-4">
          <div className="text-[11px] uppercase tracking-wide text-ink-faint">DistroKid vs CD Baby</div>
          <div className="mt-0.5 text-sm leading-snug text-ink-muted">
            {crossover == null ? (
              <>CD Baby stays cheaper at every cadence in range — owning beats renting outright.</>
            ) : crossover === 0 ? (
              <>
                <span className="text-melodic">DistroKid is cheaper from day one</span> — porting your back-catalog to
                CD Baby already outcosts a decade of flat fees. The real question is ownership, not price.
              </>
            ) : (
              <>
                Break-even at <span className="font-mono text-ink">{crossover}</span> releases/yr. You plan{' '}
                <span className="font-mono text-ink">{cat.cadencePerYear}</span> —{' '}
                <span className={aheadOfCDBaby ? 'text-melodic' : 'text-tops'}>
                  {aheadOfCDBaby ? 'DistroKid wins on cost' : 'CD Baby wins on cost'}
                </span>
                .
              </>
            )}
          </div>
        </div>
        <div className="rounded-lg border border-hairline bg-raised p-4">
          <div className="text-[11px] uppercase tracking-wide text-ink-faint">Catalog modelled</div>
          <div className="mt-0.5 font-mono text-sm text-ink tnum">
            {counts.total} releases · {counts.singles} singles / {counts.albums} albums
          </div>
          <div className="mt-1 text-[11px] text-ink-faint">
            {counts.existing} existing · {counts.backlog} backlog · {counts.forward} forward
          </div>
        </div>
      </div>

      <div className="mt-6 grid gap-6 lg:grid-cols-[320px_1fr]">
        {/* ── Control rail ── */}
        <aside className="space-y-7 lg:sticky lg:top-5 lg:self-start">
          <Group title="Existing catalog" glyph="◆">
            <p className="-mt-1 text-[11px] text-ink-faint">Already on RouteNote/DSP. Frozen since 2024.</p>
            <Stepper label="Singles" value={cat.existingSingles} max={200} onChange={(v) => setCat({ existingSingles: v })} />
            <Stepper label="Albums / EPs" value={cat.existingAlbums} max={50} onChange={(v) => setCat({ existingAlbums: v })} />
          </Group>

          <Group title="Backlog to release" glyph="≋">
            <p className="-mt-1 text-[11px] text-ink-faint">SoundCloud tracks not yet on any DSP.</p>
            <Slider label="Tracks to release" value={cat.backlogTracks} min={0} max={80} unit="" onChange={(v) => setCat({ backlogTracks: v })} />
            <Slider
              label="Bundle into EPs"
              value={cat.backlogTracksPerEp}
              min={1}
              max={8}
              format={(v) => (v <= 1 ? 'all singles' : `${v} tracks/EP`)}
              hint="Fewer deliveries = lower per-release fees on CD Baby."
              onChange={(v) => setCat({ backlogTracksPerEp: v })}
            />
          </Group>

          <Group title="Forward cadence" glyph="↗">
            <Slider label="Releases per year" value={cat.cadencePerYear} min={0} max={24} onChange={(v) => setCat({ cadencePerYear: v })} />
            <Slider
              label="Album share"
              value={cat.cadenceAlbumShare}
              min={0}
              max={1}
              step={0.05}
              format={(v) => `${Math.round(v * 100)}% albums`}
              onChange={(v) => setCat({ cadenceAlbumShare: v })}
            />
            <Slider label="Horizon" value={cat.horizonYears} min={1} max={25} unit=" yr" onChange={(v) => setCat({ horizonYears: v })} />
          </Group>

          <Group title="Revenue assumptions" glyph="▲">
            <Slider label="Peak streams / release · mo" value={rev.peakStreams} min={50} max={5000} step={50} format={compact} onChange={(v) => setRev({ peakStreams: v })} />
            <Slider
              label="Long-tail floor / mo"
              value={rev.floorStreams}
              min={0}
              max={1000}
              step={10}
              format={compact}
              hint="The loyal-listener tail. A superfan on weekly repeat lives in here — noise, not a modelled spike."
              onChange={(v) => setRev({ floorStreams: v })}
            />
            <Slider label="Spike half-life" value={rev.halfLifeMonths} min={1} max={36} unit=" mo" onChange={(v) => setRev({ halfLifeMonths: v })} />
            <Slider label="Payout / stream" value={rev.perStream} min={0.001} max={0.01} step={0.0005} format={(v) => `$${v.toFixed(4)}`} onChange={(v) => setRev({ perStream: v })} />
          </Group>

          <Group title="Bandcamp layer" glyph="◇">
            <Toggle
              label="Run Bandcamp alongside"
              checked={rev.bcLayer}
              hint="Independent of the distributor — adds the same revenue to every option, so it never decides the comparison."
              onChange={(v) => setRev({ bcLayer: v })}
            />
            {rev.bcLayer && (
              <>
                <Slider
                  label="Digital sales / year"
                  value={rev.bcSalesPerYear}
                  min={0}
                  max={60}
                  format={(v) => `${v}/yr · whole catalog`}
                  hint="Across the entire catalog, not per release. For a niche catalog this is genuinely small."
                  onChange={(v) => setRev({ bcSalesPerYear: v })}
                />
                <Slider label="Bandcamp price" value={rev.bcPrice} min={1} max={20} format={money} onChange={(v) => setRev({ bcPrice: v })} />
              </>
            )}
          </Group>
        </aside>

        {/* ── Results console ── */}
        <main className="space-y-6">
          <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
            {ranked.map((r) => (
              <OptionRow key={r.opt.id} r={r} isWinner={r.opt.id === winner.opt.id} maxCost={maxCost} maxProfit={maxProfit} />
            ))}
          </div>

          <section className="rounded-lg border border-hairline bg-raised p-4">
            <div className="mb-3 flex flex-wrap items-baseline justify-between gap-2">
              <h2 className="text-sm font-semibold text-ink">The break-even, drawn</h2>
              <p className="text-xs text-ink-muted">
                CD Baby pays per release; DistroKid is flat. Where the teal crosses the blue, renting beats owning on
                pure cost.
              </p>
            </div>
            <BreakEvenChart sweep={sweep} currentCadence={cat.cadencePerYear} crossover={crossover} />
            <p className="mt-3 text-[11px] leading-snug text-ink-faint">
              At your settings: CD Baby costs <span className="font-mono text-ink-muted">{money(cdbaby.cost.total)}</span> over{' '}
              {cat.horizonYears} yr and stays up forever; DistroKid costs{' '}
              <span className="font-mono text-ink-muted">{money(distrokid.cost.total)}</span> but pulls everything the day
              you stop paying. Cost is one axis — ownership is the other.
            </p>
          </section>

          <footer className="border-t border-hairline pt-3 text-[11px] leading-relaxed text-ink-faint">
            <span className="text-ink-muted">Facts</span> (fees, cuts) from{' '}
            <code className="text-ink-muted">armada/manifeste/research-2026-distribution.md</code>.{' '}
            <span className="text-ink-muted">Assumptions</span> (plays, sales) are yours and persist locally. Streaming
            revenue is modelled as a per-release spike decaying to a flat long-tail floor; albums earn ~2.5× a single.
            Bandcamp is an independent layer — the same revenue on top of whichever distributor you pick, so it shifts
            every option equally and never decides the comparison; its real worth is ownership and the fan
            relationship, not the digital-sales line. The model is a compass, not a forecast.
          </footer>
        </main>
      </div>
    </div>
  )
}
