"""
label_charts.py -- [2026-10-01] The user: "do that (mark the best entry/exit on each chart)
for the 22 days stocks and the sip stocks first".
  set "22d" : every stock-day on the 8/27-9/30 lists (labels from day_labels.jsonl) + the
              trade bot's own buys/sells on its live days
  set "sip" : every stock-day the sip_bot traded (/var/www/screener/premarket, READ ONLY),
              labeled the same way (label_days.label) + the sip_bot's buys/sells
Charts: reports/playbook/labels_22d/ and labels_sip/ ; sip labels also appended to
data/playbook/sip_day_labels.jsonl.
"""
import gzip
import json
import sys
import time
from collections import defaultdict
from datetime import datetime
from pathlib import Path
from zoneinfo import ZoneInfo

import matplotlib
matplotlib.use("Agg")
import matplotlib.dates as md
import matplotlib.pyplot as plt

HERE = Path(__file__).resolve().parent
TRADE = Path("/var/www/screener/trade")
sys.path.insert(0, str(TRADE))
sys.path.insert(0, str(HERE))
import reference as REF
import label_days as LD
import analyze_trades as A
from alpaca_client import get_client

ET = ZoneInfo("America/New_York")
STOP_AT = (9, 10)


def bot_trades(source):
    out = defaultdict(list)
    if source == "sip":
        for p in sorted(A.SIP.glob("*_trades.jsonl")):
            for t in A.load_trades(p.name[:10], "sip"):
                out[(p.name[:10], t["symbol"])].append(t)
    else:
        for p in sorted((TRADE / "data" / "trades").glob("*_trades.jsonl")):
            for l in open(p):
                t = json.loads(l)
                if t.get("exit_price") is not None:
                    out[(p.name[:10], t["symbol"])].append(t)
    return out


def draw(lab, B, trades, path, who):
    ts = [x["t"].replace(tzinfo=None) for x in B]
    fig, (ax, axv) = plt.subplots(2, 1, figsize=(10.5, 5.2), gridspec_kw={"height_ratios": [3, 1]}, sharex=True)
    ax.plot(ts, [x["c"] for x in B], color="#1f3a5f", lw=1)
    ax.plot(ts, [x["vwap"] for x in B], color="#c0392b", lw=1.1)
    ax.axhline(B[0]["o"], color="grey", ls=":", lw=.8)
    lo = min(x["l"] for x in B); hi = max(x["h"] for x in B); pad = (hi - lo) * .14
    ax.set_ylim(lo - pad, hi + pad)
    for key, col in (("best_held", "#16a085"), ("leg2", "#2980b9")):
        mk = lab.get(key)
        if not mk:
            continue
        bi = next(x for x in B if x["m"] == mk["entry_m"])
        bj = next(x for x in B if x["m"] == mk["exit_m"])
        ax.scatter([bi["t"].replace(tzinfo=None)], [bi["c"]], marker="*", s=170, color=col, edgecolor="black", zorder=6)
        ax.scatter([bj["t"].replace(tzinfo=None)], [bj["c"]], marker="*", s=170, color="#8e44ad", edgecolor="black", zorder=6)
        ax.annotate(f"best buy {bi['c']:.2f}", (bi["t"].replace(tzinfo=None), bi["c"]), xytext=(6, -14),
                    textcoords="offset points", fontsize=7, color=col, fontweight="bold")
        ax.annotate(f"best sell {bj['c']:.2f} (+{mk['gain_pct']:.1f}%)", (bj["t"].replace(tzinfo=None), bj["c"]),
                    xytext=(6, 7), textcoords="offset points", fontsize=7, color="#8e44ad", fontweight="bold")
    pl = 0.0
    for t in trades:
        ein, eout = A.et(t["entry_time"]).replace(tzinfo=None), A.et(t["exit_time"]).replace(tzinfo=None)
        ax.scatter([ein], [t["entry_price"]], marker="o", s=70, color="#27ae60", edgecolor="black", zorder=7)
        ax.scatter([eout], [t["exit_price"]], marker="o", s=70, color="#e74c3c", edgecolor="black", zorder=7)
        pl += t.get("pl_dollars") or 0
    bh = lab.get("best_held")
    ax.set_title(f"{lab['symbol']} {lab['date']}  open->close {lab['open_to_close_pct']:+.1f}%  |  "
                 + ("NO GOOD TRADE" if lab["no_trade"] else f"best holdable +{bh['gain_pct']:.1f}%: "
                    + ", ".join(bh['entry']['tags']) + " -> " + ", ".join(bh['exit']['tags']))
                 + (f"  |  {who}: {len(trades)} trade(s) {pl:+.2f}$" if trades else ""), fontsize=8)
    ax.grid(alpha=.3)
    axv.bar(ts, [x["v"] for x in B], width=1 / 1440, color=["#8e44ad" if x["volx"] >= 10 else "#1f3a5f" for x in B])
    axv.xaxis.set_major_formatter(md.DateFormatter("%H:%M"))
    axv.grid(alpha=.3)
    plt.tight_layout()
    plt.savefig(path, dpi=95)
    plt.close()


