"""[임시] 우리은행 라이브 데모 자율 검증 루프 — extract→automap→generate→LLM HTML→PNG.

targetReport/woori(원본) + woori_bg(배경)로 전체 파이프라인을 돌려 결과 HTML/PNG 를 생성한다.
extract 는 비싸므로 1회 캐시(/tmp/woori_loop/extract.json) 후 재사용한다.
"""
from __future__ import annotations

import base64
import json
import sys
from pathlib import Path

from app.services import catalog, pipeline
from app.services.render_llm import render_html_llm_from_dataurl, render_page_png

ROOT = Path(__file__).resolve().parent.parent.parent
WOORI = ROOT / "targetReport" / "woori" / "슬라이드1.png"
WOORI_BG = ROOT / "targetReport" / "woori_bg" / "슬라이드1.png"
TMP = Path("/tmp/woori_loop")
TMP.mkdir(exist_ok=True)
FUND = "226980"
DATASET = "woori_etf_demo"

# 컴포넌트 type/title → (table, columns 매핑, orderBy, limit)
#   columns 매핑: extract column label → woori 테이블 컬럼
COLLECTION_MAP = {
    "운용성과": {
        "table": "etf_performance_matrix", "orderBy": "category_order", "limit": None,
        "cols": {"구분": "category", "1M": "m1", "3M": "m3", "6M": "m6", "1Y": "y1", "연초이후": "ytd", "설정이후": "since"},
    },
    "수익률그래프": {
        "table": "etf_return_series", "orderBy": "date_order", "limit": None,
        "cols": {"기간": "date", "ETF": "etf_index", "벤치마크": "benchmark_index"},
    },
    "기본정보": {
        "table": "etf_basic_info", "orderBy": "order", "limit": None,
        "cols": {"항목": "label", "내용": "value"},
    },
    "구성현황": {
        "table": "etf_sector_weights", "orderBy": "sector_order", "limit": None,
        "cols": {"섹터": "sector", "비중(%)": "weight"},
    },
    "분배금": {
        "table": "etf_distributions", "orderBy": "order", "limit": None,
        "cols": {"지급기준일": "pay_date", "금액(원)": "amount"},
    },
}

FIELD_MAP = {
    "main_title": ("etf_master", "report_category"),
    "sub_title": ("etf_master", "fund_name"),
    "code": ("etf_master", "product_code"),
    "description": ("etf_master", "product_feature"),
    "risk_level": ("etf_master", "risk_grade"),
    "base_date": ("etf_master", "base_date"),
    "index_intro": ("etf_index_intro", "index_intro"),
    "index_desc": ("etf_index_intro", "index_intro"),
}
NARR = "etf_narrative_factors"
NARR_COLS = ["performance_summary", "market_context", "risk_factors", "defensive_factors", "outlook_points"]


def _match(title: str) -> dict | None:
    for key, cfg in COLLECTION_MAP.items():
        if key in (title or ""):
            return cfg
    return None


def _marketing_points() -> list[str]:
    p = catalog.get_product(FUND) or {}
    rows = sorted(p.get("etf_marketing_points", []), key=lambda r: r.get("order", 0))
    return [r.get("point", "") for r in rows]


def automap(ir: dict) -> dict:
    mkt = _marketing_points()
    for comp in ir["report"]["components"]:
        spec = comp.get("dataSpec") or {}
        is_marketing = "마케팅" in (comp.get("title") or "")
        mkt_idx = 0
        for f in spec.get("fields", []) or []:
            if f.get("binding"):
                continue
            key = f.get("key")
            if is_marketing and mkt_idx < len(mkt):
                f["binding"] = {"source": "manual", "value": mkt[mkt_idx]}
                f["role"] = "scalar"
                mkt_idx += 1
            elif key in FIELD_MAP:
                t, c = FIELD_MAP[key]
                f["binding"] = {"source": "column", "table": t, "column": c}
            elif f.get("role") == "narrative_input" or f.get("dataType") == "text":
                f["binding"] = {"source": "columns", "refs": [{"table": NARR, "column": c} for c in NARR_COLS]}
            else:
                f["binding"] = {"source": "manual", "value": f.get("label", "")}
        coll = spec.get("collection")
        if coll and coll.get("enabled"):
            cfg = _match(comp.get("title", ""))
            if not cfg:
                continue
            coll["datasetId"] = DATASET
            coll["table"] = cfg["table"]
            coll["orderBy"] = cfg["orderBy"]
            coll["orderDir"] = "asc"
            coll["limit"] = cfg["limit"]
            for col in coll.get("columns", []) or []:
                if not col.get("column"):
                    col["column"] = cfg["cols"].get(col.get("label"))
    return ir


def main() -> int:
    catalog.load_product_data.cache_clear()
    ex_path = TMP / "extract.json"
    if "--reextract" in sys.argv or not ex_path.exists():
        b64 = base64.b64encode(WOORI.read_bytes()).decode()
        ex = pipeline.run_extract(b64, "image/png")
        ex_path.write_text(json.dumps(ex, ensure_ascii=False, indent=2), encoding="utf-8")
    ex = json.loads(ex_path.read_text(encoding="utf-8"))

    mapped = automap(json.loads(json.dumps(ex["ir"])))
    gen = pipeline.run_generate(mapped, FUND)
    (TMP / "generate.json").write_text(json.dumps(gen, ensure_ascii=False, indent=2), encoding="utf-8")
    print("warnings:", gen.get("warnings"))

    ref = "data:image/png;base64," + base64.b64encode(WOORI.read_bytes()).decode()
    bg = "data:image/png;base64," + base64.b64encode(WOORI_BG.read_bytes()).decode()
    html, w = render_html_llm_from_dataurl(gen["view"], ref, bg)
    (TMP / "report.html").write_text(html, encoding="utf-8")
    print("html len:", len(html), "| html warnings:", w)
    png = render_page_png(html)
    (TMP / "report.png").write_bytes(png)
    print("png bytes:", len(png))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
