"""
C-6111 (6-1차 측류 정제 컬럼) 데이터 추출 + 운전모드 1차 특성 분석.

field_hist DB(shinam 실데이터, WIDE 포맷)에서 ptlist/mapping/tblist로 태그를 디코드해
tidy DataFrame을 만든다. 재사용 가능한 tag_frame() 추출기 포함.

근거: docs/학습형제어-오퍼레이터모방-플랜.md §15(디코드), §16(C-6111 토폴로지).
"""
import sys
import psycopg
import pandas as pd

DSN = "host=localhost port=5432 dbname=field_hist user=postgres password=postgres"
ASSET = "/ASSETS/P6"

# C-6111 역할별 태그 (ff_column_config/ff_stream_config + 사용자 도메인, 플랜 §16.1)
ROLES = {
    "feed":          "FICQ-6101.PV",   # 피드(주 외란)
    "steam_op":      "TICA-6111A.OP",  # 리보일러 스팀 밸브(조작/OP)
    "steam_flow":    "FIQ-6115.PV",    # 실제 스팀 유량
    "reb_temp":      "TICA-6111A.PV",  # 리보일러 온도(A, 최고온)
    "T_B":           "TI-6111B.PV",    # 피드존
    "T_C":           "TI-6111C.PV",    # 민감단(제품 추출 트레이 근처)
    "T_D":           "TI-6111D.PV",    # 탑상(최저온)
    "feed_preheat":  "TI-6103.PV",     # 원료 예열
    "vacuum":        "PICA-6111.PV",   # 진공압력
    "dp":            "PI-6111B.PV",    # 컬럼 차압
    "product":       "FICQ-6118.PV",   # 측류 제품 P
    "reflux":        "FICQ-6113.PV",   # 리플럭스 R
    "light":         "FICQ-6114.PV",   # 경질분 제거 D
    "heavy":         "FICQ-6116.PV",   # 중질분 제거 B
    "reb_level":     "LI-6111.PV",     # 리보일러 레벨
    "reflux_drum":   "LICA-6113.PV",   # 리플럭스 드럼 레벨
}


def resolve(conn, shorttags, asset=ASSET):
    """shortptname 목록 -> {tag: (tblname, colnum)}"""
    with conn.cursor() as cur:
        cur.execute("""
            SELECT p.shortptname, t.tblname, m.oit
            FROM ptlist p JOIN mapping m ON m.pid=p.pid JOIN tblist t ON t.tid=m.tid
            WHERE p.asset=%s AND p.shortptname = ANY(%s)
        """, (asset, list(shorttags)))
        out = {}
        for short, tbl, oit in cur.fetchall():
            out[short] = (tbl, int(oit))
    return out


def tag_frame(conn, role_map, asset=ASSET):
    """{role: shorttag} -> dtat 인덱스 DataFrame(컬럼=role). 테이블별 1쿼리 후 merge."""
    loc = resolve(conn, role_map.values(), asset)
    missing = [r for r, t in role_map.items() if t not in loc]
    if missing:
        print(f"[warn] 미해결 태그: {[(r, role_map[r]) for r in missing]}", file=sys.stderr)
    # 테이블별 그룹
    by_tbl = {}
    for role, short in role_map.items():
        if short not in loc:
            continue
        tbl, col = loc[short]
        by_tbl.setdefault(tbl, []).append((role, col))
    df = None
    for tbl, cols in by_tbl.items():
        sel = ", ".join([f'col{c:02d} AS "{role}"' for role, c in cols])
        q = f"SELECT dtat, {sel} FROM {tbl}"
        part = pd.read_sql(q, conn)
        df = part if df is None else df.merge(part, on="dtat", how="outer")
    return df.sort_values("dtat").reset_index(drop=True)


