"""S9-S14: Review server integrity checks."""

import os
import re

from recoil_checks import register_check


def check_all_routes_have_handlers(base, discovered):
    """S9: All documented API routes have handlers in review_server.py."""
    passes, fails, warns = [], [], []
    server_path = os.path.join(base, "editors", "review_server.py")

    if not os.path.isfile(server_path):
        fails.append("review_server.py not found")
        return {"pass": passes, "fail": fails, "warn": warns}

    with open(server_path, encoding="utf-8") as f:
        content = f.read()

    # Extract documented endpoints from the docstring
    doc_routes = set()
    for m in re.finditer(r'(?:GET|POST|PATCH|DELETE)\s+(/api/\S+)', content[:3000]):
        route = m.group(1).rstrip()
        # Normalize: strip {param} placeholders
        route = re.sub(r'\{[^}]+\}', '*', route)
        doc_routes.add(route)

    # Check that each documented route has a handler
    handler_code = content[3000:]
    for route in sorted(doc_routes):
        # Extract the base path (up to the first wildcard) for matching
        base_path = route.split('*')[0].rstrip('/')
        if not base_path:
            base_path = route.replace('*', '')
        # Also check for the route segment keywords (e.g., "accept", "casting")
        segments = [s for s in route.replace('*', '').split('/') if s and s != 'api']
        found = base_path in handler_code or any(
            f'"{seg}"' in handler_code or f"'{seg}'" in handler_code
            for seg in segments if len(seg) > 3
        )
        if found:
            passes.append(f"Route {route} has handler")
        else:
            warns.append(f"Route {route} may lack handler implementation")

    if not doc_routes:
        warns.append("No documented routes found in docstring")

    return {"pass": passes, "fail": fails, "warn": warns}


def check_endpoint_frontend_parity(base, discovered):
    """S10: Frontend JS references match available API endpoints."""
    passes, fails, warns = [], [], []

    # Check review.html
    review_path = os.path.join(base, "editors", "review.html")
    server_path = os.path.join(base, "editors", "review_server.py")

    if not os.path.isfile(review_path):
        warns.append("review.html not found")
        return {"pass": passes, "fail": fails, "warn": warns}

    if not os.path.isfile(server_path):
        warns.append("review_server.py not found")
        return {"pass": passes, "fail": fails, "warn": warns}

    with open(review_path, encoding="utf-8") as f:
        html_content = f.read()
    with open(server_path, encoding="utf-8") as f:
        server_content = f.read()

    # Find fetch() calls in HTML/JS
    fetch_urls = set()
    for m in re.finditer(r'fetch\([\'"`](/api/[^\'"`,\s]+)', html_content):
        fetch_urls.add(m.group(1))

    for url in sorted(fetch_urls):
        # Normalize to check in server
        url_base = re.sub(r'/\$\{[^}]+\}', '/', url)
        url_base = re.sub(r'/\d+', '/', url_base)
        if url_base.rstrip("/") in server_content or url.split("/")[2] in server_content:
            passes.append(f"Frontend fetch {url} has server handler")
        else:
            warns.append(f"Frontend fetch {url} may lack server handler")

    if not fetch_urls:
        warns.append("No fetch() calls found in review.html")

    return {"pass": passes, "fail": fails, "warn": warns}


def check_static_paths(base, discovered):
    """S11: Static file references in HTML point to existing files."""
    passes, fails, warns = [], [], []

    html_files = [
        os.path.join(base, "editors", "review.html"),
        os.path.join(base, "editors", "production-console.html"),
    ]

    for html_path in html_files:
        if not os.path.isfile(html_path):
            continue

        with open(html_path, encoding="utf-8") as f:
            content = f.read()

        # Find src="..." and href="..." references
        for m in re.finditer(r'(?:src|href)=["\']([^"\']+)["\']', content):
            ref = m.group(1)
            if ref.startswith("http") or ref.startswith("//") or ref.startswith("data:"):
                continue
            if ref.startswith("/api/"):
                continue

            # Resolve relative to editors/
            editors_dir = os.path.dirname(html_path)
            full_path = os.path.normpath(os.path.join(editors_dir, ref))

            if os.path.isfile(full_path):
                passes.append(f"{os.path.basename(html_path)}: {ref} exists")
            else:
                warns.append(f"{os.path.basename(html_path)}: {ref} not found")

    return {"pass": passes, "fail": fails, "warn": warns}


def check_review_html_exists(base, discovered):
    """S12: Required editor HTML files exist."""
    passes, fails, warns = [], [], []

    required = ["review.html", "production-console.html"]
    for name in required:
        path = os.path.join(base, "editors", name)
        if os.path.isfile(path):
            passes.append(f"{name} exists")
        else:
            fails.append(f"{name} not found")

    return {"pass": passes, "fail": fails, "warn": warns}


def check_server_port_config(base, discovered):
    """S13: Server port is configured and not conflicting."""
    passes, fails, warns = [], [], []
    server_path = os.path.join(base, "editors", "review_server.py")

    if not os.path.isfile(server_path):
        warns.append("review_server.py not found")
        return {"pass": passes, "fail": fails, "warn": warns}

    with open(server_path, encoding="utf-8") as f:
        content = f.read()

    port_match = re.search(r'PORT\s*=\s*(\d+)', content)
    if port_match:
        port = int(port_match.group(1))
        passes.append(f"Server port configured: {port}")
        if port == 8420:
            warns.append("Port 8430 expected for starsend, found 8420 (recoil's port)")
    else:
        warns.append("Could not find PORT configuration")

    return {"pass": passes, "fail": fails, "warn": warns}


def check_cors_headers(base, discovered):
    """S14: Server sends appropriate CORS headers for local dev."""
    passes, fails, warns = [], [], []
    server_path = os.path.join(base, "editors", "review_server.py")

    if not os.path.isfile(server_path):
        warns.append("review_server.py not found")
        return {"pass": passes, "fail": fails, "warn": warns}

    with open(server_path, encoding="utf-8") as f:
        content = f.read()

    if "Access-Control-Allow-Origin" in content:
        passes.append("CORS headers present")
    else:
        warns.append("No CORS headers found (may cause issues with cross-origin requests)")

    return {"pass": passes, "fail": fails, "warn": warns}


register_check("s9_routes_handlers", "API Routes Have Handlers", check_all_routes_have_handlers, section="server")
register_check("s10_endpoint_parity", "Frontend ↔ Backend Parity", check_endpoint_frontend_parity, section="server")
register_check("s11_static_paths", "Static File References", check_static_paths, section="server")
register_check("s12_editor_html", "Editor HTML Files Exist", check_review_html_exists, section="server", quick=True)
register_check("s13_port_config", "Server Port Config", check_server_port_config, section="server")
register_check("s14_cors_headers", "CORS Headers", check_cors_headers, section="server")
