import sys
import shutil
import time
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich.prompt import Confirm, Prompt
from pathlib import Path
import subprocess

# Import our modules
from . import checks
from . import network
from .client import setup_client
from .server import setup_server, get_server_root, install_server, SERVER_DIR
from .utils import clear_screen, get_project_root

console = Console()

# Check if running in server-only mode
SERVER_MODE = "--server" in sys.argv or "-s" in sys.argv

def run_system_check(interactive=False):
    """Runs a visual pre-flight check of the system."""
    while True: # Loop until healthy or user bails
        clear_screen()
        console.print(Panel("[bold cyan]System Status Check[/bold cyan]", expand=False))
        
        table = Table(show_header=True, header_style="bold magenta")
        table.add_column("Component", style="dim")
        table.add_column("Status")
        table.add_column("Action Needed", style="bold red")

        # -- 1. Flatpak Check --
        if checks.is_flatpak_installed():
            flatpak_status = "[green]✅ Installed[/green]"
            flatpak_action = ""
            has_flatpak = True
        else:
            flatpak_status = "[red]❌ Missing[/red]"
            flatpak_action = "Install Flatpak"
            has_flatpak = False
        table.add_row("Flatpak System", flatpak_status, flatpak_action)

        # -- 2. TES3MP Engine Check --
        if has_flatpak and checks.is_tes3mp_installed():
            engine_status = "[green]✅ Installed[/green]"
            engine_action = ""
            has_engine = True
        else:
            engine_status = "[red]❌ Missing[/red]"
            engine_action = "Run Client Setup" if has_flatpak else "Fix Flatpak First"
            has_engine = False
        table.add_row("TES3MP Engine", engine_status, engine_action)

        # -- 3. System Dependencies --
        missing_deps = checks.check_dependencies()
        if not missing_deps:
            dep_status = "[green]✅ Ready[/green]"
            dep_action = ""
        else:
            dep_status = f"[red]❌ Missing: {', '.join(missing_deps)}[/red]"
            dep_action = "Install System Libs"
        table.add_row("System Deps", dep_status, dep_action)

        # -- 4. Data Files Check --
        data_status = checks.check_data_files(get_project_root())
        if data_status["config_linked"]:
            files_status = "[green]✅ Linked[/green]"
            files_action = ""
        elif data_status["local_present"]:
            files_status = "[yellow]⚠️ Found (Not Linked)[/yellow]"
            files_action = "Run Client Setup"
        else:
            files_status = "[red]❌ Missing[/red]"
            files_action = "Drop files in folder"
        table.add_row("Morrowind Data", files_status, files_action)

        # -- 5. Tailscale Check --
        if checks.is_tailscale_installed():
            ts_status = "[green]✅ Installed[/green]"
            if checks.is_tailscale_running():
                ts_status += " (Running)"
                ts_action = ""
            else:
                ts_status += " [yellow](Stopped)[/yellow]"
                ts_action = "Start Service"
        else:
            ts_status = "[red]❌ Missing[/red]"
            ts_action = "Install Tailscale"
        table.add_row("Tailscale Network", ts_status, ts_action)

        # -- 6. Port Status Check --
        if checks.is_port_free(25565):
            port_status = "[green]✅ Free[/green]"
            port_action = "Ready to Host"
        else:
            port_status = "[yellow]⚠️  In Use[/yellow]"
            port_action = "Server Running?"
        table.add_row("UDP Port 25565", port_status, port_action)

        console.print(table)
        console.print("\n")
        
        # --- Auto-Fix Logic ---
        
        # Priority 0: Deps
        if missing_deps:
            console.print("[red bold]CRITICAL: Missing system libraries![/red bold]")
            console.print(f"Required: {', '.join(missing_deps)}")
            
            # Detect package manager
            install_cmd = None
            pkg_manager = None
            
            # Map library names to package names for common distros
            # Dynamic mapping for robust auto-install
            pkgs = []
            
            # Helper to add if missing
            def add_if_missing(lib_substr, deb_pkg, rpm_pkg, arch_pkg):
                for m in missing_deps:
                    if lib_substr in m:
                        if shutil.which("apt-get"):
                            pkgs.append(deb_pkg)
                        elif shutil.which("dnf"):
                            pkgs.append(rpm_pkg)
                        elif shutil.which("pacman"):
                            pkgs.append(arch_pkg)
                        break

            # Add known dependencies here
            add_if_missing("libzvbi", "libzvbi0", "zvbi", "zvbi")
            add_if_missing("libsnappy", "libsnappy1v5", "snappy", "snappy")
            add_if_missing("libgsm", "libgsm1", "gsm", "gsm")
            add_if_missing("libxml2", "libxml2", "libxml2", "libxml2")
            
            # OpenSceneGraph libraries (libosg*)
            add_if_missing("libosg", "libopenscenegraph-dev", "OpenSceneGraph", "openscenegraph")
            add_if_missing("libOpenThreads", "libopenscenegraph-dev", "OpenSceneGraph", "openscenegraph")
            
            # Boost libraries
            add_if_missing("libboost_system", "libboost-system-dev", "boost-system", "boost-libs")
            add_if_missing("libboost_filesystem", "libboost-filesystem-dev", "boost-filesystem", "boost-libs")
            add_if_missing("libboost_program_options", "libboost-program-options-dev", "boost-program-options", "boost-libs")
            add_if_missing("libboost_iostreams", "libboost-iostreams-dev", "boost-iostreams", "boost-libs")
            
            # Audio/Video libraries
            add_if_missing("libopenal", "libopenal1", "openal-soft", "openal")
            add_if_missing("libavcodec", "libavcodec-dev", "ffmpeg-libs", "ffmpeg")
            add_if_missing("libavformat", "libavformat-dev", "ffmpeg-libs", "ffmpeg")
            add_if_missing("libavutil", "libavutil-dev", "ffmpeg-libs", "ffmpeg")
            add_if_missing("libswscale", "libswscale-dev", "ffmpeg-libs", "ffmpeg")
            add_if_missing("libswresample", "libswresample-dev", "ffmpeg-libs", "ffmpeg")
            
            # UI/Physics libraries
            add_if_missing("libMyGUIEngine", "libmygui-dev", "mygui", "mygui")
            add_if_missing("libBullet", "libbullet-dev", "bullet", "bullet")
            add_if_missing("libLinearMath", "libbullet-dev", "bullet", "bullet")
            
            # Lua (for server)
            add_if_missing("libluajit", "libluajit-5.1-2", "luajit", "luajit")


            if shutil.which("apt-get"):
                pkg_manager = "apt"
                install_cmd = ["sudo", "apt-get", "install", "-y"] + pkgs
            elif shutil.which("dnf"):
                pkg_manager = "dnf"
                install_cmd = ["sudo", "dnf", "install", "-y"] + pkgs
            elif shutil.which("pacman"):
                pkg_manager = "pacman"
                install_cmd = ["sudo", "pacman", "-S", "--noconfirm"] + pkgs

            if install_cmd:
                console.print(f"[yellow]We can try to install these mostly automatically using {pkg_manager}.[/yellow]")
                if Confirm.ask("Install missing libraries now?"):
                    try:
                        subprocess.check_call(install_cmd)
                        console.print("[green]Installation successful! Re-checking...[/green]")
                        continue
                    except subprocess.CalledProcessError:
                        console.print("[red]Installation failed. Please install manually.[/red]")
            
            # Fallback manual instructions
            console.print("[yellow]For Debian/Ubuntu/Mint:[/yellow] sudo apt install libzvbi0")
            console.print("[yellow]For Fedora:[/yellow] sudo dnf install zvbi")
            console.print("[yellow]For Arch:[/yellow] sudo pacman -S zvbi")
            
            if not Confirm.ask("Continue anyway?", default=False):
                sys.exit(1)

        # Priority 1: Flatpak
        if not has_flatpak:
            console.print("[red]CRITICAL: Flatpak is required. Please install it with your distro's package manager.[/red]")
            sys.exit(1)

        # Priority 2: Engine
        if not has_engine:
            if Confirm.ask("[bold yellow]TES3MP Engine is missing. Install it now?[/bold yellow]"):
                console.print("[dim]Running installation...[/dim]")
                setup_client() 
                continue # Re-run checks
            else:
                # User declined, stop nagging but warn
                console.print("[yellow]Warning: You cannot play without the engine.[/yellow]")

        # Priority 3: Data Linkage
        # If we found files but config isn't ready
        if not data_status["config_linked"] and data_status["local_present"]:
             if Confirm.ask("[bold yellow]Data files found but not linked. Link them now?[/bold yellow]"):
                 setup_client()
                 continue

        # If we are here, everything is either good or user declined fixes.
        # If explicit check OR logical issues remain (skipped fixes), pause.
        any_issues_remaining = not (has_engine and data_status["config_linked"])
        
        if interactive or any_issues_remaining:
             Prompt.ask("Press Enter to continue")

        break # If we get here, pass-through to main menu

