"""Config validator for Codex Patcher — validates 6 config targets.

Unlike Claude/Gemini patchers (regex-based), Codex validation is state-based:
checks config.toml values and environment variables.
"""

import os
import tomllib
from dataclasses import dataclass
from typing import Callable, Optional


@dataclass
class ConfigTarget:
    name: str
    description: str
    check_key: str  # "config_toml" | "env" | "auth"


PATCH_TARGETS = [
    ConfigTarget(
        name="api_endpoint",
        description="Custom proxy via model_providers",
        check_key="config_toml",
    ),
    ConfigTarget(
        name="authentication",
        description="API key auth configured",
        check_key="auth",
    ),
    ConfigTarget(
        name="analytics_disabled",
        description="Analytics/telemetry disabled",
        check_key="config_toml",
    ),
    ConfigTarget(
        name="approval_bypass",
        description="Approval policy set to never",
        check_key="config_toml",
    ),
    ConfigTarget(
        name="sandbox_bypass",
        description="Sandbox set to danger-full-access",
        check_key="config_toml",
    ),
    ConfigTarget(
        name="env_vars",
        description="System environment variables configured",
        check_key="env",
    ),
]


def _read_toml(path):
    """Read TOML file, return dict or empty dict."""
    if not os.path.isfile(path):
        return None
    with open(path, "rb") as f:
        return tomllib.load(f)


def _check_api_endpoint(toml_data, config):
    """Check Target 1: model_providers.custom with correct base_url."""
    if toml_data is None:
        return "RED", "config.toml not found"

    mp = toml_data.get("model_providers", {})
    custom = mp.get("custom", {}) if isinstance(mp, dict) else {}

    base_url = config["base_url"].rstrip("/")
    if not base_url.endswith("/v1"):
        base_url += "/v1"

    if not custom:
        return "RED", "model_providers.custom section missing"

    if custom.get("base_url") != base_url:
        return "YELLOW", f"base_url mismatch: {custom.get('base_url')} != {base_url}"

    if toml_data.get("model_provider") != "custom":
        return "YELLOW", "model_provider != 'custom'"

    return "GREEN", f"base_url={base_url}"


def _check_auth(codex_dir, config):
    """Check Target 2: API key authentication."""
    # Check env var
    env_key = os.environ.get("OPENAI_API_KEY", "")
    if env_key == config["api_key"]:
        return "GREEN", "OPENAI_API_KEY set correctly"

    # Check /etc/environment
    etc_env = "/etc/environment"
    if os.path.isfile(etc_env):
        with open(etc_env) as f:
            content = f.read()
        if config["api_key"] in content:
            return "GREEN", "API key in /etc/environment"

    if env_key:
        return "YELLOW", "OPENAI_API_KEY set but different value"

    return "RED", "OPENAI_API_KEY not set"


def _check_analytics(toml_data):
    """Check Target 3: analytics disabled."""
    if toml_data is None:
        return "RED", "config.toml not found"

    analytics = toml_data.get("analytics", {})
    if not isinstance(analytics, dict):
        return "RED", "[analytics] section missing"

    if analytics.get("enabled") is False:
        return "GREEN", "analytics.enabled = false"

    if "enabled" not in analytics:
        return "YELLOW", "[analytics] exists but 'enabled' key missing"

    return "YELLOW", f"analytics.enabled = {analytics.get('enabled')}"


def _check_approval(toml_data, config):
    """Check Target 4: approval_policy."""
    if toml_data is None:
        return "RED", "config.toml not found"

    target_policy = config.get("approval_policy", "never")
    current = toml_data.get("approval_policy")

    if current == target_policy:
        return "GREEN", f'approval_policy = "{target_policy}"'

    if current is not None:
        return "YELLOW", f'approval_policy = "{current}" (expected "{target_policy}")'

    return "RED", "approval_policy not set"


