"""Backend types for Contree MCP DO NOT EDIT THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING"""

from base64 import b64decode, b64encode
from enum import Enum
from typing import Any, Literal, TypeVar
from uuid import UUID

from pydantic import BaseModel, ByteSize, Field, PositiveInt, model_validator
from typing_extensions import Self

PublicUUID = str(UUID(int=0))

E = TypeVar("E", bound=Enum)


class ImageCredentials(BaseModel):
    username: str = ""
    password: str = ""


class ImageRegistry(BaseModel):
    url: str
    credentials: ImageCredentials = ImageCredentials()


class ImportImageMetadata(BaseModel):
    registry: ImageRegistry
    tag: str | None = None
    timeout: PositiveInt = 300


class ImageSize(BaseModel):
    physical: int = -1
    logical: int = -1


class Image(BaseModel):
    """Response model for image endpoints.

    API handlers:
    - GET /inspect/{image_uuid}/ -> Image
    - GET /inspect/?tag={tag} -> Image (redirect)
    - PATCH /images/{image_uuid}/tag -> Image
    - DELETE /images/{image_uuid}/tag -> Image
    """

    uuid: str = Field(description="Image UUID")
    tag: str | None = Field(default=None, description="Image tag or null")
    created_at: str = Field(default="", description="ISO 8601 creation timestamp")


class ImageListResponse(BaseModel):
    """Response from GET /images.

    API handlers:
    - GET /images -> ImageListResponse
    """

    images: list[Image] = Field(default_factory=list)


class FileItem(BaseModel):
    """File info in directory listing."""

    path: str = Field(description="File name relative to directory")
    size: int = Field(description="File size in bytes")
    owner: int | str = Field(description="User ID or name of owner")
    group: int | str = Field(description="Group ID or name")
    mode: int = Field(description="File permissions as integer")
    mtime: int = Field(description="Last modification Unix timestamp")
    is_dir: bool = Field(description="Directory indicator")
    is_regular: bool = Field(description="Regular file indicator")
    is_symlink: bool = Field(description="Symbolic link indicator")
    is_socket: bool = Field(description="Socket indicator")
    is_fifo: bool = Field(description="FIFO/named pipe indicator")
    symlink_to: str = Field(default="", description="Target path for symlinks")


class DirectoryList(BaseModel):
    """Response from GET /inspect/{uuid}/list.

    API handlers:
    - GET /inspect/{image_uuid}/list -> DirectoryList
    """

    path: str = Field(description="Directory path listed")
    files: list[FileItem] = Field(default_factory=list)


class FileResponse(BaseModel):
    """Response from file endpoints.

    API handlers:
    - POST /files -> FileResponse
    - GET /files?sha256={hash} -> FileResponse
    """

    uuid: str = Field(description="File UUID")
    sha256: str = Field(description="SHA256 hash of file content")


class InstanceSpawnResponse(BaseModel):
    """Response from POST /instances.

    API handlers:
    - POST /instances -> InstanceSpawnResponse
    - POST /images/import -> InstanceSpawnResponse (same format)
    """

    uuid: str = Field(description="Operation UUID")


class Stream(BaseModel):
    value: str
    encoding: Literal["ascii", "base64"] = "ascii"
    truncated: bool = False

    def text(self) -> str:
        if self.encoding == "ascii":
            return self.value
        elif self.encoding == "base64":
            return b64decode(self.value).decode("utf-8", errors="replace")
        raise ValueError(f"Unsupported encoding: {self.encoding}")

    @classmethod
    def from_bytes(cls, data: bytes, max_size: int = -1) -> Self:
        encoding: Literal["ascii", "base64"]
        truncated = False
        if 0 < max_size < len(data):
            data = data[:max_size]
            truncated = True
        try:
            encoding = "ascii"
            value = data.decode("ascii")
        except UnicodeDecodeError:
            encoding = "base64"
            value = b64encode(data).decode("ascii")
        return cls(value=value, encoding=encoding, truncated=truncated)

    def to_bytes(self) -> bytes:
        match self.encoding:
            case "ascii":
                return self.value.encode("ascii")
            case "base64":
                return b64decode(self.value)
            case _:
                raise ValueError(f"Unsupported encoding: {self.encoding}")

    def __bool__(self) -> bool:
        return bool(self.value)


class ConsumedResources(BaseModel):
    block_input: int = -1
    block_output: int = -1
    cost: float = -1.0
    elapsed_time: float = -1
    involuntary_switches: int = -1
    max_rss: int = -1
    monotonic_time: float = -1
    page_faults: int = -1
    page_faults_io: int = -1
    shared_memory: int = -1
    signals: int = -1
    swaps: int = -1
    system_cpu_time: float = -1.0
    unshared_memory: int = -1
    user_cpu_time: float = -1.0
    voluntary_switches: int = -1


