#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""p11_pull.py — 把 212 上 P11 早盘策略出的票（≤3 只，有序）拉到 119 供盯盘页读取。

数据源（只读，不改 212 任何东西）：
  /opt/kpl-cli/data/ladder/yijiner_latest.json   官方 P11 一进二出票，items 有序
  /opt/kpl-cli/data/ladder/yijiner_YYYYMMDD.json 当日留档（优先）

产出：
  /root/work/kpl/dingpan/p11.json          供页面直读
  /root/work/kpl/dingpan/p11-history.jsonl 每日快照（按天追加一行）

用法：
  python3 p11_pull.py            正常拉取
  python3 p11_pull.py --dry      只打印不落盘
"""
import json
import os
import subprocess
import sys
from datetime import datetime, timezone, timedelta

TZ_BJ = timezone(timedelta(hours=8))
HOST = "root@193.112.101.212"
SSH = [
    "ssh", "-i", "/root/.ssh/stock_key", "-p", "5522",
    "-o", "BatchMode=yes", "-o", "ConnectTimeout=12",
    "-o", "StrictHostKeyChecking=accept-new", HOST,
]
LADDER = "/opt/kpl-cli/data/ladder"
OUT_JSON = "/root/work/kpl/dingpan/p11.json"
OUT_HIST = "/root/work/kpl/dingpan/p11-history.jsonl"
MAX_ITEMS = 3


def bj_now():
    return datetime.now(TZ_BJ)


def remote_cat(path):
    try:
        r = subprocess.run(SSH + ["cat " + path], capture_output=True, timeout=45)
        if r.returncode != 0:
            return None
        return r.stdout.decode("utf-8", "replace")
    except Exception:
        return None


def load_picks():
    now = bj_now()
    day = now.strftime("%Y%m%d")
    for path in ("%s/yijiner_%s.json" % (LADDER, day), "%s/yijiner_latest.json" % LADDER):
        raw = remote_cat(path)
        if not raw:
            continue
        try:
            d = json.loads(raw)
        except Exception:
            continue
        if not isinstance(d, dict):
            continue
        items = d.get("items") or []
        if not items and not d.get("pass_count"):
            continue
        return d, path
    return None, None


def build(d, path):
    now = bj_now()
    items = []
    for i, it in enumerate((d.get("items") or [])[:MAX_ITEMS], 1):
        items.append({
            "rank": i,
            "code": str(it.get("code") or ""),
            "name": it.get("name") or "",
            "bid": it.get("real_pct", it.get("bid")),
            "price": it.get("price"),
            "pre_close": it.get("pre_close"),
            "score": it.get("score"),
            "confidence": it.get("confidence"),
            "l2_tag": it.get("l2_tag") or "",
            "plate": it.get("plate") or "",
            "concepts": it.get("concepts") or "",
            "wme": it.get("wme"),
            "strong": bool(it.get("strong")),
            "p10p13": bool(it.get("p10p13")),
            "keep_reason": it.get("keep_reason") or "",
        })

    upd = d.get("updated_at_str") or d.get("updated_at") or ""
    day = ""
    for cand in (upd, str(d.get("day") or "")):
        s = "".join(ch for ch in cand if ch.isdigit())
        if len(s) >= 8:
            day = "%s-%s-%s" % (s[0:4], s[4:6], s[6:8])
            break
    today = now.strftime("%Y-%m-%d")
    return {
        "ok": bool(items),
        "day": day,
        "today": today,
        "fresh": day == today,
        "updated_at": upd,
        "pulled_at": now.strftime("%Y-%m-%d %H:%M:%S"),
        "source": path,
        "pool_size": d.get("pool_size"),
        "pass_count": d.get("pass_count"),
        "locked": bool(d.get("locked")),
        "lock_at": d.get("lock_at") or "",
        "items": items,
    }


def main():
    dry = "--dry" in sys.argv
    d, path = load_picks()
    if d is None:
        payload = {
            "ok": False, "day": "", "today": bj_now().strftime("%Y-%m-%d"),
            "fresh": False, "pulled_at": bj_now().strftime("%Y-%m-%d %H:%M:%S"),
            "err": "拉取失败或 212 上没有出票", "items": [],
        }
    else:
        payload = build(d, path)

    text = json.dumps(payload, ensure_ascii=False, indent=1)
    if dry:
        print(text)
        return

    os.makedirs(os.path.dirname(OUT_JSON), exist_ok=True)
    tmp = OUT_JSON + ".tmp"
    with open(tmp, "w", encoding="utf-8") as f:
        f.write(text)
    os.replace(tmp, OUT_JSON)

    if payload.get("ok") and payload.get("items"):
        last_day = ""
        try:
            with open(OUT_HIST, encoding="utf-8") as f:
                lines = [l for l in f.read().splitlines() if l.strip()]
            if lines:
                last_day = json.loads(lines[-1]).get("day", "")
        except Exception:
            pass
        if last_day != payload["day"]:
            with open(OUT_HIST, "a", encoding="utf-8") as f:
                f.write(json.dumps(payload, ensure_ascii=False) + "\n")

    print("[%s] ok=%s day=%s items=%d fresh=%s" % (
        payload["pulled_at"], payload.get("ok"), payload.get("day"),
        len(payload.get("items") or []), payload.get("fresh")))


if __name__ == "__main__":
    main()
