# -*- coding: utf-8 -*-

import time
import random
from urllib.parse import quote

from playwright.sync_api import sync_playwright


USER_AGENT = (
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
    "AppleWebKit/537.36 (KHTML, like Gecko) "
    "Chrome/136.0.0.0 Safari/537.36"
)


def build_api_url(realtor_id, page=1, trade_type=""):
    realtor_id = quote(str(realtor_id).strip())

    return (
        "https://new.land.naver.com/api/articles"
        f"?realtorId={realtor_id}"
        f"&page={int(page)}"
        "&order=rank"
        f"&tradeType={trade_type}"
        "&realEstateType="
        "&isFixed=false"
    )


def normalize_article_item(item):
    article_no = (
        item.get("articleNo")
        or item.get("atclNo")
        or item.get("articleNumber")
        or ""
    )

    article_no = str(article_no).strip()

    return {
        "article_no": article_no,
        "article_name": item.get("articleName", "") or item.get("atclNm", ""),
        "trade_type": item.get("tradeTypeName", "") or item.get("tradTpNm", ""),
        "real_estate_type": item.get("realEstateTypeName", "") or item.get("rletTpNm", ""),
        "price_text": item.get("dealOrWarrantPrc", "") or item.get("hanPrc", ""),
        "building_name": item.get("buildingName", "") or item.get("complexName", ""),
        "floor_info": item.get("floorInfo", ""),
        "area_info": item.get("areaName", ""),
        "article_feature_desc": item.get("articleFeatureDesc", ""),
        "direction": item.get("direction", ""),
    }


def extract_article_list(data):
    if not isinstance(data, dict):
        return []

    article_list = (
        data.get("articleList")
        or data.get("articles")
        or data.get("list")
        or data.get("result")
        or []
    )

    if isinstance(article_list, dict):
        article_list = (
            article_list.get("articleList")
            or article_list.get("articles")
            or article_list.get("list")
            or []
        )

    if not isinstance(article_list, list):
        return []

    return article_list