class ProcessExitState(BaseModel):
    continued: bool = False
    core_dump: bool = False
    exit_code: int = 0
    pid: int = 0
    signal: int = -1
    stopped: bool = False
    timed_out: bool = False


class InstanceResult(BaseModel):
    resources: ConsumedResources = ConsumedResources()
    state: ProcessExitState = ProcessExitState()
    stdout: Stream
    stderr: Stream


class InstanceFileSpec(BaseModel):
    uuid: str
    mode: str = "0644"
    uid: int = 0
    gid: int = 0


class InstanceMetadata(BaseModel):
    """Metadata for instance execution operations"""

    command: str = Field(description="Command to run")
    image: str = Field(description="Image UUID or string starts with 'tag:'")
    hostname: str = "linuxkit"
    args: list[str] = Field(default_factory=list, description="Command arguments, must be used with shell is false")
    shell: bool = Field(default=False, description="In this mode command is a shell expression and args must be empty")
    env: dict[str, str] = Field(default_factory=dict)
    cwd: str = Field(default="/root", description="Path to the working directory, must be absolute")
    disposable: bool = False
    stdin: Stream = Stream(value="")
    timeout: PositiveInt = 60
    truncate_output_at: ByteSize = ByteSize(64 * 1024)
    files: dict[str, InstanceFileSpec] = Field(default_factory=dict, description="Files to add to the image")
    result: InstanceResult | None = None


class OperationStatus(str, Enum):
    PENDING = "PENDING"
    EXECUTING = "EXECUTING"
    SUCCESS = "SUCCESS"
    FAILED = "FAILED"
    CANCELLED = "CANCELLED"
    ASSIGNED = "ASSIGNED"

    def __str__(self) -> str:
        return self.value

    def is_terminal(self) -> bool:
        cls = self.__class__
        return self in {cls.SUCCESS, cls.FAILED, cls.CANCELLED}


class OperationKind(str, Enum):
    INSTANCE = "instance"
    IMAGE_IMPORT = "image_import"

    def __str__(self) -> str:
        return self.value


class OperationResult(BaseModel):
    image: str | None = Field(default=None, description="Result image UUID or null")
    tag: str | None = Field(default=None, description="Assigned tag or null")


class OperationSummary(BaseModel):
    """Summary model for operations in list.

    API handlers:
    - GET /operations -> OperationListResponse.operations (list of OperationSummary)
    """

    uuid: str = Field(description="Operation UUID")
    kind: OperationKind = Field(description="Operation kind")
    status: OperationStatus = Field(description="Operation status")
    error: str | None = Field(default=None, description="Error message if failed")
    created_at: str = Field(default="", description="ISO 8601 creation timestamp")


class OperationListResponse(BaseModel):
    """Response from GET /operations.

    API handlers:
    - GET /operations -> OperationListResponse
    """

    operations: list[OperationSummary] = Field(default_factory=list)

    @model_validator(mode="before")
    @classmethod
    def wrap_list(cls, data: Any) -> Any:
        """Handle backend returning list instead of dict with operations key."""
        if isinstance(data, list):
            return {"operations": data}
        return data


class OperationResponse(BaseModel):
    """Response model for operation detail endpoint.

    API handlers:
    - GET /operations/{operation_id} -> OperationResponse
    """

    uuid: str = Field(default="", description="Operation UUID")
    status: OperationStatus = Field(description="Operation status")
    kind: OperationKind = Field(description="Operation kind")
    error: str | None = Field(default=None, description="Error message if any")
    metadata: InstanceMetadata | ImportImageMetadata | None = Field(default=None, description="Operation metadata")
    result: OperationResult | None = Field(default=None, description="Operation result")
    duration: float = Field(default=0.0, description="Operation duration")

    @model_validator(mode="before")
    @classmethod
    def parse_metadata(cls, data: Any) -> Any:
        if isinstance(data, dict) and "kind" in data:
            data = dict(data)  # Create mutable copy
            data["kind"] = data["kind"].lower()
        return data


class CancelOperationResponse(BaseModel):
    """Response from cancel operation endpoint.

    API handlers:
    - DELETE /operations/{operation_id} -> CancelOperationResponse
    """

    uuid: str = Field(default="", description="Operation UUID")
    status: OperationStatus = Field(default=OperationStatus.CANCELLED)
