#!/usr/bin/env python3
"""So sánh HAI nhánh hạ quy mô trước khi chọn cho nghiệp vụ:

  cfs_0.25_sd  BCSD hạ quy mô Tx 1.0->0.25 (tất định) rồi N mô hình AI  (exp3/sd)
  cfs_0.25_AI  N mô hình AI học hạ quy mô + dự báo trực tiếp từ CFS thô (exp3/ai)

Cả hai dùng CHUNG cỗ máy ensemble N mô hình AI, chỉ khác cách biểu diễn Tx tại
điểm, nên bảng so sánh cô lập đúng ảnh hưởng của phương pháp hạ quy mô.

Hai tầng được báo cáo:
  * TẦNG GIÁ TRỊ (°C): D1 (BCSD) vs D2 (AI regression) lấy từ bcsd.json —
    trả lời "trường 0.25° nào gần quan trắc hơn".
  * TẦNG SỰ KIỆN EHDE: median trên 21 điểm của POD/POFD/FAR/FBI/CSI/SEDI/AUC
    (ensemble clf, quyết định 2 tầng) cho từng nhánh — trả lời "nhánh nào phát
    hiện EHD tốt hơn". Đây là tầng quyết định.

Chạy được cả khi array chưa xong: điểm nào thiếu thì bỏ qua và ghi rõ N điểm.
"""

from __future__ import annotations

import json
import os
import sys
import time

import numpy as np

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import cfs_common as C

D = os.path.join(C.OUT, "AI_Results", "exp3")
BCSD = os.path.join(C.OUT, "AI_Results", "bcsd.json")
OUT = "/home/tanpv/Progs/claude/HW_CFS_raw/ehd_cfs_compare_sd_ai.html"
WK = C.WEEK_NAMES
CSS = open(os.path.join(os.path.dirname(__file__), "_report_css.txt")).read()
TARGET = {"POD": (">", .6), "POFD": ("<", .2), "FAR": ("<", .2), "CSI": (">", .4)}
EVMET = ["POD", "POFD", "FAR", "FBI", "CSI", "SEDI", "AUC"]


def load_track(track):
    d = os.path.join(D, track)
    out = {}
    if not os.path.isdir(d):
        return out
    for f in sorted(os.listdir(d)):
        if f.startswith("pt") and f.endswith(".json"):
            out[int(f[2:4])] = json.load(open(os.path.join(d, f)))
    return out


def week_medians(R):
    """median over points of each event metric, per week (ensemble clf final)."""
    med = {}
    for w in WK:
        rows = []
        for i in R:
            r = R[i].get(w, {})
            if r.get("skip") or "clf" not in r:
                continue
            s = dict(r["clf"]["final"]); s["AUC"] = r["clf"]["AUC_p1"]
            rows.append(s)
        if rows:
            med[w] = {m: float(np.nanmedian([x[m] for x in rows])) for m in EVMET}
            med[w]["n"] = len(rows)
            med[w]["base"] = float(np.nanmedian([x["base"] for x in rows]))
    return med


def tcell(m, v, other=None):
    """colour by target box; bold if this track beats the other on this metric."""
    if not np.isfinite(v):
        return "<td>—</td>"
    cls = ""
    if m in TARGET:
        op, r = TARGET[m]
        ok = v > r if op == ">" else v < r
        cls = "good" if ok else "bad"
    txt = "%.3f" % v
    if other is not None and np.isfinite(other):
        better = (v > other) if m in ("POD", "CSI", "SEDI", "AUC") else \
                 (v < other) if m in ("POFD", "FAR") else \
                 (abs(v - 1) < abs(other - 1))          # FBI closest to 1 wins
        if better and abs(v - other) > 1e-9:
            txt = "<b>%s</b>" % txt
    return "<td class='%s'>%s</td>" % (cls, txt)


def value_table():
    if not os.path.exists(BCSD):
        return "<p>chưa có bcsd.json cho tầng giá trị.</p>"
    b = json.load(open(BCSD))
    H = ["<table><caption>Tầng giá trị (°C) trên năm kiểm định — D1 = BCSD "
         "(cơ sở cfs_0.25_sd), D2 = AI regression (cơ sở cfs_0.25_AI). "
         "exc_ratio = tần suất vượt ngưỡng mô hình / quan trắc (1 là lý tưởng).</caption>"
         "<tr><th>Tuần</th><th>PP</th><th>MAE</th><th>RMSE</th><th>CORR</th>"
         "<th>exc_ratio</th><th>POD</th><th>FAR</th><th>CSI</th></tr>"]
    for w in WK:
        if w not in b:
            continue
        for tag, nm in (("D1", "BCSD (sd)"), ("D2", "AI reg (AI)")):
            r = b[w][tag]
            H.append("<tr><td>%s</td><td>%s</td><td>%.2f</td><td>%.2f</td>"
                     "<td>%.3f</td><td>%.2f</td><td>%.3f</td><td>%.3f</td>"
                     "<td>%.3f</td></tr>"
                     % (w if tag == "D1" else "", nm, r["MAE"], r["RMSE"],
                        r["CORR"], r["exc_ratio"], r["POD"], r["FAR"], r["CSI"]))
    H.append("</table>")
    return "".join(H)


