"""robots.txt 정책 준수 유틸리티.

웹 크롤링/스크래핑 전 대상 사이트의 robots.txt를 자동으로 확인한다.
결과는 도메인(scheme://netloc) 단위로 TTL 1시간 캐시에 보관하여
반복 네트워크 요청을 방지한다.

Usage:
    from utils.robots_policy import check_robots_txt

    if check_robots_txt("https://example.com/page"):
        # 크롤링 진행
        ...
"""

from __future__ import annotations

import logging
import time
from urllib.parse import urlparse
from urllib.robotparser import RobotFileParser

logger = logging.getLogger(__name__)

# 캐시: { "https://example.com": (RobotFileParser, timestamp) }
_robots_cache: dict[str, tuple[RobotFileParser, float]] = {}
_CACHE_TTL: float = 3600.0  # 1시간


def _cache_key(url: str) -> str | None:
    """URL에서 scheme://netloc 형식의 캐시 키를 추출한다."""
    parsed = urlparse(url)
    if not parsed.scheme or not parsed.netloc:
        return None
    return f"{parsed.scheme}://{parsed.netloc}"


def _fetch_robots_parser(base_url: str) -> RobotFileParser:
    """robots.txt를 fetch하여 파서를 반환한다.

    네트워크 에러는 호출부에서 처리한다.
    """
    parser = RobotFileParser()
    parser.set_url(f"{base_url}/robots.txt")
    parser.read()
    return parser


def _get_cached_parser(base_url: str) -> RobotFileParser | None:
    """캐시에서 유효한(TTL 이내) 파서를 반환한다. 없으면 None."""
    entry = _robots_cache.get(base_url)
    if entry is None:
        return None
    parser, ts = entry
    if time.monotonic() - ts > _CACHE_TTL:
        return None
    return parser


def check_robots_txt(url: str, user_agent: str = "*") -> bool:
    """robots.txt 정책에 따라 URL 크롤링 허용 여부를 반환한다.

    Args:
        url:        크롤링 대상 URL (scheme 포함 필수).
        user_agent: 크롤러 User-Agent 문자열. 기본값 '*' (모든 봇).

    Returns:
        True  — 크롤링 허용 또는 정책 확인 불가(fail-open).
        False — robots.txt가 명시적으로 해당 경로를 차단.
    """
    base_url = _cache_key(url)
    if base_url is None:
        logger.debug("robots_policy: URL 파싱 실패, 허용 처리: %s", url)
        return True

    parser = _get_cached_parser(base_url)
    if parser is None:
        try:
            parser = _fetch_robots_parser(base_url)
        except Exception as exc:
            logger.warning("robots_policy: fetch 실패 (허용 처리): %s — %s", base_url, exc)
            return True
        _robots_cache[base_url] = (parser, time.monotonic())

    return parser.can_fetch(user_agent, url)