def classify_phases(df):
    """1차 운전모드 분류 (임계 기반, §16.3-2). 추후 정교화."""
    import numpy as np
    reb, vac, steam, prod = df["reb_temp"], df["vacuum"], df["steam_op"], df["product"]
    hot_vac = (reb > 60) & (vac < 200) & (steam > 5)   # 컬럼 가동(hot+진공)
    # 온도 추세(60분=120샘플 기울기)로 startup/shutdown 구분
    slope = reb.diff().rolling(120, min_periods=10, center=True).mean()
    mode = np.where(
        hot_vac,
        np.where(prod < 80, "LINEOUT", "PROD"),       # 제품≈0 → 전환류/라인아웃
        np.where(slope > 0.02, "STARTUP",
                 np.where(slope < -0.02, "SHUTDOWN", "STOPPED")))
    return pd.Series(mode, index=df.index, name="mode")


def plot_timeline(df, png):
    import matplotlib
    matplotlib.use("Agg")
    import matplotlib.pyplot as plt
    d = df.iloc[::30].copy()      # 15분 다운샘플
    colors = {"PROD": "#2ca02c", "LINEOUT": "#ff7f0e", "STARTUP": "#1f77b4",
              "SHUTDOWN": "#d62728", "STOPPED": "#7f7f7f"}
    fig, ax = plt.subplots(5, 1, figsize=(16, 12), sharex=True)
    ax[0].plot(d.dtat, d.reb_temp, lw=.5, label="reb_temp(A)")
    ax[0].plot(d.dtat, d.T_C, lw=.5, label="T_C(민감단)")
    ax[0].plot(d.dtat, d.T_D, lw=.5, label="T_D(탑상)")
    ax[0].set_ylabel("온도"); ax[0].legend(loc="upper right", fontsize=7)
    ax[1].plot(d.dtat, d.feed, lw=.5, color="purple"); ax[1].set_ylabel("feed FICQ-6101")
    ax[2].plot(d.dtat, d["product"], lw=.5, color="orange"); ax[2].set_ylabel("측류제품 6118")
    ax[3].plot(d.dtat, d.steam_flow, lw=.5, color="red")
    ax[3].plot(d.dtat, d.steam_op * 10, lw=.5, color="brown", alpha=.5, label="OP×10")
    ax[3].set_ylabel("스팀유량/OP"); ax[3].legend(loc="upper right", fontsize=7)
    ax[4].plot(d.dtat, d.vacuum, lw=.5, color="teal"); ax[4].set_ylabel("진공 PICA-6111")
    ax[4].set_ylim(100, 130)
    # 모드 배경 음영
    for a in ax:
        for m, c in colors.items():
            seg = d[d["mode"] == m]
            a.scatter(seg.dtat, [a.get_ylim()[0]] * len(seg), c=c, s=2, marker="|")
    fig.suptitle("C-6111 (6-1차) 전체기간 — 운전모드별 (하단 컬러바)")
    fig.tight_layout()
    fig.savefig(png, dpi=90)
    print(f"플롯 저장: {png}")


def main():
    with psycopg.connect(DSN) as conn:
        df = tag_frame(conn, ROLES)
    print(f"행수={len(df)}  기간={df.dtat.min()} ~ {df.dtat.max()}")
    print("\n=== 핵심 신호 분포 (운전모드 임계 설정용) ===")
    show = ["feed", "reb_temp", "vacuum", "product", "reflux", "steam_op",
            "steam_flow", "T_C", "T_D", "dp"]
    desc = df[show].describe(percentiles=[.01, .05, .25, .5, .75, .95, .99]).T
    print(desc[["min", "1%", "5%", "50%", "95%", "99%", "max"]].round(2).to_string())

    df["mode"] = classify_phases(df)
    print("\n=== 운전모드 분포 (30초 샘플 기준) ===")
    vc = df["mode"].value_counts()
    for m, n in vc.items():
        print(f"  {m:9s} {n:7d}  {100*n/len(df):5.1f}%  ≈ {n*30/3600:7.1f} h")

    out = "/home/windpacer/projects/hc900_ax/scripts/analysis/c6111_data.pkl"
    df.to_pickle(out)
    plot_timeline(df, "/home/windpacer/projects/hc900_ax/scripts/analysis/c6111_timeline.png")
    print(f"저장: {out}")


if __name__ == "__main__":
    main()
