# -*- coding: utf-8 -*-
"""
STEP110-04 Happy Realtor Full Pipeline Orchestrator v2

원칙:
- 운영중인 기존 시스템은 그대로 둔다.
- 행복공인 테스트 계정(realtor_id=1)만 사용한다.
- 상위 오케스트레이터는 운영 DB 스키마를 과하게 직접 참조하지 않는다.
- 검증된 하위 실행 파일을 연결한다.

흐름:
  STEP108 workday collect/fetch
  -> STEP109 draft engine
  -> quality check v2
  -> PASS 시에만 선택적으로 publish

사용:
  cd /d D:\honghee\blog_api

  상태만 확인:
  python jobs\test_happy_realtor_full_pipeline.py --dry-run

  수집/상세수집/초안/품질검사:
  python jobs\test_happy_realtor_full_pipeline.py

  이미 수집된 특정 매물로 초안/품질검사:
  python jobs\test_happy_realtor_full_pipeline.py --skip-workday --article-no 2633019770

  품질 PASS 시 실제 테스트 발행:
  python jobs\test_happy_realtor_full_pipeline.py --publish
"""

import argparse
import json
import subprocess
import sys
from pathlib import Path
from datetime import datetime

BASE_DIR = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(BASE_DIR))

from db import get_conn

REALTOR_ID = 1
PYTHON = sys.executable

WORKDAY_JOB = BASE_DIR / "jobs" / "run_one_realtor_workday.py"
DRAFT_ENGINE_JOB = BASE_DIR / "jobs" / "test_draft_engine.py"
QUALITY_TOOL = BASE_DIR / "tools" / "check_draft_quality_v2.py"
PUBLISH_ONE_JOB = BASE_DIR / "workers" / "publish_one_queue_step105.py"


def log(*args):
    print(*args, flush=True)


def safe_json(obj):
    return json.dumps(obj or {}, ensure_ascii=False, default=str)


def run_cmd(label, cmd, timeout=3600, capture=False, allow_fail=False):
    log("=" * 80)
    log(f"[RUN START] {label}")
    log("[CMD]", " ".join(str(x) for x in cmd))
    log("=" * 80)

    result = subprocess.run(
        cmd,
        cwd=str(BASE_DIR),
        text=True,
        encoding="utf-8",
        errors="replace",
        timeout=timeout,
        capture_output=capture,
    )

    if capture:
        if result.stdout:
            log("[STDOUT]", result.stdout[-3000:])
        if result.stderr:
            log("[STDERR]", result.stderr[-3000:])

    log("=" * 80)
    log(f"[RUN END] {label} returncode={result.returncode}")
    log("=" * 80)

    if result.returncode != 0 and not allow_fail:
        raise RuntimeError(f"{label} failed returncode={result.returncode}")

    return result


def fetch_latest_pending_queue():
    """
    최소한의 공통 컬럼만 조회한다.
    """
    conn = get_conn()
    try:
        with conn.cursor() as cur:
            cur.execute(
                """
                SELECT
                    q.id AS queue_id,
                    q.realtor_id,
                    q.draft_id,
                    q.article_no,
                    q.queue_status,
                    q.created_at,
                    d.draft_title
                FROM blog_publish_queue q
                LEFT JOIN blog_article_drafts d ON d.id=q.draft_id
                WHERE q.realtor_id=%s
                  AND q.queue_status='pending'
                ORDER BY q.id DESC
                LIMIT 1
                """,
                (REALTOR_ID,),
            )
            return cur.fetchone()
    finally:
        conn.close()


def fetch_latest_draft():
    conn = get_conn()
    try:
        with conn.cursor() as cur:
            cur.execute(
                """
                SELECT
                    id,
                    realtor_id,
                    article_no,
                    draft_title,
                    created_at
                FROM blog_article_drafts
                WHERE realtor_id=%s
                ORDER BY id DESC
                LIMIT 1
                """,
                (REALTOR_ID,),
            )
            return cur.fetchone()
    finally:
        conn.close()