def too_late():
    t = datetime.now(ET)
    return (t.hour, t.minute) >= STOP_AT


def run_22d():
    out = HERE / "labels_22d"
    out.mkdir(exist_ok=True)
    labs = {(l["date"], l["symbol"]): l for l in map(json.loads, open(LD.OUT)) if l["date"] >= "2026-08-27"}
    trades = bot_trades("trade")
    n = 0
    for p in sorted(LD.BARS.glob("bars_2026-*.json.gz")):
        d = json.load(gzip.open(p, "rt"))
        if d["date"] < "2026-08-27":
            continue
        for s in d["top30_current"]:
            lab = labs.get((d["date"], s))
            ref = REF.load(d["date"], s)
            if not lab or not ref:
                continue
            B = LD.build(d["symbols"][s]["bars"], ref)
            draw(lab, B, trades.get((d["date"], s), []), out / f"{d['date']}_{s}.png", "trade bot")
            n += 1
        REF._CACHE.clear()
        if too_late():
            print("stopped 9:10"); break
    print(f"22d charts: {n}", flush=True)


def run_sip():
    out = HERE / "labels_sip"
    out.mkdir(exist_ok=True)
    trades = bot_trades("sip")
    client = get_client()
    labs, n = [], 0
    for (day, s), tr in sorted(trades.items()):
        if too_late():
            print("stopped 9:10"); break
        ref = REF.load(day, s)
        if not ref:
            continue
        d = datetime.fromisoformat(day).replace(tzinfo=ET)
        try:
            raw = client.get_minute_bars(s, start=d.replace(hour=9, minute=30), end=d.replace(hour=16), limit=1000)
        except Exception as e:
            print(day, s, e); continue
        rows = [[int(b.timestamp.timestamp()), float(b.open), float(b.high), float(b.low), float(b.close), float(b.volume)]
                for b in raw]
        B = LD.build(rows, ref)
        if len(B) < 100:
            continue
        lab = LD.label(day, s, B)
        lab["source"] = "sip_bot"
        lab["bot_pl"] = round(sum(t["pl_dollars"] for t in tr), 2)
        labs.append(lab)
        draw(lab, B, tr, out / f"{day}_{s}.png", "sip_bot")
        n += 1
    with open(TRADE / "data" / "playbook" / "sip_day_labels.jsonl", "w") as f:
        for l in labs:
            f.write(json.dumps(l, default=str) + "\n")
    print(f"sip charts: {n} of {len(trades)} traded stock-days", flush=True)


if __name__ == "__main__":
    t0 = time.time()
    if "sip" in sys.argv:
        run_sip()
    if "22d" in sys.argv:
        run_22d()
    print(f"done in {time.time() - t0:.0f}s")
