"""
Proxy management routes for OpenClaw.
Starts LLM proxy that captures ALL LLM traffic (TUI, Telegram, API, etc.).
"""

import asyncio
import logging
import socket
import subprocess
import sys
from typing import Optional

from fastapi import APIRouter
from pydantic import BaseModel

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/proxy", tags=["Proxy"])

# Global proxy process reference and state
_llm_proxy_process: Optional[subprocess.Popen] = None
_current_provider: str = "openai"
_current_integration: str = None  # Which integration started the proxy (openclaw, ollama, langchain, etc.)
_proxy_running_in_process: bool = False  # Set when proxy runs via --proxy --web
_started_with_openclaw: bool = False  # Set when proxy is started with --openclaw flag

# Supported providers
PROVIDERS = ["openai", "anthropic", "groq", "deepseek", "mistral", "xai", "gemini", "together", "cohere", "cerebras", "moonshot", "minimax"]


def _get_proxy_port() -> int:
    """Return the proxy port — set by main.py via SV_PROXY_PORT, defaults to 8742."""
    import os
    return int(os.environ.get('SV_PROXY_PORT', '8742'))


def _is_port_in_use(port: int) -> bool:
    """Check if a port is in use (proxy might be running)."""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        try:
            s.bind(("127.0.0.1", port))
            return False  # Port is free
        except OSError:
            return True  # Port is in use


def set_proxy_running_in_process(running: bool, provider: str = "openai", integration: str = None):
    """Called by main.py when proxy is started via --proxy --web flag."""
    global _proxy_running_in_process, _current_provider, _current_integration
    _proxy_running_in_process = running
    if running:
        _current_provider = provider
        _current_integration = integration


def auto_start_from_config(integration: str, mode: str, host: str, port: int, provider: Optional[str] = None) -> bool:
    """
    Auto-start the proxy as a subprocess from svconfig.yml settings.
    Sets all globals so status/stop work correctly from the UI.
    Returns True if started successfully.
    """
    global _llm_proxy_process, _current_provider, _current_integration, _multi_mode, _started_with_openclaw

    if _llm_proxy_process is not None and _llm_proxy_process.poll() is None:
        return True  # Already running
    if _is_port_in_use(port):
        return True  # Already running externally

    multi = (mode == "multi-provider")

    # Validate: single mode requires a provider
    if not multi and not provider:
        raise ValueError(
            "svconfig.yml: 'proxy.provider' is required when mode is 'single'.\n"
            "Example:\n"
            "  proxy:\n"
            "    mode: single\n"
            "    provider: openai\n"
            "Valid options: openai, anthropic, gemini, groq, mistral, grok, ollama"
        )

    effective_provider = provider or "openai"

    # Web app port — used so the subprocess knows where to report threats
    import os as _os
    web_port = int(_os.environ.get('SV_WEB_PORT', '8741'))

    if integration == "openclaw":
        # When running from a PyInstaller binary, sys.executable IS the app binary.
        # The "securevector-app" console script only exists in pip installs.
        executable = sys.executable if getattr(sys, "frozen", False) else "securevector-app"
        cmd = [executable, "--proxy", "--openclaw",
               "--proxy-port", str(port), "--port", str(web_port)]
        if multi:
            cmd.append("--multi")
        else:
            cmd.extend(["--provider", effective_provider])
    else:
        if getattr(sys, "frozen", False):
            # PyInstaller binary: run self with --proxy flags (no -m support in frozen env)
            cmd = [sys.executable, "--proxy",
                   "--proxy-port", str(port), "--port", str(web_port)]
        else:
            cmd = [sys.executable, "-m", "securevector.integrations.openclaw_llm_proxy",
                   "--port", str(port),
                   "--securevector-url", f"http://127.0.0.1:{web_port}"]
        if multi:
            cmd.append("--multi")
        else:
            cmd.extend(["--provider", effective_provider])

    try:
        _llm_proxy_process = subprocess.Popen(cmd, stderr=subprocess.PIPE)
        import time; time.sleep(0.5)
        if _llm_proxy_process.poll() is None:
            _current_provider = "multi" if multi else effective_provider
            _current_integration = integration
            _multi_mode = multi
            _started_with_openclaw = (integration == "openclaw")
            logger.info(f"[svconfig] Proxy auto-started: integration={integration}, mode={mode}, provider={effective_provider}, port={port}")
            return True
        else:
            # Process exited immediately — openclaw/pi-ai likely not installed, or config error
            # This is non-fatal: user may be using a different agent framework
            logger.warning(
                f"[svconfig] Proxy exited immediately (code={_llm_proxy_process.poll()}). "
                f"OpenClaw may not be installed, or this user is using a different agent framework. "
                f"Starting without proxy — use the Integrations page to start it manually."
            )
    except FileNotFoundError:
        logger.warning(f"[svconfig] Proxy command not found ({cmd[0]}). Starting without proxy.")
    except Exception as e:
        logger.warning(f"[svconfig] Could not auto-start proxy: {e}")
    return False


class StartProxyRequest(BaseModel):
    provider: str = "openai"
    multi: bool = False
    integration: str = None  # Which integration is starting the proxy (langchain, ollama, crewai, etc.)


# Track if multi-mode is active
_multi_mode = False


