"""Gate checks for professional market source governance."""

from urllib.parse import urlparse


CONTRACT_SCOPE = "market_intel_public_campaign_source_governance"
SOURCE_POLICY_VERSION = "source_governance_v1"
SUPPORTED_PLATFORMS = ("momo", "pchome", "coupang", "shopee")
ALLOWED_STRUCTURED_DATA_TYPES = {
    "AggregateOffer",
    "BreadcrumbList",
    "ItemList",
    "Offer",
    "Product",
}
PRIVATE_URL_MARKERS = (
    "/account",
    "/cart",
    "/checkout",
    "/login",
    "/member",
    "/members",
    "/my",
    "/order",
    "/orders",
    "/profile",
    "/signin",
    "/user",
)
MIN_CRAWL_DELAY_SECONDS = 1.0
MAX_REQUESTS_PER_RUN = 50


def _is_public_http_url(value):
    if not isinstance(value, str) or not value.strip():
        return False
    parsed = urlparse(value.strip())
    if parsed.scheme not in ("http", "https"):
        return False
    if not parsed.netloc:
        return False
    lowered_path = (parsed.path or "").lower()
    return not any(marker in lowered_path for marker in PRIVATE_URL_MARKERS)


def _unique_source_keys(sources):
    keys = [
        f"{source['platform_code']}:{source['source_key']}"
        for source in sources
        if source["platform_code"] and source["source_key"]
    ]
    return bool(keys and len(keys) == len(set(keys)) == len(sources))


def _all_sources_have_allowed_structured_data(sources):
    return bool(
        sources
        and all(
            source["structured_data_preferred"]
            and source["json_ld_first"]
            and bool(
                set(source["structured_data_types"]).intersection(
                    ALLOWED_STRUCTURED_DATA_TYPES
                )
            )
            for source in sources
        )
    )


def _rate_limits_safe(sources):
    return bool(
        sources
        and all(
            source["crawl_delay_seconds"] >= MIN_CRAWL_DELAY_SECONDS
            and 0 < source["max_requests_per_run"] <= MAX_REQUESTS_PER_RUN
            for source in sources
        )
    )


def _source_url_set_safe(source):
    return bool(
        source["source_url_safe"]
        and source["canonical_url_safe"]
        and source["robots_url_safe"]
        and source["sitemap_url_safe"]
    )


def _source_boundaries_safe(source):
    return bool(
        source["tos_public_page_checked"]
        and not source["login_required"]
        and not source["member_or_order_data"]
        and not source["cart_order_or_pii"]
        and not source["anti_bot_bypass_required"]
    )