class NaverBrowserArticleFetcher:
    """
    브라우저는 1회만 실행하고,
    이후 realtorId별 API 호출은 page.evaluate(fetch)로 반복한다.

    목적:
    - requests 429 회피
    - Playwright 스크롤/DOM 분석 제거
    - realtorId 기준 실제 네이버부동산 최신 매물번호 수집
    """

    def __init__(
        self,
        headless=True,
        bootstrap_url="https://new.land.naver.com/",
    ):
        self.headless = headless
        self.bootstrap_url = bootstrap_url
        self.pw = None
        self.browser = None
        self.context = None
        self.page = None

    def start(self):
        self.pw = sync_playwright().start()

        self.browser = self.pw.chromium.launch(
            headless=self.headless,
            args=[
                "--disable-blink-features=AutomationControlled",
                "--no-sandbox",
            ],
        )

        self.context = self.browser.new_context(
            locale="ko-KR",
            viewport={"width": 1365, "height": 900},
            user_agent=USER_AGENT,
        )

        self.page = self.context.new_page()

        print("[BROWSER START]")
        print("[BOOTSTRAP]", self.bootstrap_url)

        self.page.goto(
            self.bootstrap_url,
            wait_until="domcontentloaded",
            timeout=60000,
        )

        self.page.wait_for_timeout(3000)

    def close(self):
        try:
            if self.context:
                self.context.close()
        except Exception:
            pass

        try:
            if self.browser:
                self.browser.close()
        except Exception:
            pass

        try:
            if self.pw:
                self.pw.stop()
        except Exception:
            pass

        print("[BROWSER CLOSED]")

    def fetch_json(self, api_url):
        result = self.page.evaluate(
            """
            async (url) => {
                try {
                    const res = await fetch(url, {
                        method: 'GET',
                        credentials: 'include',
                        headers: {
                            'accept': 'application/json,text/plain,*/*'
                        }
                    });

                    const text = await res.text();

                    let json = null;

                    try {
                        json = JSON.parse(text);
                    } catch (e) {
                        json = null;
                    }

                    return {
                        ok: res.ok,
                        status: res.status,
                        url: res.url,
                        text: text,
                        json: json
                    };

                } catch (e) {
                    return {
                        ok: false,
                        status: 0,
                        url: url,
                        text: '',
                        json: null,
                        error: String(e)
                    };
                }
            }
            """,
            api_url,
        )

        return result

    def fetch_articles(
        self,
        realtor_id,
        page=1,
        trade_type="",
    ):
        api_url = build_api_url(
            realtor_id=realtor_id,
            page=page,
            trade_type=trade_type,
        )

        print("[FETCH]", realtor_id, "page=", page, "trade=", trade_type)

        result = self.fetch_json(api_url)

        status = int(result.get("status") or 0)

        print("[STATUS]", status)

        if status != 200:
            return {
                "ok": False,
                "status": status,
                "article_no": "",
                "candidates": [],
                "api_url": api_url,
                "error": (result.get("text") or result.get("error") or "")[:500],
            }

        data = result.get("json")

        article_list = extract_article_list(data)

        candidates = []

        for raw in article_list:
            if not isinstance(raw, dict):
                continue

            item = normalize_article_item(raw)

            article_no = item.get("article_no")

            if not article_no:
                continue

            item["source_url"] = api_url
            item["source_keyword"] = str(realtor_id)
            item["collector"] = "browser_fetch_api"
            item["page"] = int(page)
            item["trade_type_code"] = trade_type

            candidates.append(item)

        latest_article_no = candidates[0]["article_no"] if candidates else ""

        return {
            "ok": True,
            "status": status,
            "article_no": latest_article_no,
            "candidates": candidates,
            "api_url": api_url,
        }

    def fetch_latest_article(
        self,
        realtor_id,
    ):
        """
        최근개재일/기본 rank 기준 page=1 첫 번째 매물만 반환.
        """
        result = self.fetch_articles(
            realtor_id=realtor_id,
            page=1,
            trade_type="",
        )

        if result.get("article_no"):
            return result

        # 혹시 전체 tradeType이 비어 있을 때 안 나오면 보조 시도
        for trade_type in ["A1", "B1", "B2"]:
            result = self.fetch_articles(
                realtor_id=realtor_id,
                page=1,
                trade_type=trade_type,
            )

            if result.get("article_no"):
                return result

            time.sleep(random.uniform(0.3, 0.8))

        return result

    def fetch_many_latest(
        self,
        realtor_ids,
        delay_min=0.5,
        delay_max=1.2,
    ):
        results = []

        total = len(realtor_ids)

        for idx, realtor_id in enumerate(realtor_ids, start=1):
            print("=" * 80)
            print(f"[{idx}/{total}] REALTOR ID: {realtor_id}")

            result = self.fetch_latest_article(
                realtor_id=realtor_id,
            )

            results.append({
                "realtor_id": realtor_id,
                "result": result,
            })

            sleep_sec = random.uniform(delay_min, delay_max)

            print(f"[SLEEP] {sleep_sec:.2f}s")

            time.sleep(sleep_sec)

        return results


def fetch_many_latest_articles(
    realtor_ids,
    headless=True,
    delay_min=0.5,
    delay_max=1.2,
):
    fetcher = NaverBrowserArticleFetcher(
        headless=headless,
    )

    try:
        fetcher.start()

        return fetcher.fetch_many_latest(
            realtor_ids=realtor_ids,
            delay_min=delay_min,
            delay_max=delay_max,
        )

    finally:
        fetcher.close()


if __name__ == "__main__":
    realtor_ids = [
        "s5575s",
        "hope6130066",
        "k3739919",
    ]

    results = fetch_many_latest_articles(
        realtor_ids=realtor_ids,
        headless=False,
    )

    print("=" * 80)
    print("[FINAL RESULT]")

    for row in results:
        realtor_id = row["realtor_id"]
        result = row["result"]

        print(
            realtor_id,
            "ok=",
            result.get("ok"),
            "status=",
            result.get("status"),
            "article_no=",
            result.get("article_no"),
            "count=",
            len(result.get("candidates", []) or []),
        )