import socket
import time
from pathlib import Path

from flashenv.config import PRIV_KEY_PATH
from fabric import Connection
from invoke.exceptions import UnexpectedExit
from paramiko.ssh_exception import NoValidConnectionsError, SSHException
from rich.console import Console

console = Console()
key_path = PRIV_KEY_PATH
user = "ec2-user"


def wait_for_ssh(ip: str, user: str, key_path: Path, retries: int = 30, delay: int = 5):
    """
    Polls the server until SSH is available.
    """
    connect_kwargs = {"key_filename": str(key_path), "look_for_keys": False, "timeout": 5}

    for _i in range(retries):
        try:
            with Connection(host=ip, user=user, connect_kwargs=connect_kwargs) as c:
                c.run("whoami", hide=True, warn=True)
                return True
        except (NoValidConnectionsError, socket.timeout, SSHException, OSError):
            time.sleep(delay)
            continue

    return False


def provision_instance(ip: str, image_name: str):
    """
    Connects to the instance and runs the installation commands live.
    """
    with console.status(f"[bold yellow]⏳ Waiting for SSH to become available on {ip}..."):
        ready = wait_for_ssh(ip, user, key_path)
        if not ready:
            raise Exception("Timed out waiting for SSH connection.")
    console.log(f"✅ SSH is ready on {ip}.")

    conn = Connection(host=ip, user=user, connect_kwargs={"key_filename": str(key_path), "banner_timeout": 200})

    try:
        with console.status("[bold blue]📦 Updating system packages..."):
            conn.sudo("dnf update -y", hide=True)
            console.log("✅ System updated.")

        with console.status("[bold blue]🐳 Installing Docker..."):
            conn.sudo("dnf install -y docker", hide=True)
            conn.sudo("systemctl start docker", hide=True)
            conn.sudo("systemctl enable docker", hide=True)
            conn.sudo("usermod -aG docker ec2-user", hide=True)
            console.log("✅ Docker installed and started.")

        with console.status(f"[bold cyan]🚀 Pulling and running '{image_name}'..."):
            conn.sudo(f"docker run -d -p 80:80 --restart always --name app {image_name}", hide=True)
            console.log(f"✅ Container '{image_name}' is running.")

    except UnexpectedExit as e:
        console.print(f"[red]❌ Command failed:[/red] {e}")
        raise e
    except Exception as e:
        console.print(f"[red]❌ Provisioning error:[/red] {e}")
        raise e
    finally:
        conn.close()


def fetch_container_logs(ip: str, container_name: str = "app") -> str:
    """
    Connects via SSH (Fabric) and retrieves the remote Docker container logs.
    """
    conn = Connection(
        host=ip, user=user, connect_kwargs={"key_filename": str(key_path), "timeout": 10, "banner_timeout": 200}
    )

    try:
        result = conn.sudo(f"docker logs {container_name}", hide=True)
        return result.stdout.strip()
    except UnexpectedExit as e:
        error_msg = e.result.stderr.strip() if e.result else "Unknown error"
        return f"❌ Error fetching logs: {error_msg}"
    except Exception as e:
        return f"❌ Connection failed: {e}"
    finally:
        conn.close()
