"""
Docker utilities for managing containers and networks
"""

import subprocess
import json
from typing import Dict, List, Optional
from datetime import datetime


class DockerManager:
    """Manages Docker containers and networks"""

    @staticmethod
    def run_command(cmd: str) -> Optional[str]:
        """Run shell command and return output"""
        try:
            result = subprocess.run(
                cmd, shell=True, capture_output=True, text=True, check=True
            )
            return result.stdout.strip()
        except subprocess.CalledProcessError:
            return None

    @staticmethod
    def get_container_status(service_path: str) -> Dict:
        """Get status of containers for a service path

        Args:
            service_path: Path like 'infrastructure/traefik/default'
        """
        from .config import Config

        compose_dir = Config.INSTALL_DIR / service_path
        compose_file = compose_dir / "docker-compose.yml"

        if not compose_file.exists():
            return {
                "status": "not_created",
                "uptime": None,
                "ports": [],
                "container_name": service_path
            }

        # Use docker compose to get container status
        cmd = f"docker compose -f {compose_file} ps --format json 2>/dev/null"
        output = DockerManager.run_command(cmd)

        if not output:
            return {
                "status": "not_created",
                "uptime": None,
                "ports": [],
                "container_name": service_path
            }

        try:
            # Parse JSON output (one JSON object per line)
            containers = []
            for line in output.strip().split('\n'):
                if line.strip():
                    containers.append(json.loads(line))

            if not containers:
                return {
                    "status": "stopped",
                    "uptime": None,
                    "ports": [],
                    "container_name": service_path
                }

            # Check if any container is running
            running = any(c.get("State") == "running" for c in containers)
            container_names = [c.get("Name", "") for c in containers]

            # Get ports from first container
            ports = []
            for c in containers:
                publishers = c.get("Publishers") or []
                for p in publishers:
                    if p.get("PublishedPort"):
                        ports.append(f"{p.get('PublishedPort')}/{p.get('Protocol', 'tcp')}")

            # Get uptime from first running container
            uptime_str = None
            for c in containers:
                if c.get("State") == "running":
                    # RunningFor is like "10 minutes ago"
                    uptime_str = c.get("RunningFor", "").replace(" ago", "")
                    break

            return {
                "status": "running" if running else "stopped",
                "uptime": uptime_str,
                "ports": ports[:5],  # Limit ports shown
                "container_name": ", ".join(container_names)
            }
        except:
            return {
                "status": "stopped",
                "uptime": None,
                "ports": [],
                "container_name": service_path
            }

    @staticmethod
    def _format_uptime(timedelta) -> str:
        """Format timedelta for uptime display"""
        total_seconds = int(timedelta.total_seconds())
        days = total_seconds // 86400
        hours = (total_seconds % 86400) // 3600
        minutes = (total_seconds % 3600) // 60

        if days > 0:
            return f"{days}d {hours}h {minutes}m"
        elif hours > 0:
            return f"{hours}h {minutes}m"
        else:
            return f"{minutes}m"

    @staticmethod
    def get_network_status(network_name: str) -> Dict:
        """Get status of a network"""
        networks = DockerManager.run_command("docker network ls --format '{{.Name}}'")
        if not networks or network_name not in networks:
            return {"exists": False, "container_count": 0}

        # Get connected containers
        inspect_cmd = f"docker network inspect {network_name} --format '{{{{len .Containers}}}}'"
        count = DockerManager.run_command(inspect_cmd)
        container_count = int(count) if count and count.isdigit() else 0

        return {"exists": True, "container_count": container_count}

    @staticmethod
    def start_service(service_name: str, compose_dir: str) -> bool:
        """Start a service using docker-compose"""
        cmd = f"cd {compose_dir} && docker-compose up -d"
        output = DockerManager.run_command(cmd)
        return output is not None

    @staticmethod
    def stop_service(service_name: str, compose_dir: str) -> bool:
        """Stop a service using docker-compose"""
        cmd = f"cd {compose_dir} && docker-compose down"
        output = DockerManager.run_command(cmd)
        return output is not None

    @staticmethod
    def get_service_logs(service_name: str, tail: int = 100) -> Optional[str]:
        """Get logs from a service container"""
        container_name = f"infra_{service_name}"
        cmd = f"docker logs --tail {tail} {container_name}"
        return DockerManager.run_command(cmd)

    @staticmethod
    def check_docker() -> bool:
        """Check if Docker is running"""
        output = DockerManager.run_command("docker info > /dev/null 2>&1")
        return output is not None
