from __future__ import annotations

import os
import sys
import subprocess
from pathlib import Path
from typing import Optional

from SYS.config import load_config
from SYS.logger import debug, log

_zt_server_proc: Optional[subprocess.Popen] = None
_zt_server_last_config: Optional[str] = None

# We no longer use atexit here because explicit lifecycle management 
# is preferred in TUI/REPL, and background servers use a monitor thread 
# to shut down when the parent dies. 
# atexit.register(lambda: stop_zerotier_server())

def ensure_zerotier_server_running() -> None:
    """Check config and ensure the ZeroTier storage server is running if needed."""
    global _zt_server_proc, _zt_server_last_config

    try:
        # Load config from the project root (where config.conf typically lives)
        repo_root = Path(__file__).resolve().parent.parent
        cfg = load_config(repo_root)
    except Exception:
        return

    zt_conf = cfg.get("networking", {}).get("zerotier", {})
    serve_target = zt_conf.get("serve")
    port = zt_conf.get("port") or 999
    api_key = zt_conf.get("api_key")

    # Config hash to detect changes
    config_id = f"{serve_target}|{port}|{api_key}"
    
    # Check if proc is still alive
    if _zt_server_proc:
        if _zt_server_proc.poll() is not None:
             # Process died
             debug("ZeroTier background server died. Restarting...")
             _zt_server_proc = None
        elif config_id == _zt_server_last_config:
             # Already running with correct config
             return

    # If config changed and we have a proc, stop it
    if _zt_server_proc and config_id != _zt_server_last_config:
        debug("ZeroTier server config changed. Stopping old process...")
        try:
            _zt_server_proc.terminate()
            _zt_server_proc.wait(timeout=2)
        except Exception:
            try:
                _zt_server_proc.kill()
            except Exception:
                pass
        _zt_server_proc = None

    _zt_server_last_config = config_id

    if not serve_target:
        return

    # Resolve path
    storage_path = None
    folders = cfg.get("store", {}).get("folder", {})
    for name, block in folders.items():
        if name.lower() == serve_target.lower():
            storage_path = block.get("path") or block.get("PATH")
            break
    
    if not storage_path:
        # Fallback to direct path
        storage_path = serve_target

    if not storage_path or not Path(storage_path).exists():
        debug(f"ZeroTier host target '{serve_target}' not found at {storage_path}. Cannot start server.")
        return

    repo_root = Path(__file__).resolve().parent.parent
    server_script = repo_root / "scripts" / "remote_storage_server.py"

    if not server_script.exists():
        debug(f"ZeroTier server script not found at {server_script}")
        return

    # Use the same python executable that is currently running
    # On Windows, explicitly prefer the .venv python if it exists
    python_exe = sys.executable
    if sys.platform == "win32":
        venv_py = repo_root / ".venv" / "Scripts" / "python.exe"
        if venv_py.exists():
            python_exe = str(venv_py)

    cmd = [python_exe, str(server_script), 
           "--storage-path", str(storage_path), 
           "--port", str(port),
           "--monitor"]
    cmd += ["--parent-pid", str(os.getpid())]
    if api_key:
        cmd += ["--api-key", str(api_key)]

    try:
        debug(f"Starting ZeroTier storage server: {cmd}")
        # Capture errors to a log file instead of DEVNULL
        log_file = repo_root / "zt_server_error.log"
        with open(log_file, "a") as f:
            f.write(f"\n--- Starting server at {__import__('datetime').datetime.now()} ---\n")
            f.write(f"Command: {' '.join(cmd)}\n")
            f.write(f"CWD: {repo_root}\n")
            f.write(f"Python: {python_exe}\n")
        
        err_f = open(log_file, "a")
        # On Windows, CREATE_NO_WINDOW = 0x08000000 ensures no console pops up
        import subprocess
        _zt_server_proc = subprocess.Popen(
            cmd, 
            stdout=subprocess.DEVNULL, 
            stderr=err_f,
            cwd=str(repo_root),
            creationflags=0x08000000 if sys.platform == "win32" else 0
        )
        log(f"ZeroTier background server started on port {port} (sharing {serve_target})")
    except Exception as e:
        debug(f"Failed to start ZeroTier server: {e}")
        _zt_server_proc = None

def stop_zerotier_server() -> None:
    """Stop the background server if it is running."""
    global _zt_server_proc
    if _zt_server_proc:
        try:
            _zt_server_proc.terminate()
            _zt_server_proc.wait(timeout=2)
        except Exception:
            try:
                _zt_server_proc.kill()
            except Exception:
                pass
        _zt_server_proc = None
