"""Picture source data model with inheritance-based stream types."""

from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Dict, List, Optional, Type


@dataclass
class PictureSource:
    """Base class for picture source configurations.

    A picture source is either:
    - "raw": captures from a display using a capture engine template at a target FPS
    - "processed": applies postprocessing to another picture source
    - "static_image": returns a static frame from an uploaded asset
    - "video": decodes frames from an uploaded video asset
    """

    id: str
    name: str
    stream_type: str  # "raw", "processed", "static_image", or "video"
    created_at: datetime
    updated_at: datetime
    description: Optional[str] = None
    tags: List[str] = field(default_factory=list)

    def to_dict(self) -> dict:
        """Convert stream to dictionary. Subclasses extend this."""
        return {
            "id": self.id,
            "name": self.name,
            "stream_type": self.stream_type,
            "created_at": self.created_at.isoformat(),
            "updated_at": self.updated_at.isoformat(),
            "description": self.description,
            "tags": self.tags,
            # Subclass fields default to None for backward compat
            "display_index": None,
            "capture_template_id": None,
            "target_fps": None,
            "source_stream_id": None,
            "postprocessing_template_id": None,
            "image_asset_id": None,
            # Video fields
            "video_asset_id": None,
            "loop": None,
            "playback_speed": None,
            "start_time": None,
            "end_time": None,
            "resolution_limit": None,
            "clock_id": None,
        }

    @staticmethod
    def from_dict(data: dict) -> "PictureSource":
        """Factory: dispatch to the correct subclass based on stream_type."""
        stream_type = data.get("stream_type", "raw") or "raw"
        subcls = _PICTURE_SOURCE_MAP.get(stream_type, ScreenCapturePictureSource)
        return subcls.from_dict(data)


def _parse_common_fields(data: dict) -> dict:
    """Extract common fields shared by all picture source types."""
    raw_created = data.get("created_at")
    created_at = (
        datetime.fromisoformat(raw_created)
        if isinstance(raw_created, str)
        else raw_created if isinstance(raw_created, datetime)
        else datetime.now(timezone.utc)
    )
    raw_updated = data.get("updated_at")
    updated_at = (
        datetime.fromisoformat(raw_updated)
        if isinstance(raw_updated, str)
        else raw_updated if isinstance(raw_updated, datetime)
        else datetime.now(timezone.utc)
    )
    return dict(
        id=data["id"],
        name=data["name"],
        description=data.get("description"),
        tags=data.get("tags", []),
        created_at=created_at,
        updated_at=updated_at,
    )


@dataclass
class ScreenCapturePictureSource(PictureSource):
    """A raw capture stream from a display."""

    display_index: int = 0
    capture_template_id: str = ""
    target_fps: int = 30

    def to_dict(self) -> dict:
        d = super().to_dict()
        d["display_index"] = self.display_index
        d["capture_template_id"] = self.capture_template_id
        d["target_fps"] = self.target_fps
        return d

    @classmethod
    def from_dict(cls, data: dict) -> "ScreenCapturePictureSource":
        common = _parse_common_fields(data)
        return cls(
            **common,
            stream_type=data.get("stream_type", "raw") or "raw",
            display_index=data.get("display_index") or 0,
            capture_template_id=data.get("capture_template_id") or "",
            target_fps=data.get("target_fps") or 30,
        )


@dataclass
class ProcessedPictureSource(PictureSource):
    """A processed stream that applies postprocessing to another stream."""

    source_stream_id: str = ""
    postprocessing_template_id: str = ""

    def to_dict(self) -> dict:
        d = super().to_dict()
        d["source_stream_id"] = self.source_stream_id
        d["postprocessing_template_id"] = self.postprocessing_template_id
        return d

    @classmethod
    def from_dict(cls, data: dict) -> "ProcessedPictureSource":
        common = _parse_common_fields(data)
        return cls(
            **common,
            stream_type="processed",
            source_stream_id=data.get("source_stream_id") or "",
            postprocessing_template_id=data.get("postprocessing_template_id") or "",
        )


@dataclass
class StaticImagePictureSource(PictureSource):
    """A static image stream from an uploaded asset."""

    image_asset_id: Optional[str] = None

    def to_dict(self) -> dict:
        d = super().to_dict()
        d["image_asset_id"] = self.image_asset_id
        return d

    @classmethod
    def from_dict(cls, data: dict) -> "StaticImagePictureSource":
        common = _parse_common_fields(data)
        return cls(
            **common,
            stream_type="static_image",
            image_asset_id=data.get("image_asset_id") or data.get("image_source") or None,
        )


@dataclass
class VideoCaptureSource(PictureSource):
    """A video stream from an uploaded video asset."""

    video_asset_id: Optional[str] = None
    loop: bool = True
    playback_speed: float = 1.0
    start_time: Optional[float] = None
    end_time: Optional[float] = None
    resolution_limit: Optional[int] = None
    clock_id: Optional[str] = None
    target_fps: int = 30

    def to_dict(self) -> dict:
        d = super().to_dict()
        d["video_asset_id"] = self.video_asset_id
        d["loop"] = self.loop
        d["playback_speed"] = self.playback_speed
        d["start_time"] = self.start_time
        d["end_time"] = self.end_time
        d["resolution_limit"] = self.resolution_limit
        d["clock_id"] = self.clock_id
        d["target_fps"] = self.target_fps
        return d

    @classmethod
    def from_dict(cls, data: dict) -> "VideoCaptureSource":
        common = _parse_common_fields(data)
        return cls(
            **common,
            stream_type="video",
            video_asset_id=data.get("video_asset_id") or data.get("url") or None,
            loop=data.get("loop", True),
            playback_speed=data.get("playback_speed", 1.0),
            start_time=data.get("start_time"),
            end_time=data.get("end_time"),
            resolution_limit=data.get("resolution_limit"),
            clock_id=data.get("clock_id"),
            target_fps=data.get("target_fps") or 30,
        )


# -- Source type registry --
# Maps stream_type string to its subclass for factory dispatch.
_PICTURE_SOURCE_MAP: Dict[str, Type[PictureSource]] = {
    "raw": ScreenCapturePictureSource,
    "processed": ProcessedPictureSource,
    "static_image": StaticImagePictureSource,
    "video": VideoCaptureSource,
}