def verdict(msd, mai):
    """Count per-week wins on the four target metrics + AUC, event layer."""
    keys = ["POD", "POFD", "FAR", "FBI", "CSI", "AUC"]
    wins = {"sd": 0, "ai": 0}
    weeks = sorted(set(msd) & set(mai), key=WK.index)
    for w in weeks:
        for m in keys:
            a, b = msd[w][m], mai[w][m]
            if not (np.isfinite(a) and np.isfinite(b)) or abs(a - b) < 1e-9:
                continue
            better_sd = (a > b) if m in ("POD", "CSI", "AUC") else \
                        (a < b) if m in ("POFD", "FAR") else (abs(a - 1) < abs(b - 1))
            wins["sd" if better_sd else "ai"] += 1
    return wins, weeks


def main():
    Rsd, Rai = load_track("sd"), load_track("ai")
    msd, mai = week_medians(Rsd), week_medians(Rai)
    H = ["<!doctype html><html lang='vi'><meta charset='utf-8'>",
         "<title>So sánh cfs_0.25_sd vs cfs_0.25_AI</title><style>%s</style>" % CSS,
         "<h1>So sánh hai nhánh hạ quy mô: cfs_0.25_sd (BCSD) vs cfs_0.25_AI (AI)</h1>",
         "<p class='sub'>Chung cỗ máy ensemble N mô hình AI (P=M/N, quyết định 2 "
         "tầng). Khác biệt duy nhất: Tx tại điểm là BCSD (sd) hay CFS thô để AI tự "
         "học hạ quy mô (ai). Kiểm định 2001/2006/2009. Dựng %s.</p>"
         % time.strftime("%Y-%m-%d %H:%M"),
         "<div class='stamp'>sd: %d/21 điểm — ai: %d/21 điểm%s</div>"
         % (len(Rsd), len(Rai),
            "" if len(Rsd) == 21 == len(Rai) else "  (ARRAY CHƯA XONG — kết quả tạm)")]

    # ---- decision layer: event skill, side by side ----
    H.append("<h2>1. Tầng sự kiện EHDE (tầng quyết định) — median trên 21 điểm</h2>")
    H.append("<p class='sub'>Đậm = nhánh thắng ở chỉ số đó. Xanh/đỏ = đạt/không đạt "
             "mục tiêu (POD&gt;0.6, POFD&lt;0.2, FAR&lt;0.2, CSI&gt;0.4, FBI~1).</p>")
    H.append("<table><tr><th>Tuần</th><th>Nhánh</th><th>nền</th>"
             + "".join("<th>%s</th>" % m for m in EVMET) + "</tr>")
    for w in WK:
        for tag, M, Mo in (("sd (BCSD)", msd, mai), ("ai (AI)", mai, msd)):
            if w not in M:
                continue
            H.append("<tr><td>%s</td><td>%s</td><td>%.3f</td>%s</tr>"
                     % (w if tag.startswith("sd") else "", tag, M[w]["base"],
                        "".join(tcell(m, M[w][m],
                                      Mo[w][m] if w in Mo else None) for m in EVMET)))
    H.append("</table>")

    wins, weeks = verdict(msd, mai)
    if weeks:
        lead = "sd (BCSD)" if wins["sd"] > wins["ai"] else \
               "ai (AI)" if wins["ai"] > wins["sd"] else "hoà"
        H.append("<div class='note'>Đếm thắng theo tuần trên POD/POFD/FAR/FBI/CSI/AUC "
                 "(%d tuần có đủ hai nhánh): <b>sd %d — ai %d</b>. Dẫn: <b>%s</b>. "
                 "%s</div>"
                 % (len(weeks), wins["sd"], wins["ai"], lead,
                    "Kết quả tạm, chờ array xong để chốt." if
                    (len(Rsd) < 21 or len(Rai) < 21) else
                    "Đây là căn cứ chọn nhánh cho nghiệp vụ."))

    # ---- value layer ----
    H.append("<h2>2. Tầng giá trị (°C) — nền tảng hạ quy mô của mỗi nhánh</h2>")
    H.append(value_table())

    H.append("</html>")
    open(OUT, "w").write("\n".join(H))
    print("viet %s  (sd %d/21, ai %d/21)" % (OUT, len(Rsd), len(Rai)))


if __name__ == "__main__":
    main()