def _check_sandbox(toml_data, config):
    """Check Target 5: sandbox_mode."""
    if toml_data is None:
        return "RED", "config.toml not found"

    target_mode = config.get("sandbox_mode", "danger-full-access")
    current = toml_data.get("sandbox_mode")

    if current == target_mode:
        return "GREEN", f'sandbox_mode = "{target_mode}"'

    if current is not None:
        return "YELLOW", f'sandbox_mode = "{current}" (expected "{target_mode}")'

    return "RED", "sandbox_mode not set"


def _check_env_vars(config):
    """Check Target 6: system environment variables."""
    base_url = config["base_url"].rstrip("/")
    if not base_url.endswith("/v1"):
        base_url += "/v1"

    etc_env = "/etc/environment"
    if not os.path.isfile(etc_env):
        return "RED", "/etc/environment not found"

    with open(etc_env) as f:
        content = f.read()

    has_base = "OPENAI_BASE_URL" in content
    has_key = "OPENAI_API_KEY" in content

    if has_base and has_key:
        return "GREEN", "OPENAI_BASE_URL + OPENAI_API_KEY set"

    missing = []
    if not has_base:
        missing.append("OPENAI_BASE_URL")
    if not has_key:
        missing.append("OPENAI_API_KEY")

    return "YELLOW" if (has_base or has_key) else "RED", f"Missing: {', '.join(missing)}"


def validate_all(codex_dir, config):
    """Validate all 6 targets. Returns list of (target, status, message) tuples."""
    config_path = os.path.join(codex_dir, "config.toml")
    toml_data = _read_toml(config_path)

    results = []

    # Target 1: API endpoint
    status, msg = _check_api_endpoint(toml_data, config)
    results.append((PATCH_TARGETS[0], status, msg))

    # Target 2: Auth
    status, msg = _check_auth(codex_dir, config)
    results.append((PATCH_TARGETS[1], status, msg))

    # Target 3: Analytics
    status, msg = _check_analytics(toml_data)
    results.append((PATCH_TARGETS[2], status, msg))

    # Target 4: Approval
    status, msg = _check_approval(toml_data, config)
    results.append((PATCH_TARGETS[3], status, msg))

    # Target 5: Sandbox
    status, msg = _check_sandbox(toml_data, config)
    results.append((PATCH_TARGETS[4], status, msg))

    # Target 6: Env vars
    status, msg = _check_env_vars(config)
    results.append((PATCH_TARGETS[5], status, msg))

    return results


# ANSI colors
GREEN_C = "\033[92m"
YELLOW_C = "\033[93m"
RED_C = "\033[91m"
BOLD_C = "\033[1m"
RESET_C = "\033[0m"

STATUS_COLORS = {
    "GREEN": GREEN_C,
    "YELLOW": YELLOW_C,
    "RED": RED_C,
}


def print_validation_report(results):
    """Print formatted validation report."""
    print(f"\n  {BOLD_C}Codex Patcher — Validation Report{RESET_C}")
    print("  " + "─" * 50)

    counts = {"GREEN": 0, "YELLOW": 0, "RED": 0}
    for target, status, msg in results:
        color = STATUS_COLORS.get(status, "")
        print(f"  {color}[{status:6s}]{RESET_C}  {target.name}: {target.description}")
        if status != "GREEN":
            print(f"           → {msg}")
        counts[status] = counts.get(status, 0) + 1

    print("  " + "─" * 50)
    total = len(results)
    print(f"  {GREEN_C}{counts['GREEN']}{RESET_C}/{total} GREEN  "
          f"{YELLOW_C}{counts['YELLOW']}{RESET_C} YELLOW  "
          f"{RED_C}{counts['RED']}{RESET_C} RED")

    if counts["GREEN"] == total:
        print(f"\n  {GREEN_C}All targets configured correctly!{RESET_C}")
    elif counts["RED"] > 0:
        print(f"\n  {RED_C}Critical targets missing. Run: python3 codex_patcher.py --apply{RESET_C}")

    return counts
