"""
Y Build SDK Data Models

Typed data classes for API responses.
"""

from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Optional, List, Dict, Any


class ContainerStatus(str, Enum):
    """Container lifecycle status."""
    PENDING = "pending"
    CREATING = "creating"
    RUNNING = "running"
    STOPPING = "stopping"
    STOPPED = "stopped"
    ARCHIVED = "archived"
    FAILED = "failed"
    TIMEOUT = "timeout"

    def is_active(self) -> bool:
        """Return True if container can accept commands."""
        return self in (ContainerStatus.RUNNING,)

    def is_terminal(self) -> bool:
        """Return True if container is in a final state."""
        return self in (
            ContainerStatus.STOPPED,
            ContainerStatus.ARCHIVED,
            ContainerStatus.FAILED,
        )


@dataclass
class ContainerInfo:
    """Container information returned from API."""
    container_id: str
    thread_id: str
    status: ContainerStatus
    shard_id: int
    worker_id: Optional[str] = None

    # Resource allocation
    cpu_limit: float = 1.0
    memory_limit: int = 4 * 1024 * 1024 * 1024  # 4GB
    storage_limit: int = 20 * 1024 * 1024 * 1024  # 20GB

    # Port mappings and preview URLs
    ports: Dict[int, int] = field(default_factory=dict)  # {container_port: host_port}
    urls: Dict[int, str] = field(default_factory=dict)  # {container_port: preview_url}

    # Timestamps
    created_at: Optional[datetime] = None
    started_at: Optional[datetime] = None
    last_activity_at: Optional[datetime] = None
    stopped_at: Optional[datetime] = None
    expires_at: Optional[datetime] = None

    # Metadata
    image: Optional[str] = None
    workspace_path: Optional[str] = None
    error_message: Optional[str] = None

    # Raw response for extension
    _raw: Dict[str, Any] = field(default_factory=dict, repr=False)

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "ContainerInfo":
        """Create ContainerInfo from API response dict."""
        # Parse status
        status_str = data.get("status", "pending")
        try:
            status = ContainerStatus(status_str.lower())
        except ValueError:
            status = ContainerStatus.PENDING

        # Parse timestamps
        def parse_ts(val):
            if not val:
                return None
            if isinstance(val, datetime):
                return val
            try:
                return datetime.fromisoformat(val.replace("Z", "+00:00"))
            except (ValueError, AttributeError):
                return None

        # Parse ports - API returns {int: int} or {"port": host_port}
        raw_ports = data.get("ports", {})
        ports = {int(k): int(v) for k, v in raw_ports.items()} if raw_ports else {}

        # Parse urls - API returns {int: str} or {"port": "url"}
        raw_urls = data.get("urls", {})
        urls = {int(k): v for k, v in raw_urls.items()} if raw_urls else {}

        return cls(
            container_id=data.get("container_id") or data.get("id", ""),
            thread_id=data.get("thread_id", ""),
            status=status,
            shard_id=data.get("shard_id", 0),
            worker_id=data.get("worker_id"),
            cpu_limit=data.get("cpu_limit", 1.0),
            memory_limit=data.get("memory_limit", 4 * 1024**3),
            storage_limit=data.get("storage_limit", 20 * 1024**3),
            ports=ports,
            urls=urls,
            created_at=parse_ts(data.get("created_at")),
            started_at=parse_ts(data.get("started_at")),
            last_activity_at=parse_ts(data.get("last_activity_at")),
            stopped_at=parse_ts(data.get("stopped_at")),
            expires_at=parse_ts(data.get("expires_at")),
            image=data.get("image"),
            workspace_path=data.get("workspace_path"),
            error_message=data.get("error_message"),
            _raw=data,
        )


@dataclass
class ExecResult:
    """Result of executing a command in a container."""
    exit_code: int
    stdout: str
    stderr: str

    # Timing
    duration_ms: Optional[float] = None
    timed_out: bool = False

    # Raw response
    _raw: Dict[str, Any] = field(default_factory=dict, repr=False)

    @property
    def success(self) -> bool:
        """Return True if command exited with code 0."""
        return self.exit_code == 0

    @property
    def output(self) -> str:
        """Return combined stdout + stderr."""
        parts = []
        if self.stdout:
            parts.append(self.stdout)
        if self.stderr:
            parts.append(self.stderr)
        return "\n".join(parts)

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "ExecResult":
        """Create ExecResult from API response dict."""
        return cls(
            exit_code=data.get("exit_code", -1),
            stdout=data.get("stdout", ""),
            stderr=data.get("stderr", ""),
            duration_ms=data.get("duration_ms"),
            timed_out=data.get("timed_out", False),
            _raw=data,
        )


@dataclass
class FileInfo:
    """File or directory information."""
    name: str
    path: str
    is_dir: bool
    size: int = 0
    mode: str = ""
    modified_at: Optional[datetime] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "FileInfo":
        """Create FileInfo from API response dict."""
        return cls(
            name=data.get("name", ""),
            path=data.get("path", ""),
            is_dir=data.get("is_dir", False),
            size=data.get("size", 0),
            mode=data.get("mode", ""),
            modified_at=datetime.fromisoformat(data["modified_at"].rstrip("Z")) if data.get("modified_at") else None,
        )


@dataclass
class ProcessInfo:
    """Background process information."""
    process_id: str
    command: str
    running: bool
    exit_code: Optional[int] = None
    stdout: str = ""
    stderr: str = ""
    started_at: Optional[str] = None

    _raw: Dict[str, Any] = field(default_factory=dict, repr=False)

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "ProcessInfo":
        """Create ProcessInfo from API response dict."""
        return cls(
            process_id=data.get("process_id", ""),
            command=data.get("command", ""),
            running=data.get("running", False),
            exit_code=data.get("exit_code"),
            stdout=data.get("stdout", ""),
            stderr=data.get("stderr", ""),
            started_at=data.get("started_at"),
            _raw=data,
        )


@dataclass
class ServiceInfo:
    """Service discovery information."""
    service: str
    version: str
    status: str
    api_version: str = "v1"
    endpoints: Dict[str, str] = field(default_factory=dict)
    features: List[str] = field(default_factory=list)

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "ServiceInfo":
        """Create ServiceInfo from API response dict."""
        return cls(
            service=data.get("service", "ybuild-runtime"),
            version=data.get("version", "unknown"),
            status=data.get("status", "unknown"),
            api_version=data.get("api_version", "v1"),
            endpoints=data.get("endpoints", {}),
            features=data.get("features", []),
        )
