"""Read-only PixelRAG OCR/VLM replay contract builder.

This module turns PixelRAG visual evidence receipts into a machine-readable
contract for an Ollama-first OCR/VLM worker. It does not execute OCR, call a
model, write RAG data, write price tables, or promote visual fields.
"""

from __future__ import annotations

from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Mapping

from services.pixelrag_crawler_integration_service import (
    DEFAULT_ARTIFACT_MAX_AGE_HOURS,
    DEFAULT_ARTIFACT_ROOT,
    ECOMMERCE_PLATFORM_PROFILES,
)
from services.pixelrag_rag_candidate_replay_service import (
    build_pixelrag_rag_candidate_replay_readback,
)


POLICY = "read_only_pixelrag_ocr_vlm_replay_contract_v1"
DEFAULT_LIMIT = 50
DEFAULT_CONFIDENCE_THRESHOLD = 0.72

FIELD_ALIASES: dict[str, dict[str, str]] = {
    "title": {"type": "string", "required": "true", "evidence": "tile_text_or_card_region"},
    "price": {"type": "money", "required": "true", "evidence": "price_region"},
    "currency": {"type": "string", "required": "false", "evidence": "price_region"},
    "bundle_spec": {"type": "string", "required": "false", "evidence": "spec_or_bundle_region"},
    "promo_badge": {"type": "string", "required": "false", "evidence": "badge_region"},
    "campaign_badge": {"type": "string", "required": "false", "evidence": "badge_region"},
    "stock_hint": {"type": "string", "required": "false", "evidence": "availability_region"},
    "image": {"type": "asset_ref", "required": "false", "evidence": "screenshot_or_tile"},
    "product_id": {"type": "string", "required": "false", "evidence": "url_or_card_region"},
    "shop": {"type": "string", "required": "false", "evidence": "seller_region"},
    "sold_count": {"type": "number_or_label", "required": "false", "evidence": "social_proof_region"},
    "rating": {"type": "number_or_label", "required": "false", "evidence": "rating_region"},
    "shipping_badge": {"type": "string", "required": "false", "evidence": "shipping_region"},
    "discount": {"type": "string", "required": "false", "evidence": "discount_region"},
    "delivery_badge": {"type": "string", "required": "false", "evidence": "delivery_region"},
    "spec": {"type": "string", "required": "false", "evidence": "spec_region"},
    "review_count": {"type": "number_or_label", "required": "false", "evidence": "review_region"},
    "coupon": {"type": "string", "required": "false", "evidence": "coupon_region"},
    "sales_hint": {"type": "string", "required": "false", "evidence": "social_proof_region"},
    "member_price": {"type": "money", "required": "false", "evidence": "member_price_region"},
    "shipping_hint": {"type": "string", "required": "false", "evidence": "shipping_region"},
    "reward_badge": {"type": "string", "required": "false", "evidence": "reward_region"},
    "point_reward": {"type": "string", "required": "false", "evidence": "reward_region"},
    "public_page_visual_evidence": {
        "type": "evidence_summary",
        "required": "true",
        "evidence": "visible_page_regions",
    },
}


def _normalise_platforms(
    platform: str | tuple[str, ...] | list[str] | None,
) -> tuple[str, ...] | None:
    if isinstance(platform, str):
        return (platform.strip().lower(),) if platform.strip() else None
    selected = tuple(
        str(item or "").strip().lower()
        for item in (platform or [])
        if str(item or "").strip()
    )
    return selected or None


def _tile_inputs(candidate: Mapping[str, Any]) -> list[dict[str, Any]]:
    files = ((candidate.get("file_summary") or {}).get("files") or [])
    tiles: list[dict[str, Any]] = []
    for index, item in enumerate(files):
        if item.get("kind") != "tile":
            continue
        path = str(item.get("path") or "").strip()
        tiles.append({
            "index": index,
            "kind": "tile",
            "path": path,
            "exists": bool(item.get("exists")),
            "evidence_ref": f"tile:{index}",
        })
    return tiles


def _field_contract(platform: str) -> list[dict[str, Any]]:
    profile = ECOMMERCE_PLATFORM_PROFILES.get(platform) or {}
    fields = [str(item) for item in list(profile.get("data_targets") or []) if str(item)]
    if "price" in fields and "currency" not in fields:
        fields.insert(fields.index("price") + 1, "currency")
    if not fields:
        fields = ["public_page_visual_evidence"]
    contracts: list[dict[str, Any]] = []
    for field in fields:
        base = FIELD_ALIASES.get(field) or {
            "type": "string",
            "required": "false",
            "evidence": "visible_region",
        }
        contracts.append({
            "field": field,
            "type": base["type"],
            "required": base["required"] == "true",
            "evidence_requirement": base["evidence"],
            "min_confidence": DEFAULT_CONFIDENCE_THRESHOLD if field in {"title", "price"} else 0.62,
            "allow_empty": base["required"] != "true",
        })
    return contracts


