"""Pipeline: levanta el geo stack Docker (Valhalla + PostGIS + Martin) y verifica servicios."""

from __future__ import annotations

import json
import os
import subprocess
import sys
import time
from urllib import request as urllib_request
from urllib.error import URLError

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", ".."))

from python.functions.infra.docker_container_running import docker_container_running

POSTGIS_CONTAINER = "better_maps_postgis"
MARTIN_CONTAINER = "better_maps_martin"
VALHALLA_CONTAINER = "better_maps_valhalla"


def setup_geo_stack_docker_pipeline(
    compose_path: str = "apps/footprint_geo_stack/docker-compose.yml",
    wait_seconds: int = 60,
    verify: bool = True,
) -> dict:
    """Levanta el geo stack via docker compose y verifica que los servicios responden.

    Si verify=True, los flags se calculan independientemente del resultado de
    `docker compose up -d`: si los contenedores ya estan vivos (lanzados
    previamente con su .env correcto) la verificacion sigue funcionando aunque
    el `up` actual falle por variables de entorno faltantes.

    Returns:
        Dict con claves:
          "docker_up"   (bool): True si docker compose arrancó sin error.
          "valhalla_ok" (bool): True si Valhalla responde a /status.
          "postgis_ok"  (bool): True si el contenedor postgis está vivo y pg_isready OK.
          "martin_ok"   (bool): True si Martin responde a /health.
    """
    result = {
        "docker_up": False,
        "valhalla_ok": False,
        "postgis_ok": False,
        "martin_ok": False,
    }

    # Step 1: docker compose up -d (best-effort; no bloquea verify si falla)
    try:
        proc = subprocess.run(
            ["docker", "compose", "-f", compose_path, "up", "-d"],
            capture_output=True,
            text=True,
            timeout=120,
        )
        result["docker_up"] = proc.returncode == 0
    except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
        result["docker_up"] = False

    if not verify:
        return result

    # Step 2: esperar a que los servicios esten listos (solo si acabamos de levantar)
    if result["docker_up"] and wait_seconds > 0:
        time.sleep(wait_seconds)

    # Step 3: Valhalla — /status responde JSON
    try:
        req = urllib_request.Request("http://localhost:8002/status", method="GET")
        with urllib_request.urlopen(req, timeout=10) as resp:
            data = json.loads(resp.read().decode())
            result["valhalla_ok"] = isinstance(data, dict)
    except (URLError, OSError, json.JSONDecodeError):
        result["valhalla_ok"] = False

    # Step 4: PostGIS — contenedor vivo + pg_isready
    if docker_container_running(POSTGIS_CONTAINER):
        try:
            proc = subprocess.run(
                ["docker", "exec", POSTGIS_CONTAINER, "pg_isready", "-U", "geoserver", "-d", "gis"],
                capture_output=True,
                text=True,
                timeout=15,
            )
            result["postgis_ok"] = proc.returncode == 0
        except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
            result["postgis_ok"] = False

    # Step 5: Martin — /health responde 200 (con fallback a contenedor vivo)
    try:
        req = urllib_request.Request("http://localhost:3000/health", method="GET")
        with urllib_request.urlopen(req, timeout=10) as resp:
            result["martin_ok"] = resp.status == 200
    except (URLError, OSError):
        result["martin_ok"] = docker_container_running(MARTIN_CONTAINER)

    return result
