"""
04단계 PDCA 파이프라인: 프로필 → 스캔 → 라벨 → 선별.
"""

from __future__ import annotations

import argparse
import json
import sys
import time
from pathlib import Path

import pandas as pd

from config import CHART_LOOKBACK_DAYS, SYMBOL
from deepcoin.data.mtf_bb import load_frames_from_db
from deepcoin.matching.config import (
    MATCHING_BACKTEST_HTML,
    MATCHING_FIRE_OUTCOMES,
    MATCHING_GT_OVERLAP,
    MATCHING_MATCHED_RULES,
    MATCHING_RULE_CANDIDATES,
    MATCHING_RULE_FIRES,
)
from deepcoin.matching.label_outcomes import label_fire_outcomes
from deepcoin.matching.profile_rules import build_rule_candidates, save_rule_candidates
from deepcoin.matching.rule_eval import (
    build_mtf_scan_frame,
    conditions_columns,
    scan_rule_fires,
)
from deepcoin.matching.select_rules import (
    select_matched_rules,
    write_backtest_summary_html,
)
from deepcoin.ops.monitor import Monitor
from deepcoin.paths import ensure_dirs


def run_matching_pipeline(
    phase: str = "all",
    trades_csv: Path | None = None,
) -> None:
    """
    04a~04d 단계를 순서대로 실행합니다.

    Args:
        phase: all | profile | scan | label | select.
        trades_csv: 03b CSV 경로(선택).
    """
    ensure_dirs()
    t0 = time.time()
    from config import MATCH_INCLUDE_ATOMIC, MATCH_LABEL_MODE

    print(
        f"=== 04 매칭 파이프라인 {SYMBOL} "
        f"(label={MATCH_LABEL_MODE}, atomic={MATCH_INCLUDE_ATOMIC}) ==="
    )
    sys.stdout.flush()

    candidates_path = MATCHING_RULE_CANDIDATES
    fires_path = MATCHING_RULE_FIRES
    outcomes_path = MATCHING_FIRE_OUTCOMES

    candidates: dict | None = None
    fires: pd.DataFrame | None = None
    outcomes: pd.DataFrame | None = None
    frames = None

    if phase in ("all", "profile"):
        print("[04] Phase 4-1 Plan/Do: GT 프로필 → 규칙 후보")
        candidates = build_rule_candidates(trades_csv)
        save_rule_candidates(candidates, candidates_path)
        if phase == "profile":
            return

    if phase in ("all", "scan", "label"):
        if candidates is None:
            candidates = json.loads(candidates_path.read_text(encoding="utf-8"))
        rules = candidates.get("rules", [])
        print(f"[04] Phase 4-2 Do: 전구간 발화 스캔 ({len(rules)}규칙)")
        sys.stdout.flush()
        mon = Monitor(cooldown_file=None)
        frames = load_frames_from_db(mon, SYMBOL, lookback_days=CHART_LOOKBACK_DAYS)
        needed = conditions_columns(rules)
        scan_frame = build_mtf_scan_frame(frames, needed)
        fires = scan_rule_fires(scan_frame, rules)
        fires_path.parent.mkdir(parents=True, exist_ok=True)
        fires.to_csv(fires_path, index=False, encoding="utf-8-sig")
        print(f"[04-2] 저장: {fires_path} ({len(fires):,}행)")
        if phase == "scan":
            return

    if phase in ("all", "label", "select"):
        if fires is None:
            fires = pd.read_csv(fires_path)
        if phase in ("all", "label"):
            print("[04] Phase 4-3 Check: 발화별 forward PnL 라벨")
            if frames is None:
                mon = Monitor(cooldown_file=None)
                frames = load_frames_from_db(mon, SYMBOL, lookback_days=CHART_LOOKBACK_DAYS)
            outcomes = label_fire_outcomes(fires, frames)
            outcomes.to_csv(outcomes_path, index=False, encoding="utf-8-sig")
            print(f"[04-3] 저장: {outcomes_path}")
            if phase == "label":
                return

    if phase in ("all", "select"):
        if candidates is None:
            candidates = json.loads(candidates_path.read_text(encoding="utf-8"))
        if outcomes is None:
            outcomes = pd.read_csv(outcomes_path)
        print("[04] Phase 4-4 Act: EV 필터·규칙 선별")
        matched = select_matched_rules(outcomes, candidates)
        MATCHING_MATCHED_RULES.parent.mkdir(parents=True, exist_ok=True)
        MATCHING_MATCHED_RULES.write_text(
            json.dumps(matched, ensure_ascii=False, indent=2),
            encoding="utf-8",
        )
        print(f"[04-4] 저장: {MATCHING_MATCHED_RULES}")
        overlap = matched.get("gt_overlap", {})
        MATCHING_GT_OVERLAP.write_text(
            json.dumps(overlap, ensure_ascii=False, indent=2),
            encoding="utf-8",
        )
        write_backtest_summary_html(matched, MATCHING_BACKTEST_HTML)
        print(f"완료 ({time.time() - t0:.0f}초)")


def main() -> None:
    """CLI 진입."""
    parser = argparse.ArgumentParser(description="04 GT+EV 매칭 파이프라인")
    parser.add_argument(
        "--phase",
        choices=("all", "profile", "scan", "label", "select"),
        default="all",
    )
    parser.add_argument("--trades-csv", type=str, default="")
    args = parser.parse_args()
    csv = Path(args.trades_csv) if args.trades_csv else None
    run_matching_pipeline(phase=args.phase, trades_csv=csv)


if __name__ == "__main__":
    main()
