"""Metadata dataclasses for projects, scenes, and keyframe groups."""

from __future__ import annotations

__author__ = "Lene Preuss <lene.preuss@gmail.com>"

from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any


def _now_utc() -> datetime:
    return datetime.now(timezone.utc)


def _dt_to_str(dt: datetime) -> str:
    return dt.strftime("%Y-%m-%dT%H:%M:%SZ")


def _str_to_dt(s: str) -> datetime:
    return datetime.strptime(s, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc)


@dataclass
class ProviderDefaults:
    """Default provider names for a project."""

    image: str = "seedream"
    video: str = "seedance"

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

    @classmethod
    def from_dict(cls, data: dict[str, str]) -> ProviderDefaults:
        return cls(image=data.get("image", "seedream"), video=data.get("video", "seedance"))


@dataclass
class ProjectCost:
    """Aggregated cost breakdown for a project."""

    amount: float = 0.0
    currency: str = "USD"
    image_generation: float = 0.0
    video_generation: float = 0.0

    def to_dict(self) -> dict[str, Any]:
        return {
            "amount": self.amount,
            "currency": self.currency,
            "breakdown": {
                "image_generation": self.image_generation,
                "video_generation": self.video_generation,
            },
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> ProjectCost:
        breakdown = data.get("breakdown", {})
        return cls(
            amount=data.get("amount", 0.0),
            currency=data.get("currency", "USD"),
            image_generation=breakdown.get("image_generation", 0.0),
            video_generation=breakdown.get("video_generation", 0.0),
        )


@dataclass
class ProjectMetadata:
    """Top-level project metadata stored in project.json."""

    name: str
    created_at: datetime
    updated_at: datetime
    aspect_ratio: str = "16:9"
    description: str = ""
    default_provider: ProviderDefaults = field(default_factory=ProviderDefaults)
    total_cost: ProjectCost = field(default_factory=ProjectCost)
    scenes: list[str] = field(default_factory=list)

    def to_dict(self) -> dict[str, Any]:
        return {
            "name": self.name,
            "created_at": _dt_to_str(self.created_at),
            "updated_at": _dt_to_str(self.updated_at),
            "aspect_ratio": self.aspect_ratio,
            "description": self.description,
            "default_provider": self.default_provider.to_dict(),
            "total_cost": self.total_cost.to_dict(),
            "scenes": list(self.scenes),
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> ProjectMetadata:
        return cls(
            name=data["name"],
            created_at=_str_to_dt(data["created_at"]),
            updated_at=_str_to_dt(data["updated_at"]),
            aspect_ratio=data.get("aspect_ratio", "16:9"),
            description=data.get("description", ""),
            default_provider=ProviderDefaults.from_dict(data.get("default_provider", {})),
            total_cost=ProjectCost.from_dict(data.get("total_cost", {})),
            scenes=list(data.get("scenes", [])),
        )

    @classmethod
    def create_new(
        cls,
        name: str,
        aspect_ratio: str = "16:9",
        description: str = "",
    ) -> ProjectMetadata:
        now = _now_utc()
        return cls(
            name=name,
            created_at=now,
            updated_at=now,
            aspect_ratio=aspect_ratio,
            description=description,
        )


@dataclass
class ScenePrompts:
    """Default prompts stored on a scene."""

    keyframe: str = ""
    video: str = ""

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

    @classmethod
    def from_dict(cls, data: dict[str, str]) -> ScenePrompts:
        return cls(keyframe=data.get("keyframe", ""), video=data.get("video", ""))


@dataclass
class SceneCost:
    """Cost breakdown for a single scene."""

    amount: float = 0.0
    currency: str = "USD"
    image_generation: float = 0.0
    video_generation: float = 0.0

    def to_dict(self) -> dict[str, Any]:
        return {
            "amount": self.amount,
            "currency": self.currency,
            "image_generation": self.image_generation,
            "video_generation": self.video_generation,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> SceneCost:
        return cls(
            amount=data.get("amount", 0.0),
            currency=data.get("currency", "USD"),
            image_generation=data.get("image_generation", 0.0),
            video_generation=data.get("video_generation", 0.0),
        )


@dataclass
class SceneMetadata:  # pylint: disable=too-many-instance-attributes
    """Scene metadata stored in scene.json."""

    name: str
    index: int
    created_at: datetime
    updated_at: datetime
    aspect_ratio: str = "16:9"
    description: str = ""
    status: str = "empty"
    prompts: ScenePrompts = field(default_factory=ScenePrompts)
    source_images: list[str] = field(default_factory=list)
    keyframe_count: int = 0
    clip_count: int = 0
    total_duration_seconds: float = 0.0
    cost: SceneCost = field(default_factory=SceneCost)
    pending_tasks: list[str] = field(default_factory=list)
    keyframe_order: list[str] = field(default_factory=list)

    def to_dict(self) -> dict[str, Any]:
        return {
            "name": self.name,
            "index": self.index,
            "created_at": _dt_to_str(self.created_at),
            "updated_at": _dt_to_str(self.updated_at),
            "aspect_ratio": self.aspect_ratio,
            "description": self.description,
            "status": self.status,
            "prompts": self.prompts.to_dict(),
            "source_images": list(self.source_images),
            "keyframe_count": self.keyframe_count,
            "clip_count": self.clip_count,
            "total_duration_seconds": self.total_duration_seconds,
            "cost": self.cost.to_dict(),
            "pending_tasks": list(self.pending_tasks),
            "keyframe_order": list(self.keyframe_order),
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> SceneMetadata:
        return cls(
            name=data["name"],
            index=data["index"],
            created_at=_str_to_dt(data["created_at"]),
            updated_at=_str_to_dt(data["updated_at"]),
            aspect_ratio=data.get("aspect_ratio", "16:9"),
            description=data.get("description", ""),
            status=data.get("status", "empty"),
            prompts=ScenePrompts.from_dict(data.get("prompts", {})),
            source_images=list(data.get("source_images", [])),
            keyframe_count=data.get("keyframe_count", 0),
            clip_count=data.get("clip_count", 0),
            total_duration_seconds=data.get("total_duration_seconds", 0.0),
            cost=SceneCost.from_dict(data.get("cost", {})),
            pending_tasks=list(data.get("pending_tasks", [])),
            keyframe_order=list(data.get("keyframe_order", [])),
        )

    @classmethod
    def create_new(
        cls,
        name: str,
        index: int,
        aspect_ratio: str = "16:9",
        description: str = "",
    ) -> SceneMetadata:
        now = _now_utc()
        return cls(
            name=name,
            index=index,
            created_at=now,
            updated_at=now,
            aspect_ratio=aspect_ratio,
            description=description,
        )


@dataclass
class GroupCost:
    """Cost for a single keyframe generation group."""

    amount: float = 0.0
    currency: str = "USD"

    def to_dict(self) -> dict[str, Any]:
        return {"amount": self.amount, "currency": self.currency}

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> GroupCost:
        return cls(amount=data.get("amount", 0.0), currency=data.get("currency", "USD"))


@dataclass
class KeyframeGroupMetadata:
    """Keyframe group metadata stored in group.json."""

    name: str
    index: int
    created_at: datetime
    prompt: str
    source_images: list[str] = field(default_factory=list)
    provider: str = "seedream"
    model: str = "seedream-4-0-250828"
    params: dict[str, Any] = field(default_factory=dict)
    total_generated: int = 0
    selected_count: int = 0
    cost: GroupCost = field(default_factory=GroupCost)

    def to_dict(self) -> dict[str, Any]:
        return {
            "name": self.name,
            "index": self.index,
            "created_at": _dt_to_str(self.created_at),
            "prompt": self.prompt,
            "source_images": list(self.source_images),
            "provider": self.provider,
            "model": self.model,
            "params": dict(self.params),
            "total_generated": self.total_generated,
            "selected_count": self.selected_count,
            "cost": self.cost.to_dict(),
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> KeyframeGroupMetadata:
        return cls(
            name=data["name"],
            index=data["index"],
            created_at=_str_to_dt(data["created_at"]),
            prompt=data["prompt"],
            source_images=list(data.get("source_images", [])),
            provider=data.get("provider", "seedream"),
            model=data.get("model", "seedream-4-0-250828"),
            params=dict(data.get("params", {})),
            total_generated=data.get("total_generated", 0),
            selected_count=data.get("selected_count", 0),
            cost=GroupCost.from_dict(data.get("cost", {})),
        )


@dataclass
class KeyframeSidecar:
    """Per-keyframe sidecar stored as <filename>.meta.json."""

    created_at: datetime
    index: int = 1
    type: str = "keyframe"
    cost: GroupCost = field(default_factory=GroupCost)
    content_hash: str = ""
    aspect_ratio: str = "16:9"
    resolution: list[int] = field(default_factory=lambda: [1280, 720])
    selected: bool = True
    notes: str = ""

    def to_dict(self) -> dict[str, Any]:
        return {
            "type": self.type,
            "index": self.index,
            "created_at": _dt_to_str(self.created_at),
            "cost": self.cost.to_dict(),
            "content_hash": self.content_hash,
            "aspect_ratio": self.aspect_ratio,
            "resolution": list(self.resolution),
            "selected": self.selected,
            "notes": self.notes,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> KeyframeSidecar:
        return cls(
            created_at=_str_to_dt(data["created_at"]),
            index=data.get("index", 1),
            type=data.get("type", "keyframe"),
            cost=GroupCost.from_dict(data.get("cost", {})),
            content_hash=data.get("content_hash", ""),
            aspect_ratio=data.get("aspect_ratio", "16:9"),
            resolution=list(data.get("resolution", [1280, 720])),
            selected=data.get("selected", True),
            notes=data.get("notes", ""),
        )
