#!/usr/bin/env python3
"""TuxTone path-fit scorer.

Computes the "path fit" scores printed on /linux-noise-suppression/.
Scores are COMPUTED here, never hand-typed into HTML (fleet rule #5).
Re-run after updating the verified inputs below, then re-paste the output
table into the money page.

What the score measures
-----------------------
NOT denoising quality. Four of the five paths run the same RNNoise-family
model, so output quality is broadly similar. The score measures how safe
and how easy each path is to adopt on a Linux desktop TODAY:

  maintenance  /30  days since latest upstream release (verified live)
  packaging    /20  official channels we personally verified on the
                    verify date (Arch extra, Debian stable, Fedora,
                    Ubuntu, Flathub) x 4 pts. Conservative: unverified
                    channels score zero even if they probably exist.
  stack fit    /20  runs on a 2026 default desktop (PipeWire) natively;
                    paths built for the old PulseAudio API that work via
                    the compat layer get 16.
  setup        /15  judgment constants, documented per path below.
  scope        /15  live mic system-wide 15 / live mic app-local 10 /
                    after-the-fact file cleanup only 7.

All inputs verified 2026-09-20; sources in FACTS.md.
"""

from datetime import date

VERIFY_DATE = date(2026, 9, 20)

PATHS = {
    "EasyEffects": dict(
        latest_release=date(2026, 8, 31),   # v8.2.9 (Arch pkg + Flathub)
        packaging=5,   # Arch extra, Debian trixie, Fedora, Ubuntu, Flathub - all verified
        stack="pipewire-native",
        setup=13,      # GUI: install, add Noise Reduction to input pipeline
        scope="live-system",
    ),
    "PipeWire filter-chain": dict(
        latest_release=date(2026, 5, 29),   # werman plugin v1.21
        packaging=1,   # plugin verified in Arch extra only; source build elsewhere
        stack="pipewire-native",
        setup=6,       # hand-edit a filter-chain config, know your node names
        scope="live-system",
    ),
    "OBS Noise Suppression filter": dict(
        latest_release=date(2026, 8, 14),   # OBS Studio 32.2.2
        packaging=3,   # verified: Arch extra, Ubuntu (official PPA), Flathub
        stack="stack-agnostic",
        setup=12,      # per-profile filter UI inside OBS
        scope="live-app",
    ),
    "NoiseTorch": dict(
        latest_release=date(2022, 6, 17),   # v0.12.2 - dormant
        packaging=0,   # AUR only; no Arch official, no Debian, none verified official
        stack="pulse-api-compat",
        setup=15,      # single toggle GUI - still the easiest ever made
        scope="live-system",
    ),
    "CLI cleanup (ffmpeg arnndn/afftdn)": dict(
        latest_release=date(2026, 9, 18),   # ffmpeg 9.0.2 "Lei"
        packaging=5,   # ffmpeg ships in every major distro repo + Flathub runtimes
        stack="stack-agnostic",
        setup=8,       # per-file commands, model files for arnndn
        scope="post-only",
    ),
}

STACK_PTS = {"pipewire-native": 20, "stack-agnostic": 20, "pulse-api-compat": 16}
SCOPE_PTS = {"live-system": 15, "live-app": 10, "post-only": 7}


def maintenance_pts(days: int) -> int:
    if days < 120:
        return 30
    if days < 365:
        return 24
    if days < 730:
        return 15
    if days < 1500:
        return 8
    return 3


def main() -> None:
    rows = []
    for name, p in PATHS.items():
        days = (VERIFY_DATE - p["latest_release"]).days
        m = maintenance_pts(days)
        pk = min(p["packaging"], 5) * 4
        st = STACK_PTS[p["stack"]]
        se = p["setup"]
        sc = SCOPE_PTS[p["scope"]]
        total = m + pk + st + se + sc
        rows.append((total, name, m, pk, st, se, sc, days))

    rows.sort(reverse=True)
    print(f"TuxTone path-fit scores - computed {date.today().isoformat()}, "
          f"inputs verified {VERIFY_DATE.isoformat()}")
    print(f"{'path':<36} {'maint':>5} {'pkg':>4} {'stack':>5} "
          f"{'setup':>5} {'scope':>5} {'TOTAL':>6}  (release age, days)")
    for total, name, m, pk, st, se, sc, days in rows:
        print(f"{name:<36} {m:>5} {pk:>4} {st:>5} {se:>5} {sc:>5} "
              f"{total:>5}/100  ({days})")


if __name__ == "__main__":
    main()