def _output_schema(fields: list[dict[str, Any]]) -> dict[str, Any]:
    return {
        "platform": "string",
        "manifest_id": "string",
        "source_receipt_path": "string",
        "blocked_page_detected": "boolean",
        "quality": {
            "overall_confidence": "float_0_1",
            "field_confidence_min": "float_0_1",
            "missing_required_fields": "list[string]",
            "requires_identity_matcher_replay": "boolean",
            "requires_promotion_gate": "boolean",
        },
        "fields": {
            item["field"]: {
                "value": item["type"],
                "confidence": "float_0_1",
                "evidence_refs": "list[string]",
            }
            for item in fields
        },
        "next_machine_action": "string",
    }


def _validation_rules() -> list[str]:
    return [
        "blocked_or_access_denied_page_must_not_emit_product_fields",
        "every_field_value_requires_at_least_one_tile_evidence_ref",
        "required_title_and_price_must_meet_min_confidence_before_promotion_gate",
        "price_must_parse_to_numeric_money_before_any_price_candidate",
        "currency_defaults_to_TWD_only_when_page_locale_or_symbol_supports_it",
        "identity_matcher_replay_required_before_offer_matching",
        "promotion_gate_required_before_internal_rag_or_ai_insights_write",
        "direct_competitor_prices_write_forbidden",
        "direct_competitor_price_history_write_forbidden",
        "direct_ai_insights_write_forbidden",
    ]


def _model_route_contract() -> dict[str, Any]:
    return {
        "runtime_policy": "ollama_first_no_hosted_vlm_default",
        "preferred_chain": [
            {"host": "34.87.90.216:11434", "role": "gcp_a_primary"},
            {"host": "34.21.145.224:11434", "role": "gcp_b_secondary"},
            {"host": "192.168.0.111:11434", "role": "lan_final_fallback"},
        ],
        "production_app_host_is_not_ollama_node": "192.168.0.188",
        "hosted_vlm_api_allowed": False,
        "gemini_default_allowed": False,
        "secret_read_allowed": False,
        "network_call_performed_by_this_contract": False,
    }


def _candidate_contract(candidate: Mapping[str, Any]) -> dict[str, Any]:
    platform = str(candidate.get("platform") or "unknown")
    fields = _field_contract(platform)
    tiles = _tile_inputs(candidate)
    blocked_reasons = list(candidate.get("blocked_reasons") or [])
    candidate_status = str(candidate.get("candidate_status") or "unknown")
    ready = candidate_status == "eligible" and bool(tiles)
    missing_tile_count = sum(1 for item in tiles if not item["exists"])
    if candidate_status == "eligible" and not tiles:
        blocked_reasons.append("no_tile_inputs_available")
    if missing_tile_count:
        blocked_reasons.append("tile_input_missing_files")
    if candidate_status == "invalid":
        replay_status = "invalid"
    elif ready and not missing_tile_count:
        replay_status = "ready_for_ocr_vlm_replay"
    else:
        replay_status = "blocked"

    return {
        "replay_status": replay_status,
        "ready_for_ollama_vlm_worker": replay_status == "ready_for_ocr_vlm_replay",
        "candidate_status": candidate_status,
        "blocked_reasons": blocked_reasons,
        "platform": platform,
        "manifest_id": candidate.get("manifest_id"),
        "source_receipt_path": candidate.get("receipt_path"),
        "url": candidate.get("url"),
        "title_hint": candidate.get("title"),
        "http_status": candidate.get("http_status"),
        "visual_barrier_detected": bool(candidate.get("visual_barrier_detected")),
        "visual_barrier_reason": candidate.get("visual_barrier_reason"),
        "input_tiles": tiles,
        "field_contract": fields,
        "field_contract_count": len(fields),
        "output_schema": _output_schema(fields),
        "validation_rules": _validation_rules(),
        "prompt_contract": {
            "task": "extract_public_marketplace_offer_card_fields_from_tiles",
            "language": "zh-TW",
            "allowed_inputs": ["tile images", "receipt metadata", "field contract"],
            "forbidden_inputs": ["secrets", "cookies", "sessions", "private account pages"],
            "instruction": (
                "Return only fields supported by visible tile evidence; mark unknown "
                "instead of guessing, and set blocked_page_detected=true for access "
                "denied, captcha, login, or traffic verification pages."
            ),
        },
        "automation_boundary": {
            "ocr_execution_performed": False,
            "vlm_execution_performed": False,
            "writes_database": False,
            "writes_ai_insights": False,
            "writes_price_tables": False,
            "network_call": False,
            "secret_read": False,
        },
        "next_machine_action": (
            "run_ollama_first_vlm_replay_worker"
            if replay_status == "ready_for_ocr_vlm_replay"
            else (
                "run_platform_probe_or_use_structured_api"
                if candidate.get("visual_barrier_detected") or candidate.get("http_status", 0) >= 400
                else "refresh_pixelrag_visual_capture_receipt"
            )
        ),
    }


