# -*- coding: utf-8 -*-
"""
STEP110-01 Draft Quality Checker

목적:
- 운영 초안/테스트 초안의 품질을 자동 점검한다.
- 기존 운영 초안보다 나빠지는 업데이트를 막기 위한 회귀 검사 도구다.

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

  draft_id 기준:
  python tools\check_draft_quality.py --draft-id 208

  article_no 기준 최신 초안:
  python tools\check_draft_quality.py --realtor-id 1 --article-no 2633019803

  여러 건은 각각 실행 권장.
"""

import argparse
import re
import sys
import json
from pathlib import Path
from html import unescape

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

from db import get_conn


def clean_text(value):
    value = "" if value is None else str(value)
    value = unescape(value)
    value = re.sub(r"<[^>]+>", " ", value)
    value = re.sub(r"\s+", " ", value)
    return value.strip()


def fetch_draft(conn, draft_id=None, realtor_id=None, article_no=None):
    with conn.cursor() as cur:
        if draft_id:
            cur.execute("""
                SELECT *
                FROM blog_article_drafts
                WHERE id=%s
                LIMIT 1
            """, (int(draft_id),))
            return cur.fetchone()

        cur.execute("""
            SELECT *
            FROM blog_article_drafts
            WHERE realtor_id=%s
              AND article_no=%s
            ORDER BY id DESC
            LIMIT 1
        """, (int(realtor_id), str(article_no)))
        return cur.fetchone()


def count_images(html):
    return len(re.findall(r"<img\b", html or "", flags=re.I))


def has_any(html, patterns):
    src = html or ""
    for p in patterns:
        if re.search(p, src, flags=re.I | re.S):
            return True
    return False


def extract_broker_description_text(html):
    html = html or ""
    m = re.search(
        r"중개사\s*매물설명.*?<div[^>]*font-size:16px[^>]*>(.*?)</div>",
        html,
        flags=re.I | re.S,
    )
    if not m:
        m = re.search(
            r"중개사\s*매물설명(.*?)(?:상담\s*및\s*중개사\s*안내|중개대상물\s*표시|realestate-realtor-map-image)",
            html,
            flags=re.I | re.S,
        )
    if not m:
        return ""
    return clean_text(m.group(1))


def score_quality(draft):
    html = draft.get("clipboard_html") or draft.get("draft_html") or ""
    text = clean_text(html)
    broker_desc = extract_broker_description_text(html)
    image_count = count_images(html)

    checks = []

    def add(name, ok, score, message):
        checks.append({
            "name": name,
            "ok": bool(ok),
            "score": int(score if ok else 0),
            "max_score": int(score),
            "message": message,
        })

    add(
        "대표이미지",
        has_any(html, [r"realestate-representative-image", r"header_.*?\.png"]),
        15,
        "대표이미지 블록 또는 header 이미지가 있어야 합니다.",
    )

    add(
        "중개사 지도",
        has_any(html, [r"realestate-realtor-map-image", r"realtor_naver_map_"]),
        15,
        "중개사 지도 이미지가 포함되어야 합니다.",
    )

    add(
        "중개사 매물설명",
        bool(broker_desc),
        15,
        f"중개사 매물설명 길이={len(broker_desc)}",
    )

    add(
        "매물설명 충분성",
        len(broker_desc) >= 40,
        10,
        f"중개사 매물설명이 너무 짧으면 품질이 낮습니다. 현재={len(broker_desc)}자",
    )

    add(
        "소재지",
        "소재지" in text and not re.search(r"소재지\s*확인\s*필요", text),
        10,
        "소재지가 명시되어야 합니다.",
    )

    add(
        "법정 표시사항",
        has_any(html, [r"realestate-legal-disclosure-table", r"중개대상물\s*표시"]),
        10,
        "중개대상물 표시·광고 명시사항이 필요합니다.",
    )

    add(
        "평면도",
        has_any(html, [r"평면도", r"floorplan", r"photoinfra"]),
        8,
        "평면도 또는 구조 이미지가 있으면 좋습니다.",
    )

    add(
        "이미지 개수",
        image_count >= 4,
        7,
        f"이미지 수={image_count}. 최소 4장 이상 권장.",
    )

    add(
        "중개사 정보 완성도",
        "확인 필요" not in text,
        5,
        "'확인 필요'가 포함되면 운영 품질이 낮습니다.",
    )

    add(
        "SEO footer",
        has_any(html, [r"realestate-seo-footer", r"관련\s*키워드"]),
        5,
        "SEO footer 또는 관련 키워드가 포함되면 좋습니다.",
    )

    total = sum(x["score"] for x in checks)
    max_total = sum(x["max_score"] for x in checks)

    grade = "A"
    if total < 90:
        grade = "B"
    if total < 75:
        grade = "C"
    if total < 60:
        grade = "D"

    return {
        "draft_id": draft.get("id"),
        "realtor_id": draft.get("realtor_id"),
        "article_no": draft.get("article_no"),
        "draft_title": draft.get("draft_title"),
        "image_count": image_count,
        "broker_description_length": len(broker_desc),
        "score": total,
        "max_score": max_total,
        "grade": grade,
        "checks": checks,
    }


def print_report(report):
    print("=" * 80)
    print("[STEP110 DRAFT QUALITY REPORT]")
    print("draft_id:", report.get("draft_id"))
    print("realtor_id:", report.get("realtor_id"))
    print("article_no:", report.get("article_no"))
    print("title:", report.get("draft_title"))
    print("score:", f"{report.get('score')}/{report.get('max_score')}")
    print("grade:", report.get("grade"))
    print("image_count:", report.get("image_count"))
    print("broker_description_length:", report.get("broker_description_length"))
    print("-" * 80)

    for item in report["checks"]:
        mark = "OK" if item["ok"] else "FAIL"
        print(f"[{mark}] {item['name']} ({item['score']}/{item['max_score']}) - {item['message']}")

    print("=" * 80)

    if report["grade"] in ["C", "D"]:
        print("[QUALITY WARNING] 운영 반영 전 보완 필요")
    else:
        print("[QUALITY OK] 기본 품질 기준 통과")


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--draft-id", type=int, default=None)
    parser.add_argument("--realtor-id", type=int, default=None)
    parser.add_argument("--article-no", default="")
    parser.add_argument("--json", action="store_true")
    args = parser.parse_args()

    if not args.draft_id and not (args.realtor_id and args.article_no):
        raise RuntimeError("--draft-id 또는 --realtor-id + --article-no 필요")

    conn = get_conn()

    try:
        draft = fetch_draft(
            conn,
            draft_id=args.draft_id,
            realtor_id=args.realtor_id,
            article_no=args.article_no,
        )

        if not draft:
            raise RuntimeError("draft not found")

        report = score_quality(draft)

        if args.json:
            print(json.dumps(report, ensure_ascii=False, indent=2, default=str))
        else:
            print_report(report)

    finally:
        conn.close()


if __name__ == "__main__":
    main()
