# -*- coding: utf-8 -*-
"""
STEP105-03: Tail Comment property detection + length reinforcement patch.

Run:
  cd /d D:\honghee\blog_api
  python tools\patch_tail_comment_detection_v2.py
"""

from pathlib import Path
from datetime import datetime

ROOT = Path(__file__).resolve().parents[1]
TARGET = ROOT / "workers" / "publish_modules" / "tail_comment.py"

if not TARGET.exists():
    raise FileNotFoundError(TARGET)

backup = TARGET.with_name(f"tail_comment_backup_detection_v2_{datetime.now().strftime('%Y%m%d_%H%M%S')}.py")
backup.write_text(TARGET.read_text(encoding="utf-8", errors="replace"), encoding="utf-8")
print("[BACKUP]", backup)

new_text = """# -*- coding: utf-8 -*-

import random
import json
import sys
from pathlib import Path

try:
    from .human_typing import human_type_text
    from .human_profile import (
        get_human_profile,
        get_typing_config,
        detect_property_type_from_context,
        normalize_property_type,
        build_profile_tail_comment,
    )
except Exception:
    from human_typing import human_type_text
    from human_profile import (
        get_human_profile,
        get_typing_config,
        detect_property_type_from_context,
        normalize_property_type,
        build_profile_tail_comment,
    )


BASE_DIR = Path(__file__).resolve().parents[2]
if str(BASE_DIR) not in sys.path:
    sys.path.append(str(BASE_DIR))


def _safe_get(row, key, default=""):
    if not row:
        return default

    try:
        if isinstance(row, dict):
            return row.get(key, default)
        return getattr(row, key, default)
    except Exception:
        return default


def _parse_json_maybe(value):
    if not value:
        return {}

    if isinstance(value, dict):
        return value

    try:
        return json.loads(str(value))
    except Exception:
        return {}


def _get_conn():
    try:
        from db import get_conn
        return get_conn()
    except Exception as e:
        print("[TAIL DB WARN] get_conn failed:", str(e))
        return None


def _fetch_one(cur, sql, params):
    try:
        cur.execute(sql, params)
        return cur.fetchone() or {}
    except Exception:
        return {}


def load_tail_context_from_db(queue=None):
    queue = queue or {}
    draft_id = _safe_get(queue, "draft_id")
    article_no = _safe_get(queue, "article_no")
    realtor_id = _safe_get(queue, "realtor_id")

    result = {
        "queue": dict(queue) if isinstance(queue, dict) else {},
        "draft": {},
        "article": {},
        "realtor": {},
    }

    conn = _get_conn()
    if not conn:
        return result

    try:
        with conn.cursor() as cur:
            if draft_id:
                result["draft"] = _fetch_one(
                    cur,
                    "SELECT * FROM blog_article_drafts WHERE id=%s LIMIT 1",
                    (draft_id,),
                )

            if not article_no:
                article_no = _safe_get(result["draft"], "article_no")

            if article_no:
                result["article"] = _fetch_one(
                    cur,
                    "SELECT * FROM blog_realtor_articles WHERE article_no=%s LIMIT 1",
                    (article_no,),
                )

            if realtor_id:
                result["realtor"] = _fetch_one(
                    cur,
                    "SELECT * FROM blog_realtors WHERE id=%s LIMIT 1",
                    (realtor_id,),
                )

    except Exception as e:
        print("[TAIL DB WARN] context load failed:", str(e))
    finally:
        try:
            conn.close()
        except Exception:
            pass

    return result


def detect_property_type_v2(draft=None, queue=None, article=None):
    draft = draft or {}
    queue = queue or {}
    article = article or {}

    source_json = _parse_json_maybe(_safe_get(draft, "source_json"))
    detail = {}
    if isinstance(source_json, dict):
        detail = source_json.get("detail") or source_json.get("article_detail") or {}

    candidates = [
        _safe_get(draft, "property_type"),
        _safe_get(draft, "real_estate_type"),
        _safe_get(draft, "real_estate_type_name"),
        _safe_get(draft, "article_type"),
        _safe_get(draft, "article_name"),
        _safe_get(draft, "draft_title"),
        _safe_get(article, "property_type"),
        _safe_get(article, "real_estate_type"),
        _safe_get(article, "real_estate_type_name"),
        _safe_get(article, "article_type"),
        _safe_get(article, "article_type_name"),
        _safe_get(article, "realestate_type_code"),
        _safe_get(article, "realestate_type_name"),
        _safe_get(article, "article_name"),
        _safe_get(article, "article_title"),
        _safe_get(article, "building_type_name"),
        _safe_get(article, "trade_building_type_code"),
        _safe_get(queue, "publish_title"),
        _safe_get(queue, "article_no"),
    ]

    if isinstance(detail, dict):
        candidates.extend([
            detail.get("realestateTypeName"),
            detail.get("realestateTypeCode"),
            detail.get("articleTypeCode"),
            detail.get("articleName"),
            detail.get("articleSubName"),
            detail.get("buildingTypeName"),
            detail.get("lawUsage"),
            detail.get("principalUse"),
        ])

    merged = " ".join([str(x or "") for x in candidates])
    normalized = normalize_property_type(merged)

    upper = merged.upper()
    if normalized == "default":
        if any(x in upper for x in ["APT", "ABYG", "JGC"]):
            normalized = "apartment"
        elif any(x in upper for x in ["OPST", "OFFICETEL"]):
            normalized = "officetel"
        elif any(x in upper for x in ["VL", "DDDGG", "JWJT"]):
            normalized = "villa"

    if normalized == "default":
        if any(x in merged for x in ["다가구", "단독주택", "상가주택", "주택"]):
            normalized = "building"
        elif any(x in merged for x in ["아파트", "맨션"]):
            normalized = "apartment"
        elif any(x in merged for x in ["상가", "점포", "사무실"]):
            normalized = "store"
        elif any(x in merged for x in ["토지", "대지", "임야", "전답"]):
            normalized = "land"

    return normalized


def _build_context(draft=None, queue=None, article=None, realtor=None, property_type=""):
    draft = draft or {}
    queue = queue or {}
    article = article or {}
    realtor = realtor or {}

    source_json = _parse_json_maybe(_safe_get(draft, "source_json"))
    detail = {}
    if isinstance(source_json, dict):
        detail = source_json.get("detail") or source_json.get("article_detail") or {}

    title = (
        _safe_get(draft, "draft_title")
        or _safe_get(article, "article_name")
        or (detail.get("articleName") if isinstance(detail, dict) else "")
        or _safe_get(queue, "publish_title")
        or _safe_get(queue, "article_no")
        or "오늘 소개드린 매물"
    )

    trade_type = (
        _safe_get(article, "trade_type_name")
        or _safe_get(article, "trade_type")
        or (detail.get("tradeTypeName") if isinstance(detail, dict) else "")
        or ""
    )

    price = (
        _safe_get(article, "price_text")
        or _safe_get(draft, "price_text")
        or (detail.get("dealOrWarrantPrc") if isinstance(detail, dict) else "")
        or ""
    )

    region = (
        _safe_get(article, "exposure_address")
        or _safe_get(article, "address")
        or _safe_get(draft, "address")
        or (detail.get("exposureAddress") if isinstance(detail, dict) else "")
        or ""
    )

    return {
        "title": str(title or "").strip(),
        "office_name": str(_safe_get(realtor, "office_name") or _safe_get(draft, "office_name") or "").strip(),
        "trade_type": str(trade_type or "").strip(),
        "property_type": str(property_type or "").strip(),
        "price": str(price or "").strip(),
        "region": str(region or "").strip(),
    }


def _ensure_min_tail_length(comment, context=None, min_len=300):
    comment = str(comment or "").strip()

    extras = [
        "방문 전에는 현재 매물 가능 여부와 조건 변동 여부를 먼저 확인해 주세요. 같은 조건처럼 보여도 실제 현장에서는 채광, 소음, 주차, 동선에서 차이가 날 수 있습니다.",
        "사진과 기본 정보만으로는 판단하기 어려운 부분이 있으니 가능하다면 직접 방문해서 구조와 주변 분위기를 함께 보시는 것을 추천드립니다.",
        "가격과 입주 가능일, 관리비, 수리 여부는 상담 시점에 다시 확인하는 것이 가장 정확합니다. 문의 주시면 현재 확인 가능한 기준으로 안내드리겠습니다.",
        "생활권을 함께 비교하시면 선택이 더 쉬워집니다. 출퇴근 동선, 장보기, 병원, 학교, 대중교통 접근성처럼 매일 이용하는 부분도 함께 체크해보시면 좋습니다.",
    ]

    guard = 0
    while len(comment) < min_len and guard < 4:
        extra = random.choice(extras)
        if extra not in comment:
            comment = (comment + "\\n\\n" + extra).strip()
        guard += 1

    return comment


def build_human_tail_comment(draft=None, queue=None, realtor_id=None, profile_id=None):
    dbctx = load_tail_context_from_db(queue=queue)

    loaded_draft = dbctx.get("draft") or {}
    loaded_article = dbctx.get("article") or {}
    loaded_realtor = dbctx.get("realtor") or {}

    merged_draft = {}
    merged_draft.update(loaded_draft)
    if isinstance(draft, dict):
        merged_draft.update(draft)

    merged_queue = {}
    merged_queue.update(dbctx.get("queue") or {})
    if isinstance(queue, dict):
        merged_queue.update(queue)

    rid = realtor_id or _safe_get(merged_queue, "realtor_id") or _safe_get(loaded_realtor, "id")
    profile = get_human_profile(realtor_id=rid, profile_id=profile_id)

    property_type = detect_property_type_v2(
        draft=merged_draft,
        queue=merged_queue,
        article=loaded_article,
    )

    context = _build_context(
        draft=merged_draft,
        queue=merged_queue,
        article=loaded_article,
        realtor=loaded_realtor,
        property_type=property_type,
    )

    comment = build_profile_tail_comment(
        realtor_id=rid,
        profile=profile,
        property_type=property_type,
        context=context,
    )

    comment = _ensure_min_tail_length(comment, context=context, min_len=300)

    if comment:
        print(
            "[TAIL PROFILE]",
            f"profile={profile.get('profile_id')}",
            f"name={profile.get('name')}",
            f"property_type={property_type}",
            f"title={context.get('title')}",
            f"len={len(comment)}",
        )
        return comment

    return _ensure_min_tail_length(
        "방문 전에는 현재 매물 가능 여부와 조건 변동 여부를 먼저 확인해 주세요.",
        context=context,
        min_len=300,
    )


def type_tail_comment_after_body(page, frame=None, draft=None, queue=None, realtor_id=None, profile_id=None):
    rid = realtor_id or _safe_get(queue, "realtor_id")
    comment = build_human_tail_comment(
        draft=draft,
        queue=queue,
        realtor_id=rid,
        profile_id=profile_id,
    )

    if not comment:
        print("[TAIL COMMENT SKIP] empty")
        return False

    profile = get_human_profile(realtor_id=rid, profile_id=profile_id)
    typing_cfg = get_typing_config(profile)

    print("[TAIL COMMENT START]", f"len={len(comment)}")

    try:
        page.keyboard.press("End")
        page.wait_for_timeout(random.randint(400, 900))
        page.keyboard.press("Enter")
        page.keyboard.press("Enter")
        page.wait_for_timeout(random.randint(500, 1300))

        typed = human_type_text(
            page=page,
            text=comment,
            min_delay_ms=typing_cfg.get("min_delay_ms", 35),
            max_delay_ms=typing_cfg.get("max_delay_ms", 125),
            pause_chance=typing_cfg.get("pause_chance", 0.055),
        )

        page.wait_for_timeout(random.randint(800, 1800))

        print("[TAIL COMMENT DONE]", f"len={len(comment)}", f"typed={typed}")
        return True

    except Exception as e:
        print("[TAIL COMMENT ERROR]", str(e))
        return False
"""

TARGET.write_text(new_text, encoding="utf-8")
print("[DONE] patched", TARGET)
