#!/usr/bin/env python3
import json
import os
import re
import sys
from datetime import datetime, timezone
from pathlib import Path
from urllib.parse import urlparse

import requests
from bs4 import BeautifulSoup

ROOT = Path(__file__).resolve().parents[1]
BASE = os.environ.get("MPC_AUDIT_BASE", "http://127.0.0.1:43183").rstrip("/")
HOST = os.environ.get("MPC_AUDIT_HOST", "marlothparkcentral.com")
VERSION = os.environ.get("NEXT_PUBLIC_BUILD_VERSION", "6.82.190")
SESSION = requests.Session()
SESSION.headers.update({"Host": HOST, "User-Agent": f"MPC-Codex-Live-Audit/{VERSION}"})

RULES = [
    ("Unsupported status/luxury claim", re.compile(r"\b(?:a premium|premium accommodation|premium base|premium independent|ultra premium|a luxury|luxury accommodation|luxury stay|luxury guide|VIP experience|prestige listing|elite listing)\b", re.I)),
    ("Unfinished public wording", re.compile(r"\b(?:opening soon|listings are opening|coming soon|not live yet|will appear when ready|no listings yet|nothing here|being added|being prepared|details pending|photos pending|rates pending|placeholder artwork)\b", re.I)),
    ("Public prelaunch mechanics", re.compile(r"\b(?:prelaunch position|reserved prelaunch|prelaunch inventory|prelaunch listing|prelaunch-slot|post-launch only)\b", re.I)),
    ("Public admin/workflow wording", re.compile(r"\b(?:in Admin|from Admin|Accommodation Admin|prepared wording|prepared photographs|publishing mechanics|backend routing|internal state|private handling)\b", re.I)),
    ("AI/build provenance wording", re.compile(r"\b(?:AI-created|AI-generated|flattened AI|editable route data|verified source wording|generated PDF)\b", re.I)),
    ("Technical public wording", re.compile(r"\b(?:Next\.js|React build|debug screen|cPanel|environment variable|build status|internal note|admin note)\b", re.I)),
    ("Guide format CTA wording", re.compile(r"\b(?:Preview PDF|Preview the free PDF|View\s*/\s*Download PDF|PDF library|download centre)\b", re.I)),
    ("Overclaim chooser wording", re.compile(r"\bBest when\b", re.I)),
    ("Public accommodation tier mechanics", re.compile(r"\b(?:MPC Listed Holiday Home|paid stay card|paid listing|highest external accommodation placement)\b", re.I)),
]


def safe_text(text: str) -> str:
    replacements = [
        (r"MPC Premium Kruger Visitor Map", "MPC Kruger Visitor Map"),
        (r"MPC Premium Route Atlas", "MPC Route Atlas"),
        (r"Premium Safari Home", "Safari Home"),
        (r"exclusive use", "private use"),
    ]
    for pattern, replacement in replacements:
        text = re.sub(pattern, replacement, text, flags=re.I)
    return text


def visible_text(html: str) -> str:
    soup = BeautifulSoup(html, "html.parser")
    for tag in soup(["script", "style", "noscript", "svg", "template"]):
        tag.decompose()
    return re.sub(r"\s+", " ", soup.get_text(" ", strip=True)).strip()


def get(path: str):
    response = SESSION.get(BASE + path, timeout=30, allow_redirects=True)
    return response


def sitemap_routes():
    response = get("/sitemap.xml")
    if response.status_code != 200:
        raise RuntimeError(f"/sitemap.xml returned {response.status_code}")
    routes = []
    for loc in re.findall(r"<loc>(.*?)</loc>", response.text, re.I):
        parsed = urlparse(loc)
        routes.append(parsed.path or "/")
    return sorted(set(["/"] + routes))


def main():
    routes = sitemap_routes()
    results = []
    failures = []
    for route in routes:
        response = get(route)
        record = {
            "route": route,
            "status": response.status_code,
            "finalUrl": response.url,
            "contentType": response.headers.get("content-type", ""),
            "matches": [],
        }
        if response.status_code != 200:
            failures.append({"route": route, "rule": "HTTP status", "match": str(response.status_code)})
        elif "text/html" in record["contentType"]:
            text = safe_text(visible_text(response.text))
            for label, pattern in RULES:
                if route in {"/terms", "/supplier-terms", "/legal", "/delivery-refunds", "/privacy"} and label == "Public accommodation tier mechanics":
                    continue
                match = pattern.search(text)
                if match:
                    hit = {"rule": label, "match": match.group(0)}
                    record["matches"].append(hit)
                    failures.append({"route": route, **hit})
        results.append(record)

    report = {
        "version": VERSION,
        "generatedAt": datetime.now(timezone.utc).isoformat(),
        "base": BASE,
        "host": HOST,
        "routesChecked": len(results),
        "failureCount": len(failures),
        "failures": failures,
        "results": results,
    }
    out = ROOT / "operations" / "proof" / f"MPC_v{VERSION}_CODEX_PUBLIC_WORDING_LIVE_CRAWL.json"
    out.parent.mkdir(parents=True, exist_ok=True)
    out.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8")
    print(json.dumps({"routes_checked": len(results), "failures": len(failures)}, indent=2))
    if failures:
        print(json.dumps(failures[:50], indent=2), file=sys.stderr)
        return 1
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
