"""Artifact request/result models shared across screenshot backends."""

from __future__ import annotations

from dataclasses import dataclass
from enum import Enum
from pathlib import Path


class MotionSnapshotFormat(Enum):
    GIF = "gif"


@dataclass(frozen=True, kw_only=True, slots=True)
class HtmlSnapshotRequest:
    path: Path

    def __post_init__(self) -> None:
        if not isinstance(self.path, Path):
            raise TypeError("html snapshot path must be a pathlib.Path")

    def to_dict(self) -> dict[str, object]:
        return {"path": str(self.path)}


@dataclass(frozen=True, kw_only=True, slots=True)
class MotionSnapshotRequest:
    path: Path
    format: MotionSnapshotFormat = MotionSnapshotFormat.GIF
    duration_s: float = 3.0
    fps: int = 5
    preserve_motion: bool = True
    required: bool = False

    def __post_init__(self) -> None:
        if not isinstance(self.path, Path):
            raise TypeError("motion snapshot path must be a pathlib.Path")
        if not isinstance(self.format, MotionSnapshotFormat):
            raise TypeError("motion snapshot format must be a MotionSnapshotFormat")
        if self.duration_s <= 0:
            raise ValueError(f"motion snapshot duration_s must be > 0, got {self.duration_s}")
        if self.fps < 1:
            raise ValueError(f"motion snapshot fps must be >= 1, got {self.fps}")
        suffix = self.path.suffix.lower()
        if suffix and suffix != f".{self.format.value}":
            raise ValueError(
                "motion snapshot path suffix must match format "
                f"{self.format.value!r}, got {self.path.name!r}"
            )

    def to_dict(self) -> dict[str, object]:
        return {
            "path": str(self.path),
            "format": self.format.value,
            "duration_s": self.duration_s,
            "fps": self.fps,
            "preserve_motion": self.preserve_motion,
            "required": self.required,
        }


@dataclass(frozen=True, kw_only=True, slots=True)
class ScreenshotArtifactsRequest:
    html_snapshot: HtmlSnapshotRequest | None = None
    motion_snapshot: MotionSnapshotRequest | None = None

    def to_dict(self) -> dict[str, object]:
        return {
            "html_snapshot": self.html_snapshot.to_dict() if self.html_snapshot else None,
            "motion_snapshot": self.motion_snapshot.to_dict() if self.motion_snapshot else None,
        }


@dataclass(frozen=True, kw_only=True, slots=True)
class MotionSnapshotResult:
    path: Path | None = None
    format: MotionSnapshotFormat | None = None
    duration_s: float | None = None
    fps: int | None = None
    written: bool = False
    truncated: bool = False

    def __post_init__(self) -> None:
        if self.written and self.path is None:
            raise ValueError("written motion snapshots must include a path")
        if self.path is not None and not isinstance(self.path, Path):
            raise TypeError("motion snapshot result path must be a pathlib.Path")
        if self.format is not None and not isinstance(self.format, MotionSnapshotFormat):
            raise TypeError("motion snapshot result format must be a MotionSnapshotFormat")

    def to_dict(self) -> dict[str, object]:
        return {
            "path": str(self.path) if self.path else None,
            "format": self.format.value if self.format else None,
            "duration_s": self.duration_s,
            "fps": self.fps,
            "written": self.written,
            "truncated": self.truncated,
        }


@dataclass(frozen=True, kw_only=True, slots=True)
class ScreenshotArtifactsResult:
    html_snapshot_path: Path | None = None
    motion_snapshot: MotionSnapshotResult | None = None

    def __post_init__(self) -> None:
        if self.html_snapshot_path is not None and not isinstance(self.html_snapshot_path, Path):
            raise TypeError("html snapshot result path must be a pathlib.Path")

    def to_dict(self) -> dict[str, object]:
        return {
            "html_snapshot_path": str(self.html_snapshot_path) if self.html_snapshot_path else None,
            "motion_snapshot": self.motion_snapshot.to_dict() if self.motion_snapshot else None,
        }
