"""
advisor_day.py -- [2026-10-02] PLAYBOOK ADVISOR (the user's design, agreed 2026-10-02):
the bot trades with its own strategy; every minute it consults the playbook (winners AND losers,
the 150 closest days of the whole library, lib_v2 features, only days before the traded day) and
asks "what did days like this do over the NEXT 5 / 10 / 15 MINUTES?":
  up    = share of the 150 that went up +1% before going down 1% (within the horizon, from that minute's close)
  down  = share that went down 1% before going up 1% (both in the same minute counts as down)
  simulate.py --advisor-min-moved 0.2: rule on the days that MOVED (user OK 2026-10-02: 60% of movers,
  >= 20% of the 150 moving, median move agrees; horizons 5/10/15)
  med   = median move over the horizon of the 150, %
  wshare= share of winners among the 150 (info only)
Output: data/playbook/advisor_<day>_h<5|10|15>.json  {sym: {minute: [up, down, med, wshare]}}  (minute = last
finished 1-min bar, 0 = 9:30). simulate.py --advisor uses it (60% rule).
    python3 advisor_day.py 2026-10-02
"""
import json
import sys
from datetime import datetime
from pathlib import Path
from zoneinfo import ZoneInfo

import numpy as np

HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(HERE)); sys.path.insert(0, "/var/www/screener/trade")
import lib_v2 as L2
import sf3_batch as S3
import sf_watchlist_day as WL
import reference as REF
from alpaca_client import get_client

ET = ZoneInfo("America/New_York")
K, MOVE = 150, 1.0
HORIZONS = (5, 10, 15)
OUT = Path("/var/www/screener/trade/data/playbook")


def outcomes(lib, AHEAD):
    """per library day and minute: +1 up first, -1 down first, 0 neither; and the AHEAD-min move %"""
    n, T = lib.C.shape
    res = np.zeros((n, T), np.int8); mv = np.zeros((n, T), np.float32)
    base = lib.C.astype(np.float32)
    done = np.zeros((n, T), bool)
    for k in range(1, AHEAD + 1):
        h = np.full((n, T), np.nan, np.float32); l = h.copy()
        h[:, :T - k] = lib.H[:, k:]; l[:, :T - k] = lib.L[:, k:]
        dn = (l / base - 1) * 100 <= -MOVE
        up = (h / base - 1) * 100 >= MOVE
        res[~done & dn] = -1
        res[~done & up & ~dn] = 1
        done |= up | dn
    mv[:, :T - AHEAD] = (lib.C[:, AHEAD:] / base[:, :T - AHEAD] - 1) * 100
    return res, mv


def main(day, syms=None):
    win = WL.windows(day)
    syms = syms or list(win)
    c = get_client(); d0 = datetime.fromisoformat(day).replace(tzinfo=ET)
    rows = {s: [[b.timestamp, float(b.open), float(b.high), float(b.low), float(b.close), float(b.volume)]
                for b in c.get_minute_bars(s, start=d0.replace(hour=9, minute=30), end=d0.replace(hour=16), limit=1000)]
            for s in syms + ["SPY", "IWM"]}
    bench = []
    for b in ("SPY", "IWM"):
        by = L2._minutes(rows[b]); arr = np.zeros(390, np.float32); o = by[min(by)][1]; last = o
        for m in range(390):
            last = by[m][4] if m in by else last; arr[m] = (last / o - 1) * 100
        bench.append(arr)
    lib = L2.Lib()
    wins = S3.load()
    ok = np.where(lib.dates < day)[0]
    OC = {h: tuple(x[ok] for x in outcomes(lib, h)) for h in HORIZONS}
    sub = lib.F[ok]
    isw = np.array([lib.keys[i] in wins for i in ok])
    del lib
    out = {}
    for s in syms:
        ref = REF.load(day, s)
        a = L2.day_arrays(rows[s], ref, day, tuple(bench)) if ref else None
        if a is None:
            continue
        D = np.zeros(len(ok)); per = {h: {} for h in HORIZONS}
        for m in range(385):
            D += ((sub[:, m, :] - a["F"][None, m, :]) ** 2).sum(1)
            if m < 5:
                continue
            k = np.argpartition(D, K)[:K]
            for h, (res, mv) in OC.items():
                r = res[k, m]
                per[h][m] = [round(float((r == 1).mean()), 3), round(float((r == -1).mean()), 3),
                             round(float(np.median(mv[k, m])), 3), round(float(isw[k].mean()), 3)]
        out[s] = per
        print(s, "done", flush=True)
    for h in HORIZONS:
        oh = {s: p[h] for s, p in out.items()}
        json.dump(oh, open(OUT / f"advisor_{day}_h{h}.json", "w"))
        U = np.array([v[0] for p in oh.values() for v in p.values()]); Dn = np.array([v[1] for p in oh.values() for v in p.values()])
        print(f"\nHORIZON {h} min: {len(oh)} stocks, {len(U)} stock-minutes")
        for t in (0.3, 0.4, 0.5, 0.6):
            print(f"  up>={t:.0%}: {(U >= t).mean():.2%} of minutes   down>={t:.0%}: {(Dn >= t).mean():.2%}")
        print(f"  up share median {np.median(U):.2f} p99 {np.percentile(U, 99):.2f} max {U.max():.2f} | "
              f"down median {np.median(Dn):.2f} p99 {np.percentile(Dn, 99):.2f} max {Dn.max():.2f}")


if __name__ == "__main__":
    main(sys.argv[1], sys.argv[2].split(",") if len(sys.argv) > 2 else None)
