from __future__ import annotations

from typing import Optional


class _BaseAsset:
    """Common base for all asset types."""

    source: str

    def __init__(self, source: str) -> None:
        if not source:
            raise ValueError("Asset source must not be empty")
        self.source = source

    def _is_url(self) -> bool:
        return self.source.startswith("http://") or self.source.startswith("https://")

    def __repr__(self) -> str:
        return f"{type(self).__name__}({self.source!r})"


class VideoAsset(_BaseAsset):
    """A video file asset.

    Args:
        source: Local file path or URL.
        start: Trim start point in the source file (seconds).  Default ``0``.
        volume: Audio volume multiplier.  ``1.0`` = original, ``0`` = silent.
    """

    start: float
    volume: float

    def __init__(
        self,
        source: str,
        *,
        start: float = 0.0,
        volume: float = 1.0,
    ) -> None:
        super().__init__(source)
        if start < 0:
            raise ValueError(f"start must be >= 0, got {start}")
        if volume < 0:
            raise ValueError(f"volume must be >= 0, got {volume}")
        self.start = start
        self.volume = volume


class AudioAsset(_BaseAsset):
    """An audio file asset.

    Args:
        source: Local file path or URL.
        start: Trim start point in the source file (seconds).
        volume: Audio volume multiplier.
    """

    start: float
    volume: float

    def __init__(
        self,
        source: str,
        *,
        start: float = 0.0,
        volume: float = 1.0,
    ) -> None:
        super().__init__(source)
        if start < 0:
            raise ValueError(f"start must be >= 0, got {start}")
        if volume < 0:
            raise ValueError(f"volume must be >= 0, got {volume}")
        self.start = start
        self.volume = volume


class ImageAsset(_BaseAsset):
    """A still image asset.

    Args:
        source: Local file path or URL.
    """


class TextAsset:
    """A text overlay asset with optional styling and animation.

    Args:
        text: The text string to display.
        font_size: Font size in pixels.
        color: Font color (FFmpeg color name or hex like ``"white"`` or ``"#ff0000"``).
        font_file: Path to a ``.ttf`` / ``.otf`` font file.  ``None`` uses FFmpeg default.
        box: Whether to draw a background box behind the text.
        box_color: Box fill colour with optional alpha, e.g. ``"black@0.5"``.
        box_border_w: Padding inside the box in pixels.
        border_width: Text stroke width.
        border_color: Text stroke colour.
        fade_in: Fade-in duration in seconds (``0`` = instant).
        fade_out: Fade-out duration in seconds (``0`` = instant).
    """

    def __init__(
        self,
        text: str,
        *,
        font_size: int = 48,
        color: str = "white",
        font_file: Optional[str] = None,
        box: bool = False,
        box_color: str = "black@0.5",
        box_border_w: int = 8,
        border_width: int = 0,
        border_color: str = "black",
        fade_in: float = 0.0,
        fade_out: float = 0.0,
    ) -> None:
        if not text:
            raise ValueError("TextAsset text must not be empty")
        self.text = text
        self.font_size = font_size
        self.color = color
        self.font_file = font_file
        self.box = box
        self.box_color = box_color
        self.box_border_w = box_border_w
        self.border_width = border_width
        self.border_color = border_color
        self.fade_in = fade_in
        self.fade_out = fade_out
        self.source = ""  # no file source

    def _is_url(self) -> bool:
        return False

    def __repr__(self) -> str:
        return f"TextAsset({self.text!r})"
