"""Database records and domain status enums."""

from __future__ import annotations

import uuid
from dataclasses import dataclass, field
from datetime import UTC, datetime
from enum import StrEnum


def utc_now() -> str:
    return datetime.now(UTC).isoformat(timespec="seconds")


def new_id() -> str:
    return uuid.uuid4().hex


class JobStatus(StrEnum):
    PENDING = "PENDING"
    RUNNING = "RUNNING"
    PAUSED = "PAUSED"
    COMPLETED = "COMPLETED"
    FAILED = "FAILED"
    CANCELLED = "CANCELLED"


class VideoStatus(StrEnum):
    PENDING = "PENDING"
    DOWNLOADING = "DOWNLOADING"
    DOWNLOADED = "DOWNLOADED"
    UPLOADING = "UPLOADING"
    UPLOADED = "UPLOADED"
    FAILED = "FAILED"
    SKIPPED = "SKIPPED"
    CANCELLED = "CANCELLED"
    UPLOAD_UNKNOWN = "UPLOAD_UNKNOWN"


class PageStatus(StrEnum):
    PENDING = "PENDING"
    PROCESSING = "PROCESSING"
    PROCESSED = "PROCESSED"
    FAILED = "FAILED"
    SKIPPED = "SKIPPED"


ACTIVE_JOB_STATUSES = (JobStatus.PENDING, JobStatus.RUNNING, JobStatus.PAUSED)
TERMINAL_JOB_STATUSES = (JobStatus.COMPLETED, JobStatus.FAILED, JobStatus.CANCELLED)
TERMINAL_VIDEO_STATUSES = (
    VideoStatus.UPLOADED,
    VideoStatus.FAILED,
    VideoStatus.SKIPPED,
    VideoStatus.CANCELLED,
    VideoStatus.UPLOAD_UNKNOWN,
)


@dataclass(slots=True)
class Job:
    id: str
    source_url: str
    status: JobStatus
    owner_id: int
    owner_chat_id: int
    correlation_id: str
    created_at: str = field(default_factory=utc_now)
    started_at: str | None = None
    finished_at: str | None = None
    total_pages: int = 0
    processed_pages: int = 0
    total_videos: int = 0
    processed_videos: int = 0
    downloaded_videos: int = 0
    uploaded_videos: int = 0
    failed_videos: int = 0
    current_stage: str = "queued"
    error_message: str | None = None
    updated_at: str = field(default_factory=utc_now)

    @classmethod
    def create(cls, source_url: str, owner_id: int, owner_chat_id: int) -> Job:
        job_id = new_id()
        return cls(
            id=job_id,
            source_url=source_url,
            status=JobStatus.PENDING,
            owner_id=owner_id,
            owner_chat_id=owner_chat_id,
            correlation_id=job_id[:12],
        )

    @property
    def short_id(self) -> str:
        return self.id[:8]


@dataclass(slots=True)
class Video:
    id: str
    job_id: str
    source_url: str
    page_url: str
    title: str
    caption: str | None
    media_type: str
    status: VideoStatus
    created_at: str = field(default_factory=utc_now)
    updated_at: str = field(default_factory=utc_now)
    media_url: str | None = None
    thumbnail_url: str | None = None
    duration_seconds: float | None = None
    file_size: int | None = None
    local_path: str | None = None
    telegram_message_id: int | None = None
    uploaded_at: str | None = None
    error_message: str | None = None
    attempts: int = 0

    @classmethod
    def create(
        cls,
        *,
        job_id: str,
        source_url: str,
        page_url: str,
        title: str,
        caption: str | None,
        media_type: str,
        media_url: str | None = None,
        thumbnail_url: str | None = None,
        duration_seconds: float | None = None,
        file_size: int | None = None,
    ) -> Video:
        return cls(
            id=new_id(),
            job_id=job_id,
            source_url=source_url,
            page_url=page_url,
            title=title,
            caption=caption,
            media_type=media_type,
            media_url=media_url,
            thumbnail_url=thumbnail_url,
            duration_seconds=duration_seconds,
            file_size=file_size,
            status=VideoStatus.PENDING,
        )


@dataclass(slots=True)
class Page:
    id: str
    job_id: str
    page_url: str
    status: PageStatus
    discovered_at: str = field(default_factory=utc_now)
    processed_at: str | None = None
    http_status: int | None = None
    error_message: str | None = None

    @classmethod
    def create(cls, job_id: str, page_url: str) -> Page:
        return cls(id=new_id(), job_id=job_id, page_url=page_url, status=PageStatus.PENDING)