@router.get("/status")
async def get_proxy_status():
    """Get the current status of the LLM proxy."""
    global _llm_proxy_process, _multi_mode

    running = False

    # Check 1: Proxy running in same process (via --proxy --web)
    if _proxy_running_in_process:
        running = True
    # Check 2: Proxy running as subprocess (started via UI button)
    elif _llm_proxy_process is not None:
        poll_result = _llm_proxy_process.poll()
        running = poll_result is None
        if not running:
            _llm_proxy_process = None
            _multi_mode = False
    # Check 3: Proxy port is in use (proxy started externally)
    elif _is_port_in_use(_get_proxy_port()):
        running = True

    proxy_port = _get_proxy_port()
    return {
        "running": running,
        "port": proxy_port,
        "provider": _current_provider if running else None,
        "integration": _current_integration if running else None,
        "multi": _multi_mode if running else False,
        "openclaw": _started_with_openclaw if running else False,
        "in_process": _proxy_running_in_process,
        "providers": PROVIDERS,
        "llm_proxy": {"running": running, "port": proxy_port},
    }


@router.post("/start")
async def start_proxy(request: StartProxyRequest = None):
    """Start the LLM proxy that captures ALL LLM traffic."""
    global _llm_proxy_process, _current_provider, _current_integration, _multi_mode

    provider = request.provider if request else "openai"
    multi = request.multi if request else False
    integration = request.integration if request else None
    if provider not in PROVIDERS:
        provider = "openai"

    # Check if already running
    if _llm_proxy_process is not None and _llm_proxy_process.poll() is None:
        mode_str = "multi-provider" if _multi_mode else _current_provider
        return {"status": "already_running", "message": f"Proxy already running ({mode_str}). Stop it first."}

    proxy_port = _get_proxy_port()

    # Check if port is in use (started externally)
    if _is_port_in_use(proxy_port):
        return {"status": "already_running", "message": f"Proxy already running on port {proxy_port} (started externally)"}

    try:
        import os as _os
        web_port = int(_os.environ.get('SV_WEB_PORT', '8741'))

        # Build command - use securevector-app for OpenClaw to enable patching
        if integration == 'openclaw':
            # Use securevector-app command for OpenClaw to trigger patching logic
            cmd = [
                "securevector-app",
                "--proxy",
                "--openclaw",
                "--proxy-port", str(proxy_port),
                "--port", str(web_port),
            ]
            if multi:
                cmd.append("--multi")
            else:
                cmd.extend(["--provider", provider])
        else:
            # Use direct module call for other integrations
            cmd = [
                sys.executable,
                "-m",
                "securevector.integrations.openclaw_llm_proxy",
                "--port", str(proxy_port),
                "--securevector-url", f"http://127.0.0.1:{web_port}",
                "-v",  # verbose mode
            ]
            if multi:
                cmd.append("--multi")
            else:
                cmd.extend(["--provider", provider])

        # Start LLM proxy
        _llm_proxy_process = subprocess.Popen(cmd)

        # Wait a moment to check if it started successfully
        await asyncio.sleep(0.5)

        if _llm_proxy_process.poll() is None:
            _current_provider = provider
            _current_integration = integration
            _multi_mode = multi
            mode_str = "multi-provider" if multi else provider
            integration_str = f" for {integration}" if integration else ""
            logger.info(f"LLM proxy started on port {proxy_port} ({mode_str}){integration_str}")
            return {
                "status": "started",
                "message": f"Proxy started ({mode_str}) on port {proxy_port}",
                "provider": provider,
                "integration": integration,
                "multi": multi,
            }
        else:
            return {"status": "error", "message": "Proxy failed to start"}

    except Exception:
        logger.exception("Failed to start LLM proxy")
        return {"status": "error", "message": "Failed to start proxy"}


def set_openclaw_mode(enabled: bool):
    """Called when proxy is started with --openclaw flag."""
    global _started_with_openclaw, _current_integration
    _started_with_openclaw = enabled
    if enabled:
        _current_integration = "openclaw"


@router.post("/stop")
async def stop_proxy():
    """Stop the LLM proxy and revert pi-ai files if started with --openclaw."""
    global _llm_proxy_process, _current_integration, _started_with_openclaw

    if _llm_proxy_process is None and not _proxy_running_in_process:
        return {"status": "not_running", "message": "LLM proxy is not running"}

    # If running in-process (via --proxy --web CLI flag), can't stop from UI
    if _proxy_running_in_process:
        return {"status": "error", "message": "Proxy was started via CLI (--proxy --web). Use Ctrl+C to stop the app, or start via the UI instead."}

    try:
        _llm_proxy_process.terminate()
        _llm_proxy_process.wait(timeout=5)
        logger.info("LLM proxy stopped")
        result = {"status": "stopped", "message": "LLM proxy stopped"}
    except subprocess.TimeoutExpired:
        _llm_proxy_process.kill()
        result = {"status": "stopped", "message": "LLM proxy killed (timeout)"}
    except Exception:
        result = {"status": "error", "message": "Error stopping LLM proxy"}

    _llm_proxy_process = None
    _current_integration = None

    # Only revert pi-ai files if started with --openclaw
    if _started_with_openclaw:
        try:
            from securevector.app.main import revert_provider_proxy
            revert_provider_proxy(_current_provider, quiet=True)
            logger.info(f"Reverted pi-ai files for {_current_provider}")
            result["reverted"] = True
        except Exception as e:
            logger.warning(f"Could not revert pi-ai files: {e}")
        _started_with_openclaw = False

    return result


@router.post("/revert")
async def revert_proxy():
    """Revert pi-ai files to original state (remove SecureVector proxy patches)."""
    try:
        from securevector.app.main import revert_proxy as do_revert

        # Run the revert in a thread to avoid blocking
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(None, do_revert)

        logger.info("Proxy files reverted successfully")
        return {"status": "success", "message": "Pi-ai files reverted to original state"}
    except Exception:
        logger.exception("Failed to revert proxy files")
        return {"status": "error", "message": "Failed to revert proxy files"}