def build_pixelrag_ocr_vlm_replay_contract(
    *,
    artifact_root: str | Path | None = None,
    platform: str | tuple[str, ...] | list[str] | None = None,
    max_age_hours: int | None = None,
    limit: int | None = None,
) -> dict[str, Any]:
    """Build a no-write OCR/VLM replay contract from PixelRAG receipts."""
    root = Path(artifact_root or DEFAULT_ARTIFACT_ROOT)
    max_age = max(1, int(max_age_hours or DEFAULT_ARTIFACT_MAX_AGE_HOURS))
    item_limit = max(1, min(int(limit or DEFAULT_LIMIT), 250))
    platforms = _normalise_platforms(platform)
    generated_at = datetime.now(timezone.utc).isoformat()

    candidate_readback = build_pixelrag_rag_candidate_replay_readback(
        artifact_root=root,
        platform=platforms,
        max_age_hours=max_age,
        limit=item_limit,
    )
    replay_items = [
        _candidate_contract(candidate)
        for candidate in list(candidate_readback.get("candidates") or [])
    ]
    ready_count = sum(1 for item in replay_items if item["replay_status"] == "ready_for_ocr_vlm_replay")
    blocked_count = sum(1 for item in replay_items if item["replay_status"] == "blocked")
    invalid_count = sum(1 for item in replay_items if item["replay_status"] == "invalid")
    tile_input_count = sum(len(item.get("input_tiles") or []) for item in replay_items)
    field_contract_count = sum(int(item.get("field_contract_count") or 0) for item in replay_items)
    missing_tile_count = sum(
        1
        for item in replay_items
        for tile in list(item.get("input_tiles") or [])
        if not tile.get("exists")
    )

    if invalid_count and invalid_count == len(replay_items):
        status = "critical"
    elif not replay_items or ready_count == 0 or blocked_count or invalid_count or missing_tile_count:
        status = "warning"
    else:
        status = "ok"

    summary = {
        "receipt_count": len(replay_items),
        "replay_ready_count": ready_count,
        "blocked_count": blocked_count,
        "invalid_count": invalid_count,
        "tile_input_count": tile_input_count,
        "missing_tile_count": missing_tile_count,
        "field_contract_count": field_contract_count,
        "extraction_execution_performed": False,
        "ocr_execution_performed": False,
        "vlm_execution_performed": False,
        "platforms": sorted({str(item.get("platform") or "unknown") for item in replay_items}),
    }

    return {
        "success": invalid_count == 0,
        "policy": POLICY,
        "status": status,
        "generated_at": generated_at,
        "artifact_root": str(root),
        "max_age_hours": max_age,
        "platform_filter": list(platforms or []),
        "summary": summary,
        "replay_items": replay_items,
        "source_candidate_replay": {
            "policy": candidate_readback.get("policy"),
            "status": candidate_readback.get("status"),
            "summary": candidate_readback.get("summary"),
        },
        "model_route_contract": _model_route_contract(),
        "replay_contract": {
            "automation_mode": "no_write_ocr_vlm_replay_package",
            "writes_database": False,
            "writes_ai_insights": False,
            "writes_price_tables": False,
            "network_call": False,
            "secret_read": False,
            "extraction_execution_performed": False,
            "blocked_pages_are_not_product_data": True,
            "requires_identity_matcher_replay": True,
            "requires_promotion_gate": True,
            "requires_embedding_signature_guard": True,
        },
        "next_machine_action": (
            "run_pixelrag_visual_capture_worker"
            if not replay_items
            else (
                "fix_invalid_pixelrag_receipts"
                if invalid_count and not ready_count
                else (
                    "run_ollama_first_vlm_replay_worker"
                    if ready_count
                    else "run_platform_probe_or_use_structured_api"
                )
            )
        ),
        "controlled_apply": {
            "network_call": False,
            "db_write": False,
            "secret_read": False,
            "production_price_write": False,
            "artifact_write": False,
            "primary_human_gate_count": 0,
        },
    }


__all__ = [
    "DEFAULT_CONFIDENCE_THRESHOLD",
    "POLICY",
    "build_pixelrag_ocr_vlm_replay_contract",
]
