"""Source-backend value objects — framework-free.

A *source* is a place tracks come from (a mounted folder, YouTube, an upload).
Backends are driven adapters (``app.infrastructure.sources``); these are the
shapes they speak in, and the ports they satisfy live in ``app.domain.ports``.

The first backend, ``local``, is *indexable*: it enumerates files already on
disk. Concrete metadata (artist/album/tags) is intentionally **not** resolved
here — a source yields a file plus a minimal title; enrichment (plan §6.2) fills
the rest later, so this stays a thin discovery layer (CLAUDE.md: no duplicated
business logic)."""

from dataclasses import dataclass, field
from pathlib import Path
from typing import Any

# A source's ``kind`` describes which ports it satisfies, so the UI/admin can
# tell an indexed folder from a searchable fetch-source. A backend may be both.
KIND_INDEXABLE = "indexable"  # enumerates files already on disk (local folder)
KIND_FETCH = "fetch"  # searches + downloads from an external service (YTM, …)


@dataclass(frozen=True, slots=True)
class SourceInfo:
    """Describes a registered source for enumeration / health (UI, admin)."""

    name: str
    label: str
    kind: str  # KIND_INDEXABLE | KIND_FETCH
    available: bool


@dataclass(frozen=True, slots=True)
class SourceFile:
    """A single importable file discovered by an indexable source.

    ``source_id`` is stable per source (the local backend uses the path relative
    to its root) so re-scans are idempotent — already-imported files are skipped.
    """

    source_id: str
    path: Path
    suggested_title: str
    file_format: str
    file_size: int


@dataclass(frozen=True, slots=True)
class SearchResult:
    """One hit from a searchable source (plan §5), shown on the discover screen.

    ``source_id`` is the stable handle the same backend later resolves in
    ``fetch`` — it must round-trip a download request without re-searching.
    ``raw`` carries the backend's untouched payload for debugging / future use.
    """

    source: str
    source_id: str
    title: str
    artist: str | None
    album: str | None
    duration_seconds: int | None
    thumbnail_url: str | None
    raw: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True, slots=True)
class RawMetadata:
    """Metadata a fetch-source can offer about an item *before* enrichment.

    Best-effort and source-shaped — the canonical metadata still comes from the
    enrichment pipeline (plan §6.2). Used to seed a more useful provisional
    title than a bare id while a download is queued."""

    title: str | None
    artist: str | None
    album: str | None
    year: int | None
    extra: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True, slots=True)
class DownloadResult:
    """A file a fetch-source produced on local disk (plan §5).

    ``path`` is a temp file the caller owns: it is stored into managed storage
    and then removed (same lifecycle as an upload). ``source_id`` is echoed back
    because some backends only learn the canonical id during the download."""

    source_id: str
    path: Path
    file_format: str
    file_size: int
    bitrate: int | None
    suggested_title: str
