import subprocess
import socket
import psutil
import webbrowser
import time
import os

import logging
from shimoku.execution_logger import log_error

logger = logging.getLogger(__name__)


def check_server(server_host: str, server_port: int):
    """
    Check if the server is already running.
    :param server_host: The server host.
    :param server_port: The port where the server is running.
    """
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    result = sock.connect_ex((server_host, server_port))
    sock.close()
    return result == 0


def kill_server(server_host: str, server_port: int):
    """
    Kill the server process.
    """
    cmd_line = ["local_server:app", "--host", server_host, "--port", str(server_port)]

    for process in psutil.process_iter(["pid", "name", "cmdline"]):
        if process.info["cmdline"] is not None and (
            len(process.info["cmdline"]) - 2 == len(cmd_line)
            and all(
                [
                    elm1 == elm2
                    for elm1, elm2 in zip(cmd_line, process.info["cmdline"][2:])
                ]
            )
        ):
            server_pid = None
            try:
                server_pid = process.info["pid"]
                proc = psutil.Process(server_pid)
                proc.terminate()
                print(f"Server (PID: {server_pid}) terminated gracefully.")
            except psutil.NoSuchProcess:
                print(f"Process with PID {server_pid} not found.")


def create_server(
    environment: str, server_host: str, server_port: int, open_server_browser: bool
):
    """
    Create a new server process and open the server URL in the default web browser.
    :param server_host: The server host.
    :param server_port: The port where the server will run.
    :param open_server_browser: Whether to open the server URL in the default web browser.
    """
    base_path = os.path.dirname(os.path.abspath(__file__))
    # Set the PYTHONPATH to include the directory of your FastAPI module
    env = os.environ.copy()
    env["PYTHONPATH"] = base_path + os.pathsep + env.get("PYTHONPATH", "")

    server_process = subprocess.Popen(
        [
            "uvicorn",
            "local_server:app",
            "--host",
            server_host,
            "--port",
            str(server_port),
        ],
        env=env,
        stdout=subprocess.DEVNULL,
    )

    print(f"Server started (PID: {server_process.pid})")

    max_time = 5
    # Wait for the server to fully initialize
    while not check_server(server_host, server_port):
        time.sleep(0.1)
        max_time -= 0.1
        if max_time <= 0:
            log_error(logger, "Server not initialized after 5 seconds.", RuntimeError)

    if open_server_browser:
        # Open the server URL in the default web browser
        webbrowser.open(f"http://{server_host}:{server_port}/graphql")

    environment_prefix = ""
    if environment != "production":
        if environment.lower() in "development":
            environment = "develop"
        environment_prefix = f"{environment}."

    webbrowser.open(
        f"http://{environment_prefix}shimoku.io/playground?port={server_port}"
    )


def main():
    server_host = "127.0.0.1"
    server_port = 8000
    kill_server_flag = True
    server_running = check_server(server_host, server_port)
    if server_running:
        print("Server already running")
        if kill_server_flag:
            kill_server()
            server_running = False

    if not server_running:
        create_server(server_host, server_port, True)


if __name__ == "__main__":
    main()
