"""Domain model for a downloaded web media file.

Backed by both PostgreSQL (primary) and Doris (warehouse).
Keyed by a UUID ``id`` column — every successful download creates a new unique row.
Insert-only — re-downloading the same URL creates a separate row.
"""

from __future__ import annotations

from datetime import datetime

from repo_core.base.models import DomainModel


class WebMedia(DomainModel):
    """Downloaded web media file stored in object storage (RustFS).

    Dual-backend: PostgreSQL and Doris (identical column sets).
    Insert-only — every download creates a new row.  Re-downloading
    the same ``source_url`` creates a separate row for audit trail.

    System-managed timestamps (``created_at``, ``updated_at``) use
    ``datetime`` following repo_core convention.

    Usage::

        media = WebMedia.from_db({
            "id": "550e8400-...",
            "source_url": "https://example.com/photo.jpg",
            "seed_id": "seed-uuid",
            "storage_key": "example.com/images/2024/photo.jpg",
            "storage_bucket": "web",
            "content_hash": "abc123...",
            "content_length": 102400,
            "media_type": "image",
        })
        row = media.to_db()
    """

    # -- Identity -------------------------------------------------------
    id: str
    source_url: str
    parent_url: str
    seed_id: str

    # -- Classification -------------------------------------------------
    media_type: str  # "image", "video", "document", "attachment"

    # -- Storage --------------------------------------------------------
    storage_bucket: str
    storage_key: str

    # -- Content metadata -----------------------------------------------
    content_hash: str
    version: int = 1  # Monotonically increasing per source_url
    etag: str | None = None  # HTTP ETag from source server response
    content_disposition: str | None = None  # Raw Content-Disposition header from source server
    content_type: str | None = None
    content_length: int
    original_filename: str | None = None

    # -- Extra context --------------------------------------------------
    metadata: dict | None = None  # noqa: A003 — shadows Python builtin, intentional domain field

    # -- Request metadata -----------------------------------------------
    final_url: str | None = None  # URL after redirects
    request_method: str = "GET"  # HTTP method used
    redirect_chain: list | None = None  # Intermediate URLs during redirects
    retry_count: int = 0  # Number of retry attempts before success
    latency_ms: int | None = None  # HTTP request duration in milliseconds
    status_code: int | None = None  # HTTP response status code
    response_headers: dict | None = None  # Full HTTP response headers

    # -- Content hash & versioning --------------------------------------
    version: int = 1  # Monotonically increasing per source_url

    # -- Timestamps -----------------------------------------------------
    created_at: datetime | None = None
    updated_at: datetime | None = None

    # -- Backend field filtering ----------------------------------------
    _db_include: set[str] | None = {
        "id",
        "source_url",
        "parent_url",
        "seed_id",
        "media_type",
        "storage_bucket",
        "storage_key",
        "content_hash",
        "version",
        "etag",
        "content_disposition",
        "content_type",
        "content_length",
        "original_filename",
        "metadata",
        "final_url",
        "request_method",
        "redirect_chain",
        "retry_count",
        "latency_ms",
        "status_code",
        "response_headers",
        "version",
        "created_at",
        "updated_at",
    }

    _warehouse_include: set[str] | None = {
        "id",
        "source_url",
        "parent_url",
        "seed_id",
        "media_type",
        "storage_bucket",
        "storage_key",
        "content_hash",
        "version",
        "etag",
        "content_disposition",
        "content_type",
        "content_length",
        "original_filename",
        "metadata",
        "final_url",
        "request_method",
        "redirect_chain",
        "retry_count",
        "latency_ms",
        "status_code",
        "response_headers",
        "version",
        "created_at",
        "updated_at",
    }

    _search_include: set[str] | None = set()  # no search backend
    _timestamps = {"created_at", "updated_at"}