def quality_json(draft_id):
    result = subprocess.run(
        [
            PYTHON,
            str(QUALITY_TOOL),
            "--draft-id",
            str(draft_id),
            "--json",
        ],
        cwd=str(BASE_DIR),
        text=True,
        encoding="utf-8",
        errors="replace",
        capture_output=True,
        timeout=600,
    )

    if result.returncode != 0:
        raise RuntimeError("quality tool failed: " + (result.stderr or result.stdout or ""))

    return json.loads(result.stdout)


def print_quality_summary(report):
    log("=" * 80)
    log("[QUALITY SUMMARY]")
    log("draft_id:", report.get("draft_id"))
    log("article_no:", report.get("article_no"))
    log("score:", f"{report.get('score')}/{report.get('max_score')}")
    log("grade:", report.get("grade"))
    log("publish_allowed:", report.get("publish_allowed"))
    log("critical_count:", report.get("critical_count"))

    if report.get("criticals"):
        log("[CRITICALS]")
        for c in report.get("criticals") or []:
            log("-", c.get("name"), c.get("message"))

    if report.get("warnings"):
        log("[WARNINGS]")
        for w in report.get("warnings") or []:
            log("-", w)

    log("=" * 80)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--dry-run", action="store_true")
    parser.add_argument("--publish", action="store_true")
    parser.add_argument("--skip-workday", action="store_true")
    parser.add_argument("--article-no", default="")
    args = parser.parse_args()

    log("=" * 80)
    log("[STEP110-04 HAPPY REALTOR ORCHESTRATOR V2 START]")
    log("TIME:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    log("realtor_id:", REALTOR_ID)
    log("dry_run:", args.dry_run)
    log("publish:", args.publish)
    log("skip_workday:", args.skip_workday)
    log("article_no:", args.article_no or "(latest)")
    log("=" * 80)

    before_queue = fetch_latest_pending_queue()
    before_draft = fetch_latest_draft()

    log("[BEFORE QUEUE]", safe_json(before_queue))
    log("[BEFORE DRAFT]", safe_json(before_draft))

    if args.dry_run:
        log("[DRY RUN] no actual work executed")
        log("[STEP110-04 DONE]")
        return

    # 1) 수집/상세수집은 기존 STEP108에 맡긴다.
    if not args.skip_workday:
        run_cmd(
            "STEP108 workday collect/fetch",
            [
                PYTHON,
                str(WORKDAY_JOB),
                "--realtor-id",
                str(REALTOR_ID),
                "--skip-draft",
                "--skip-publish",
            ],
            timeout=3600,
        )

    # 2) 초안 생성은 STEP109 Draft Engine에 맡긴다.
    draft_cmd = [
        PYTHON,
        str(DRAFT_ENGINE_JOB),
        "--realtor-id",
        str(REALTOR_ID),
    ]

    if args.article_no:
        draft_cmd += ["--article-no", args.article_no]

    run_cmd(
        "STEP109 draft engine",
        draft_cmd,
        timeout=3600,
    )

    # 3) 최신 pending queue 확인
    queue = fetch_latest_pending_queue()
    if not queue:
        raise RuntimeError("pending queue not found after draft generation")

    log("[AFTER QUEUE]", safe_json(queue))

    draft_id = queue.get("draft_id")
    queue_id = queue.get("queue_id")

    if not draft_id:
        raise RuntimeError("draft_id empty in latest pending queue")

    # 4) 품질 검사
    report = quality_json(draft_id)
    print_quality_summary(report)

    if not report.get("publish_allowed"):
        log("[PUBLISH BLOCKED] quality check failed")
        log("[STEP110-04 DONE WITH QUALITY BLOCK]")
        return

    # 5) 발행은 명시 옵션 있을 때만
    if not args.publish:
        log("[PUBLISH SKIP] quality passed but --publish not provided")
        log("[STEP110-04 DONE WITHOUT PUBLISH]")
        return

    run_cmd(
        "STEP105 publish one queue",
        [
            PYTHON,
            str(PUBLISH_ONE_JOB),
            "--queue-id",
            str(queue_id),
            "--require-test-account",
        ],
        timeout=3600,
    )

    log("[STEP110-04 HAPPY REALTOR ORCHESTRATOR V2 DONE]")


if __name__ == "__main__":
    main()