def run_server_check():
    """Runs a server-specific health check (no Flatpak or client requirements)."""
    clear_screen()
    console.print(Panel("[bold cyan]Server Status Check[/bold cyan]", expand=False))
    
    table = Table(show_header=True, header_style="bold magenta")
    table.add_column("Component", style="dim")
    table.add_column("Status")
    table.add_column("Notes")

    # -- 1. Server Binary Check --
    server_root = get_server_root()
    if server_root and (server_root / "tes3mp-server").exists():
        server_status = "[green]✅ Installed[/green]"
        server_notes = str(server_root)
    else:
        server_status = "[yellow]⚠️ Not Installed[/yellow]"
        server_notes = "Will install on first run"
    table.add_row("Server Binary", server_status, server_notes)

    # -- 2. ESM Files Check --
    from .utils import load_stored_data_path
    esm_path = load_stored_data_path()
    if esm_path and (esm_path / "Morrowind.esm").exists():
        esm_status = "[green]✅ Found[/green]"
        esm_notes = str(esm_path)
    else:
        esm_status = "[yellow]⚠️ Not Set[/yellow]"
        esm_notes = "Configure in Server Menu"
    table.add_row("ESM Files", esm_status, esm_notes)

    # -- 3. Port Check --
    if checks.is_port_free(25565):
        port_status = "[green]✅ Free[/green]"
        port_notes = "Ready to host"
    else:
        port_status = "[yellow]⚠️ In Use[/yellow]"
        port_notes = "Another server running?"
    table.add_row("UDP Port 25565", port_status, port_notes)

    # -- 4. Public IP --
    try:
        import urllib.request
        public_ip = urllib.request.urlopen('https://api.ipify.org', timeout=5).read().decode('utf8')
        ip_status = f"[green]{public_ip}[/green]"
        ip_notes = "Share this with players"
    except Exception:
        ip_status = "[yellow]Unknown[/yellow]"
        ip_notes = "Could not detect"
    table.add_row("Public IP", ip_status, ip_notes)

    # -- 5. Tailscale (optional) --
    if checks.is_tailscale_installed():
        if checks.is_tailscale_running():
            ts_status = "[green]✅ Running[/green]"
            ts_notes = "Private network available"
        else:
            ts_status = "[yellow]Stopped[/yellow]"
            ts_notes = "Run: sudo tailscale up"
    else:
        ts_status = "[dim]Not Installed[/dim]"
        ts_notes = "Optional for private hosting"
    table.add_row("Tailscale", ts_status, ts_notes)

    console.print(table)
    console.print()
    return server_root


