"""
Server Manager for AI Knowledge Hub

Manages on-demand startup, monitoring, and shutdown of the FastAPI server.
Implements resource-efficient architecture with automatic idle timeout.
"""

import os
import sys
import subprocess
import socket
import time
import signal
from pathlib import Path
from typing import Dict, Any, Optional

try:
    import requests
except ImportError:
    requests = None


# Configuration
PID_FILE = os.path.expanduser("~/.thinkbank/knowledge_hub.pid")
PORT_DEFAULT = 8765
STARTUP_TIMEOUT = 30  # seconds to wait for server to start
HEALTH_CHECK_INTERVAL = 0.5  # seconds between health checks


def start_server(port: int = PORT_DEFAULT, open_browser: bool = True) -> Dict[str, Any]:
    """
    Start FastAPI server in background.

    Args:
        port: Port number for server (default: 8765)
        open_browser: Whether to open browser automatically (default: True)

    Returns:
        dict: Status with keys: success, message, pid, port, url
    """
    # Check if already running
    if is_server_running(port):
        url = f"http://localhost:{port}"
        print(f"✓ Server already running at {url}")

        if open_browser:
            _open_browser(url)

        return {
            "success": True,
            "message": "Server already running",
            "url": url,
            "port": port
        }

    # Find Python executable
    python_exe = sys.executable

    # Find server module path
    plugin_dir = Path(__file__).parent.parent
    server_module = "thinkbank.server.app:app"

    # Start FastAPI process in background
    try:
        # Use uvicorn to run the server
        process = subprocess.Popen(
            [
                python_exe, "-m", "uvicorn",
                server_module,
                "--port", str(port),
                "--host", "127.0.0.1",
                "--log-level", "warning"
            ],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            start_new_session=True  # Detach from parent process
        )

        # Save PID
        pid_dir = Path(PID_FILE).parent
        pid_dir.mkdir(parents=True, exist_ok=True)

        with open(PID_FILE, 'w') as f:
            f.write(f"{process.pid}\n{port}\n")

        print("⏳ Starting server...", end='', flush=True)

        # Wait for server to be ready
        start_time = time.time()
        while time.time() - start_time < STARTUP_TIMEOUT:
            if check_server_health(port):
                print(" done!")
                break
            time.sleep(HEALTH_CHECK_INTERVAL)
            print(".", end='', flush=True)
        else:
            print(" timeout!")
            return {
                "success": False,
                "message": f"Server failed to start within {STARTUP_TIMEOUT}s"
            }

        url = f"http://localhost:{port}"

        # Open browser
        if open_browser:
            _open_browser(url)

        # Display success message
        print(f"""
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🧠 AI Knowledge Hub Started

Access: {url}
Status: Running (PID: {process.pid})

Tips:
- Run '/knowledge stop' when done
- Auto-stops after 30min idle
- Use '/knowledge status' to check
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
        """)

        return {
            "success": True,
            "message": "Server started successfully",
            "pid": process.pid,
            "port": port,
            "url": url
        }

    except Exception as e:
        return {
            "success": False,
            "message": f"Failed to start server: {str(e)}"
        }


def stop_server() -> Dict[str, Any]:
    """
    Stop FastAPI server.

    Returns:
        dict: Status with keys: success, message
    """
    if not os.path.exists(PID_FILE):
        return {
            "success": False,
            "message": "Server not running (no PID file found)"
        }

    try:
        with open(PID_FILE, 'r') as f:
            lines = f.readlines()
            if len(lines) < 1:
                return {
                    "success": False,
                    "message": "Invalid PID file format"
                }

            pid = int(lines[0].strip())
            port = int(lines[1].strip()) if len(lines) > 1 else PORT_DEFAULT

        # Try to terminate process
        try:
            os.kill(pid, signal.SIGTERM)

            # Wait for process to terminate
            for _ in range(10):
                try:
                    os.kill(pid, 0)  # Check if process exists
                    time.sleep(0.1)
                except ProcessLookupError:
                    # Process terminated
                    break
            else:
                # Force kill if still running
                try:
                    os.kill(pid, signal.SIGKILL)
                except ProcessLookupError:
                    pass

            # Remove PID file
            os.remove(PID_FILE)

            print("✓ Server stopped")
            return {
                "success": True,
                "message": "Server stopped successfully"
            }

        except ProcessLookupError:
            # Process doesn't exist
            os.remove(PID_FILE)
            return {
                "success": False,
                "message": "Server was not running (stale PID file removed)"
            }

    except Exception as e:
        return {
            "success": False,
            "message": f"Error stopping server: {str(e)}"
        }