def build_professional_source_governance_gates(
    *,
    package_received,
    governance,
):
    """Return gate rows. The caller decides whether failed rows block acceptance."""
    sources = governance["sources"]
    confirmations = governance["operator_confirmations"]
    operator_boundaries_confirmed = bool(
        confirmations["human_reviewed_source_policy"]
        and confirmations["robots_and_tos_checked_by_operator"]
        and confirmations["public_pages_only"]
        and confirmations["no_login_or_member_data"]
        and confirmations["no_cart_order_or_pii"]
        and confirmations["no_antibot_bypass"]
        and confirmations["structured_data_first"]
        and confirmations["provenance_required"]
        and confirmations["no_api_network_fetch"]
        and confirmations["no_database_write"]
        and confirmations["no_scheduler_attach"]
        and confirmations["no_secret_payload"]
    )
    return [
        {
            "key": "source_governance_payload_received",
            "label": "已提供 operator source governance 摘要",
            "passed": package_received,
        },
        {
            "key": "source_governance_scope_safe",
            "label": "governance scope 必須鎖定公開活動來源治理",
            "passed": governance["governance_scope"] == CONTRACT_SCOPE,
        },
        {
            "key": "source_governance_policy_version_recorded",
            "label": "來源治理 policy version 必須可稽核",
            "passed": governance["policy_version"] == SOURCE_POLICY_VERSION,
        },
        {
            "key": "source_governance_sources_present",
            "label": "至少一個平台公開來源必須被審核",
            "passed": bool(sources),
        },
        {
            "key": "source_governance_supported_platforms",
            "label": "來源平台必須在 MOMO / PChome / Coupang / Shopee 白名單內",
            "passed": bool(
                sources
                and all(
                    source["platform_code"] in SUPPORTED_PLATFORMS
                    for source in sources
                )
            ),
        },
        {
            "key": "source_governance_unique_source_keys",
            "label": "每個 platform/source_key 必須唯一",
            "passed": _unique_source_keys(sources),
        },
        {
            "key": "source_governance_public_urls_only",
            "label": "source、canonical、robots 與 sitemap URL 必須是公開 http/https URL",
            "passed": bool(
                sources and all(_source_url_set_safe(source) for source in sources)
            ),
        },
        {
            "key": "source_governance_robots_policy_checked_and_allowed",
            "label": "操作員必須先確認 robots policy 且來源允許抓取",
            "passed": bool(
                sources
                and all(
                    source["robots_policy_checked"] and source["robots_allowed"]
                    for source in sources
                )
            ),
        },
        {
            "key": "source_governance_sitemap_or_lastmod_recorded",
            "label": "每個來源需記錄 sitemap 或 lastmod provenance",
            "passed": bool(
                sources
                and all(source["sitemap_url"] or source["lastmod_source"] for source in sources)
            ),
        },
        {
            "key": "source_governance_structured_data_first",
            "label": "優先讀 JSON-LD / schema.org Product、Offer 或 ItemList",
            "passed": _all_sources_have_allowed_structured_data(sources),
        },
        {
            "key": "source_governance_rate_limits_safe",
            "label": "每來源 crawl delay 至少 1 秒且單次 request budget 不超過 50",
            "passed": _rate_limits_safe(sources),
        },
        {
            "key": "source_governance_public_data_only_no_login_or_pii",
            "label": "不得碰登入、會員、購物車、訂單或個資頁",
            "passed": bool(
                sources and all(_source_boundaries_safe(source) for source in sources)
            ),
        },
        {
            "key": "source_governance_no_antibot_bypass",
            "label": "不得要求帳號池、繞反爬或破解保護",
            "passed": bool(
                sources
                and all(not source["anti_bot_bypass_required"] for source in sources)
            ),
        },
        {
            "key": "source_governance_provenance_and_hash_required",
            "label": "每筆來源需有 provenance、snapshot hash 與 idempotency key 策略",
            "passed": bool(
                sources
                and all(
                    source["provenance_required"]
                    and source["snapshot_hash_required"]
                    and source["idempotency_key_strategy"]
                    for source in sources
                )
            ),
        },
        {
            "key": "source_governance_evidence_paths_safe",
            "label": "治理證據 artifact path 必須在 artifacts/market_intel/*.json",
            "passed": bool(
                sources
                and all(source["evidence_artifact_path_safe"] for source in sources)
            ),
        },
        {
            "key": "source_governance_operator_boundaries_confirmed",
            "label": "操作員確認 API 不連外、不寫 DB、不掛 scheduler",
            "passed": operator_boundaries_confirmed,
        },
        {
            "key": "source_governance_no_raw_payload",
            "label": "API payload 不得貼入 raw HTML、頁面本文或完整 response body",
            "passed": not governance["raw_payload_submitted_to_api"],
        },
        {
            "key": "source_governance_no_secret_or_token_key",
            "label": "API payload 不得包含 cookie、secret、password 或 token key",
            "passed": not governance["secret_or_token_submitted_to_api"],
        },
        {
            "key": "source_governance_side_effect_free",
            "label": "payload 不得要求 API 連外、寫檔、寫 DB、執行 CLI 或掛 scheduler",
            "passed": not governance["blocked_side_effects"],
        },
        {
            "key": "source_governance_api_preview_only",
            "label": "本 endpoint 只能審核治理合約，不抓 robots/sitemap/source URL",
            "passed": bool(
                not governance["api_uses_external_network"]
                and not governance["api_fetches_robots_txt"]
                and not governance["api_fetches_sitemap"]
                and not governance["api_fetches_source_url"]
                and not governance["api_opens_database_connection"]
                and not governance["api_writes_database"]
                and not governance["api_writes_file"]
                and not governance["scheduler_attached"]
            ),
        },
    ]
