#!/usr/bin/env python3
"""What sample banks does SuperDirt actually have, and which ones shadow which?

Run this after dropping new samples in, BEFORE reloading. It resolves bank
names exactly the way `start_and_midi.scd`'s three loaders do, so it can answer
the two questions that bite:

  1. Did my new folder QUIETLY REPLACE an existing bank? `loadSoundFiles`
     defaults to appendToExisting = false, so a later loader with the same
     basename frees the earlier bank's buffers and takes the name. A pack with
     a folder called `kick` or `hh` will silently shadow whatever was there,
     and the only symptom is that an old track now plays the wrong sound.

  2. How many files will SuperDirt see? NOT what `ls` shows. SuperDirt globs
     with pathMatch("*"), which skips dotfiles — and some packs ship an
     AppleDouble `._X.wav` beside every real `X.wav`. `ls` hides those too, so
     a folder looks clean while a naive glob double-counts it.

Usage:
    tools/bank-check.py                 # full report
    tools/bank-check.py --since 3       # only banks touched in the last 3 days
    tools/bank-check.py --reload        # print the sclang to paste into SC
"""
from __future__ import annotations

import argparse
import sys
import time
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))
from pvbanks import LOADERS, scan, fmt_time  # one definition of "a bank"

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--since", type=float, help="only banks with files newer than N days")
    ap.add_argument("--reload", action="store_true", help="print the sclang to paste")
    a = ap.parse_args()

    banks = scan()
    total_files = sum(e[2] for v in banks.values() for e in v)
    print(f"{len(banks)} bank names, {total_files} playable files\n")

    shadowed = {k: v for k, v in banks.items() if len(v) > 1}
    if shadowed:
        print(f"SHADOWED — {len(shadowed)} name(s) claimed by more than one folder.")
        print("The LAST loader wins; the earlier bank's buffers are freed.\n")
        for k, v in sorted(shadowed.items()):
            print(f"  {k!r}")
            for i, (label, f, n, mt) in enumerate(v):
                mark = "  <- WINS" if i == len(v) - 1 else ""
                print(f"      {label:<14} {n:>5} files  "
                      f"{fmt_time(mt)[:10]}{mark}")
        print()
    else:
        print("No shadowed bank names. Every `s \"name\"` is unambiguous.\n")

    if a.since:
        cut = time.time() - a.since * 86400
        fresh = sorted((max(e[3] for e in v), k, v) for k, v in banks.items()
                       if max(e[3] for e in v) > cut)
        print(f"Banks with files newer than {a.since:g} day(s): {len(fresh)}")
        for mt, k, v in fresh:
            loaders = "+".join(e[0] for e in v)
            print(f"  {fmt_time(mt)}  "
                  f"{k:<28} {sum(e[2] for e in v):>5} files  ({loaders})")
        print()

    if a.reload:
        print("Paste into SuperCollider to pick up new banks WITHOUT rebooting:\n")
        print("(")
        print("~dirt.doNotReadYet = true;   // keep lazy loading ON — see below")
        for label, root, depth, _ in LOADERS:
            if depth == 1:
                print(f'~dirt.loadSoundFiles("{root}/*");')
            else:
                print(f'PathName.new("{root}").folders.do {{ |m|')
                print('    m.folders.do { |f| ~dirt.loadSoundFiles(f.fullPath,')
                print('        namingFunction: { |x| x.basename.replace("-", "") }) };')
                print("};")
        print(")")
        print("\n~dirt.doNotReadYet MUST stay true. It is the ONLY gate on the")
        print("on-demand read path, so with it false a freshly registered bank")
        print("is never read at all — permanently silent, not merely slow.")


if __name__ == "__main__":
    main()