def get_status() -> Dict[str, Any]:
    """
    Get server status.

    Returns:
        dict: Status with keys: running, pid, port, url, uptime_seconds
    """
    if not os.path.exists(PID_FILE):
        print("⚠ Server not running")
        return {
            "running": False
        }

    try:
        with open(PID_FILE, 'r') as f:
            lines = f.readlines()
            pid = int(lines[0].strip())
            port = int(lines[1].strip()) if len(lines) > 1 else PORT_DEFAULT

        # Check if process is actually running
        try:
            os.kill(pid, 0)
        except ProcessLookupError:
            # Process doesn't exist - clean up stale PID file
            os.remove(PID_FILE)
            print("⚠ Server not running (stale PID file removed)")
            return {
                "running": False
            }

        # Check if server is responding
        url = f"http://localhost:{port}"
        is_healthy = check_server_health(port)

        if is_healthy:
            # Get uptime from health endpoint
            try:
                if requests:
                    response = requests.get(f"{url}/health", timeout=2)
                    uptime = response.json().get('uptime', 0)
                else:
                    uptime = 0
            except:
                uptime = 0

            print(f"""
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🧠 AI Knowledge Hub Status

Status: Running
PID: {pid}
URL: {url}
Uptime: {int(uptime)}s

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
            """)

            return {
                "running": True,
                "pid": pid,
                "port": port,
                "url": url,
                "uptime_seconds": uptime
            }
        else:
            print(f"⚠ Server process running (PID: {pid}) but not responding")
            return {
                "running": True,
                "pid": pid,
                "port": port,
                "url": url,
                "healthy": False
            }

    except Exception as e:
        print(f"⚠ Error checking status: {str(e)}")
        return {
            "running": False,
            "error": str(e)
        }


def is_server_running(port: int = PORT_DEFAULT) -> bool:
    """
    Check if server is running on specified port.

    Args:
        port: Port to check

    Returns:
        bool: True if server is listening on port
    """
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        try:
            s.connect(('127.0.0.1', port))
            return True
        except (ConnectionRefusedError, OSError):
            return False


def check_server_health(port: int = PORT_DEFAULT) -> bool:
    """
    Check if server is responding to health checks.

    Args:
        port: Port to check

    Returns:
        bool: True if server responds with 200
    """
    if not requests:
        # Fallback to socket check if requests not available
        return is_server_running(port)

    try:
        response = requests.get(
            f"http://localhost:{port}/health",
            timeout=2
        )
        return response.status_code == 200
    except:
        return False


def _open_browser(url: str) -> None:
    """
    Open URL in default browser.

    Args:
        url: URL to open
    """
    import webbrowser
    try:
        webbrowser.open(url)
    except Exception:
        # Silently fail if browser can't be opened
        pass


def restart_server(port: int = PORT_DEFAULT) -> Dict[str, Any]:
    """
    Restart server (stop + start).

    Args:
        port: Port number

    Returns:
        dict: Status from start_server
    """
    stop_result = stop_server()
    if not stop_result['success'] and 'not running' not in stop_result['message'].lower():
        return stop_result

    # Wait a moment for port to be released
    time.sleep(1)

    return start_server(port, open_browser=False)