def server_main():
    """Entry point for dedicated server mode (no client requirements)."""
    clear_screen()
    console.print(Panel("[bold blue]TES3MP Dedicated Server[/bold blue]", subtitle="Server Mode"))
    console.print("[dim]Running in server-only mode (no Flatpak/client required)[/dim]\n")
    
    run_server_check()
    Prompt.ask("Press Enter to continue to Server Menu")
    
    # Go directly to server setup
    setup_server()


def main():
    # Check for server-only mode
    if SERVER_MODE:
        server_main()
        return
    
    # 1. Run the Health Check immediately on start (silent if good)
    run_system_check(interactive=False)
    
    # 2. Main Menu
    while True:
        clear_screen()
        console.print(Panel("[bold magenta]TES3MP Manager[/bold magenta]", subtitle="Ready to Play"))
        console.print("1. [bold]Launch Game[/bold] (Start Client)")
        console.print("2. [bold]Server Settings[/bold]")
        console.print("3. [bold]Connection Doctor[/bold] (Test Peer)")
        console.print("4. [bold]Re-run Health Check[/bold]")
        console.print("5. [bold]Set Data Files Path[/bold]")
        console.print("6. Exit")
        
        choice = Prompt.ask("Select", choices=["1", "2", "3", "4", "5", "6"])
        
        if choice == "1":
            console.print("[green]Launching TES3MP...[/green]")
            try:
                exe = checks.get_install_dir() / "tes3mp-browser"
                # Set working directory to installation so it finds configs/resources
                subprocess.Popen([str(exe)], cwd=str(checks.get_install_dir()))
                time.sleep(2)
            except Exception as e:
                console.print(f"[red]Failed to launch: {e}[/red]")
                Prompt.ask("Press Enter to continue")
            sys.exit()
        elif choice == "2":
            setup_server()
            Prompt.ask("Press Enter to continue")
        elif choice == "3":
            console.print("\n[bold]Who are you trying to join?[/bold]")
            console.print("Enter their Tailscale IP (e.g., 100.101.50.5)")
            target = Prompt.ask("Target IP")
            network.test_peer_connection(target)
            Prompt.ask("\nPress Enter to return...")
        elif choice == "4":
            run_system_check(interactive=True)
        elif choice == "5":
            from .client import configure_data_path
            configure_data_path()
            Prompt.ask("Press Enter to continue")
        elif choice == "6":
            console.print("[green]Goodbye![/green]")
            sys.exit()

def tailscale_print():
    # Quick re-implementation of the guide
    console.print(Panel("""
[bold green]1. Install Tailscale[/bold green]
   curl -fsSL https://tailscale.com/install.sh | sh
   
[bold green]2. Connect[/bold green]
   sudo tailscale up

[bold green]3. Play[/bold green]
   Host IP: Run 'tailscale ip'
   Port: 25565
    """, title="Tailscale Guide", border_style="blue"))
    Prompt.ask("Press Enter to return")

if __name__ == "__main__":
    main()
