#!/usr/bin/env python3
"""
Codex Patcher Update Pipeline — check, update, patch, validate, test.

Usage:
  python3 update_codex_patcher.py --check       # Check for new version
  python3 update_codex_patcher.py --update      # Download + install new binary
  python3 update_codex_patcher.py --validate    # Validate 6 config targets
  python3 update_codex_patcher.py --patch       # Apply config patches
  python3 update_codex_patcher.py --test        # Integration test
  python3 update_codex_patcher.py --auto        # Full cycle
"""

import json
import os
import sys
import subprocess
import argparse
from pathlib import Path

SCRIPT_DIR = Path(__file__).resolve().parent
sys.path.insert(0, str(SCRIPT_DIR))

# ANSI colors
GREEN = "\033[92m"
YELLOW = "\033[93m"
RED = "\033[91m"
CYAN = "\033[96m"
BOLD = "\033[1m"
RESET = "\033[0m"


def color(text, c):
    return f"{c}{text}{RESET}"


def load_config():
    """Load codex_config.json."""
    config_path = SCRIPT_DIR / "codex_config.json"
    if not config_path.is_file():
        print(f"  {color('Config not found: ' + str(config_path), RED)}")
        sys.exit(1)
    with open(config_path) as f:
        return json.load(f)


def cmd_check(config):
    """Check GitHub releases for new Codex version."""
    print(f"\n{BOLD}Checking for updates...{RESET}")
    try:
        import urllib.request
        url = "https://api.github.com/repos/openai/codex/releases/latest"
        req = urllib.request.Request(url, headers={"User-Agent": "codex-patcher"})
        with urllib.request.urlopen(req, timeout=15) as resp:
            data = json.loads(resp.read())

        latest_tag = data.get("tag_name", "")
        # Tag format: "rust-v0.111.0"
        latest_version = latest_tag.replace("rust-v", "").replace("v", "")

        # Get installed version
        from codex_patcher import detect_codex
        _, installed = detect_codex()

        print(f"  Installed: {CYAN}{installed}{RESET}")
        print(f"  Latest:    {CYAN}{latest_version}{RESET}")

        if installed == latest_version:
            print(f"  {GREEN}Already up to date!{RESET}")
            return True
        else:
            print(f"  {YELLOW}Update available: {installed} → {latest_version}{RESET}")
            return False

    except Exception as e:
        print(f"  {color(f'Error: {e}', RED)}")
        return False


def cmd_update(config):
    """Download and install new Codex binary via update-codex.sh."""
    print(f"\n{BOLD}Updating Codex binary...{RESET}")
    update_script = SCRIPT_DIR / "update-codex.sh"
    if not update_script.is_file():
        print(f"  {color(f'update-codex.sh not found at {update_script}', RED)}")
        return False

    try:
        result = subprocess.run(
            ["bash", str(update_script)],
            timeout=300
        )
        return result.returncode == 0
    except Exception as e:
        print(f"  {color(f'Error: {e}', RED)}")
        return False


def cmd_validate(config):
    """Validate all 6 config targets."""
    print(f"\n{BOLD}Validating config targets...{RESET}")
    try:
        from updater.config_validator import validate_all, print_validation_report
        codex_dir = os.path.expanduser("~/.codex")
        results = validate_all(codex_dir, config)
        counts = print_validation_report(results)

        # Save report
        report_dir = SCRIPT_DIR / "reports"
        report_dir.mkdir(exist_ok=True)
        report_path = report_dir / "validation_report.json"
        summary = {
            "targets": [
                {"name": t.name, "status": s, "message": m}
                for t, s, m in results
            ],
            "counts": counts,
        }
        with open(report_path, "w") as f:
            json.dump(summary, f, indent=2)
        print(f"\n  Report saved: {report_path}")

        return counts.get("RED", 0) == 0
    except Exception as e:
        print(f"  {color(f'Error: {e}', RED)}")
        return False


def cmd_patch(config):
    """Apply config patches."""
    print(f"\n{BOLD}Applying patches...{RESET}")
    try:
        from codex_patcher import apply_all_patches
        ok, results = apply_all_patches(config)
        return ok
    except Exception as e:
        print(f"  {color(f'Error: {e}', RED)}")
        return False


def cmd_test(config):
    """Run integration test."""
    print(f"\n{BOLD}Running integration test...{RESET}")

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

    env = os.environ.copy()
    env["OPENAI_BASE_URL"] = base_url
    env["OPENAI_API_KEY"] = config["api_key"]

    try:
        result = subprocess.run(
            ["codex", "exec",
             "--sandbox", "danger-full-access",
             "Reply with just the number 42"],
            capture_output=True, text=True, timeout=60, env=env
        )

        output = result.stdout.strip()
        print(f"  Output: {output[:200]}")

        if "42" in output:
            print(f"  {GREEN}Test passed!{RESET}")
            return True
        else:
            print(f"  {YELLOW}Unexpected output (no '42' found){RESET}")
            if result.stderr:
                print(f"  Stderr: {result.stderr[:200]}")
            return False

    except subprocess.TimeoutExpired:
        print(f"  {RED}Test timed out (60s){RESET}")
        return False
    except Exception as e:
        print(f"  {color(f'Error: {e}', RED)}")
        return False


def cmd_auto(config):
    """Full cycle: check → update → patch → validate → test."""
    print(f"\n{BOLD}{'=' * 50}{RESET}")
    print(f"{BOLD}  Codex Patcher — Auto Update Pipeline{RESET}")
    print(f"{BOLD}{'=' * 50}{RESET}")

    steps = [
        ("Check version", cmd_check),
        ("Update binary", cmd_update),
        ("Apply patches", cmd_patch),
        ("Validate", cmd_validate),
        ("Test", cmd_test),
    ]

    for name, func in steps:
        ok = func(config)
        if not ok and name not in ("Check version",):
            print(f"\n  {RED}Pipeline stopped at: {name}{RESET}")
            return False

    print(f"\n{GREEN}{'=' * 50}{RESET}")
    print(f"{GREEN}  Pipeline completed successfully!{RESET}")
    print(f"{GREEN}{'=' * 50}{RESET}")
    return True


def main():
    parser = argparse.ArgumentParser(
        description="Codex Patcher Update Pipeline"
    )
    parser.add_argument("--check", action="store_true", help="Check for new version")
    parser.add_argument("--update", action="store_true", help="Update binary")
    parser.add_argument("--validate", action="store_true", help="Validate config")
    parser.add_argument("--patch", action="store_true", help="Apply patches")
    parser.add_argument("--test", action="store_true", help="Run integration test")
    parser.add_argument("--auto", action="store_true", help="Full auto cycle")
    args = parser.parse_args()

    config = load_config()

    if args.auto:
        return 0 if cmd_auto(config) else 1
    if args.check:
        return 0 if cmd_check(config) else 1
    if args.update:
        return 0 if cmd_update(config) else 1
    if args.validate:
        return 0 if cmd_validate(config) else 1
    if args.patch:
        return 0 if cmd_patch(config) else 1
    if args.test:
        return 0 if cmd_test(config) else 1

    parser.print_help()
    return 0


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