# -*- coding: utf-8 -*-
"""
STEP102-03d
services/complex_address_cache_bridge.py

article raw_json / dict 에서 exposureAddress, complexName 후보 추출 후
'103동', '301동' 같은 동 정보를 제거해 단지명 기준으로 주소 캐시를 보강한다.

핵심 수정:
- 시청역해모로센티아 103동 -> 시청역해모로센티아
- 가온9단지블루시티 912동 -> 가온9단지블루시티
- 양정포레힐즈스위첸 110동 -> 양정포레힐즈스위첸

운영 원칙:
- publish_worker.py 영향 없음
- 실패 시 None 반환
- 기존 소재지를 임의 보정하지 않음
"""

import json
import re
import logging
from typing import Any, Dict, Optional, Tuple

from services.naver_search_complex_resolver import resolve_and_cache_complex_address

logger = logging.getLogger(__name__)


def _safe_get(obj: Any, *keys):
    cur = obj
    for key in keys:
        if not isinstance(cur, dict):
            return None
        cur = cur.get(key)
    return cur


def parse_json_maybe(value: Any) -> Optional[Dict[str, Any]]:
    if isinstance(value, dict):
        return value

    if not value:
        return None

    if isinstance(value, str):
        try:
            return json.loads(value)
        except Exception:
            return None

    return None


def clean_complex_name(value: Optional[str]) -> Optional[str]:
    """
    네이버 검색 카드 매칭을 위해 동/호/층/타입성 꼬리를 제거한다.

    예:
    시청역해모로센티아 103동 -> 시청역해모로센티아
    가온9단지블루시티 912동 -> 가온9단지블루시티
    화진금봉3단지 301동 -> 화진금봉3단지
    빌라 해승하우스 -> 해승하우스
    """
    if not value:
        return None

    s = str(value).strip()
    s = re.sub(r"\s+", " ", s)

    # 앞쪽 부동산 유형 단어 제거
    s = re.sub(r"^(아파트|오피스텔|빌라|연립|다세대|주택|상가|분양권)\s+", "", s)

    # 끝의 동/호/층 제거
    s = re.sub(r"\s+\d{1,4}동$", "", s)
    s = re.sub(r"\s+\d{1,4}호$", "", s)
    s = re.sub(r"\s+\d{1,3}층$", "", s)

    # 괄호 정보 제거
    s = re.sub(r"\([^)]*\)", "", s).strip()

    return s or None


def extract_region_and_complex(article_data: Any) -> Tuple[Optional[str], Optional[str]]:
    """
    다양한 raw_json 구조에서 지역명/단지명을 안전하게 추출한다.

    region:
    - articleDetail.exposureAddress 우선

    complex:
    - articleDetail.complexName / hscpNm 우선
    - 없으면 articleName/buildingName 사용 후 동 정보 제거
    """
    data = parse_json_maybe(article_data)
    if not data:
        return None, None

    detail = data.get("articleDetail") if isinstance(data.get("articleDetail"), dict) else data

    region_name = (
        _safe_get(detail, "exposureAddress")
        or _safe_get(data, "exposureAddress")
        or _safe_get(detail, "address")
    )

    # complexName/hscpNm이 있으면 가장 신뢰
    complex_name = (
        _safe_get(detail, "complexName")
        or _safe_get(detail, "hscpNm")
        or _safe_get(data, "complexName")
        or _safe_get(data, "hscpNm")
    )

    # 없으면 articleName/buildingName 후보 사용
    if not complex_name:
        complex_name = (
            _safe_get(detail, "articleName")
            or _safe_get(data, "articleName")
            or _safe_get(detail, "buildingName")
            or _safe_get(data, "buildingName")
        )

    if region_name:
        region_name = str(region_name).strip()

    complex_name = clean_complex_name(complex_name)

    return region_name or None, complex_name or None


def ensure_article_complex_address_cache(
    conn,
    article_no: str,
    article_data: Any,
    force_refresh: bool = False,
) -> Optional[Dict[str, Any]]:
    """
    매물 raw_json을 받아 단지 주소 캐시를 보강한다.

    실패해도 예외를 외부로 던지지 않는다.
    fetch_article_detail 파이프라인 안정성 보호 목적.
    """
    try:
        region_name, complex_name = extract_region_and_complex(article_data)

        if not region_name or not complex_name:
            logger.info(
                "[COMPLEX_ADDRESS_SKIP] article_no=%s region=%s complex=%s",
                article_no,
                region_name,
                complex_name,
            )
            return None

        result = resolve_and_cache_complex_address(
            conn,
            region_name=region_name,
            complex_name=complex_name,
            force_refresh=force_refresh,
        )

        if result:
            logger.info(
                "[COMPLEX_ADDRESS_READY] article_no=%s %s / %s -> %s",
                article_no,
                region_name,
                complex_name,
                result.get("resolved_address"),
            )

        return result

    except Exception as e:
        logger.warning(
            "[COMPLEX_ADDRESS_SAFE_FAIL] article_no=%s err=%s",
            article_no,
            e,
        )
        return None


if __name__ == "__main__":
    samples = [
        "시청역해모로센티아 103동",
        "가온9단지블루시티 912동",
        "양정포레힐즈스위첸 110동",
        "빌라 해승하우스",
    ]
    for s in samples:
        print(s, "=>", clean_complex_name(s))
