# tests/test_docker_build.py
import os
import shutil
import subprocess
import sys
import time

import pytest
import requests


IMAGE_NAME = "manual_slop:test"
CONTAINER_NAME = "manual_slop_test_container"
WEB_PORT = 18080
HOOK_PORT = 18999


def _docker_daemon_ready() -> bool:
    result = subprocess.run(
        ["docker", "info"],
        capture_output=True,
        text=True,
        timeout=10,
    )
    return result.returncode == 0


def _start_docker_desktop() -> bool:
    if sys.platform != "win32":
        return False
    docker_paths = [
        os.path.expandvars(r"%ProgramFiles%\Docker\Docker\Docker Desktop.exe"),
        os.path.expandvars(r"%LOCALAPPDATA%\Docker\Docker Desktop.exe"),
        r"C:\Program Files\Docker\Docker\Docker Desktop.exe",
        r"C:\Users\Ed\AppData\Local\Docker\Docker Desktop.exe",
    ]
    for path in docker_paths:
        if os.path.exists(path):
            try:
                subprocess.Popen([path], shell=False)
                return True
            except Exception:
                pass
    service_result = subprocess.run(
        ["net", "start", "com.docker.service"],
        capture_output=True,
        text=True,
        timeout=10,
    )
    if service_result.returncode == 0:
        return True
    return False


def _wait_for_docker(timeout: int = 60) -> bool:
    start = time.time()
    while time.time() - start < timeout:
        if _docker_daemon_ready():
            return True
        time.sleep(2)
    return False


@pytest.fixture(scope="module")
def ensure_docker():
    """Ensure Docker daemon is running before running tests."""
    if os.environ.get("RUN_DOCKER_TEST") != "1":
        pytest.skip("Set RUN_DOCKER_TEST=1 to enable")

    if not shutil.which("docker"):
        pytest.skip("Docker CLI not installed")

    if _docker_daemon_ready():
        yield
        return

    started = _start_docker_desktop()
    if not started:
        pytest.skip(
            "Docker daemon not running and Docker Desktop not found/installed. "
            "Please install Docker Desktop on this system."
        )

    ready = _wait_for_docker()
    if not ready:
        pytest.skip("Docker daemon did not become ready within 60s")

    yield


@pytest.mark.docker
def test_docker_image_builds(ensure_docker, tmp_path):
    """Build the Docker image. Slow; opt-in."""
    repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    result = subprocess.run(
        ["docker", "build", "-t", IMAGE_NAME, "."],
        cwd=repo_root,
        capture_output=True, text=True, timeout=600,
    )
    assert result.returncode == 0, f"Docker build failed: {result.stderr}"


@pytest.mark.docker
def test_docker_container_starts_and_responds(ensure_docker):
    """Run the container, verify web and hook endpoints respond."""
    _cleanup_container()

    repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    result = subprocess.run(
        [
            "docker", "run", "-d",
            "--name", CONTAINER_NAME,
            "-p", f"{WEB_PORT}:8080",
            "-p", f"{HOOK_PORT}:8999",
            IMAGE_NAME,
        ],
        cwd=repo_root,
        capture_output=True, text=True, timeout=30,
    )
    assert result.returncode == 0, f"Docker run failed: {result.stderr}"

    try:
        start = time.time()
        ready = False
        while time.time() - start < 90:
            try:
                r = requests.get(f"http://127.0.0.1:{HOOK_PORT}/status", timeout=1)
                if r.status_code == 200:
                    ready = True
                    break
            except (requests.ConnectionError, requests.Timeout):
                pass
            time.sleep(1)
        assert ready, "Container hook API did not respond within 90s"

        r = requests.get(f"http://127.0.0.1:{WEB_PORT}/", timeout=5)
        assert r.status_code == 200
        body = r.content.lower()
        assert b"<html" in body or b"<!doctype" in body, "Web endpoint did not return HTML"

    finally:
        _cleanup_container()


def _cleanup_container() -> None:
    subprocess.run(
        ["docker", "rm", "-f", CONTAINER_NAME],
        capture_output=True,
    )