"""Source chat registration and media ingestion."""

from __future__ import annotations

import logging
from dataclasses import dataclass

from sqlalchemy.exc import IntegrityError

from app.config import Settings
from app.database.models import MediaAsset, MediaStatus
from app.database.repositories import Repositories
from app.errors import MediaError, ValidationError
from app.gateways.base import TelegramGateway

logger = logging.getLogger(__name__)

_ALLOWED_VIDEO_EXTENSIONS = {".mp4", ".mkv", ".mov", ".webm", ".m4v", ".avi"}


@dataclass(frozen=True, slots=True)
class IncomingMedia:
    chat_id: int
    message_id: int
    chat_type: str
    chat_title: str | None
    file_id: str
    file_unique_id: str
    media_type: str
    mime_type: str | None
    file_name: str | None
    file_size: int | None
    duration_seconds: float | None
    width: int | None
    height: int | None
    thumbnail_file_id: str | None
    caption: str | None


@dataclass(frozen=True, slots=True)
class IngestResult:
    status: str
    media: MediaAsset | None
    reason: str = ""


class MediaService:
    def __init__(self, repos: Repositories, settings: Settings, gateway: TelegramGateway) -> None:
        self.repos = repos
        self.settings = settings
        self.gateway = gateway

    async def register_source(
        self,
        chat_id: int,
        *,
        added_by: int,
        title: str | None = None,
    ) -> tuple[object, bool]:
        try:
            chat = await self.gateway.get_chat(chat_id)
        except Exception as exc:
            logger.warning("could not read source chat %s: %s", chat_id, type(exc).__name__)
            raise MediaError(
                "خواندن اطلاعات گروه ممکن نشد. ربات باید عضو گروه باشد و شناسه درست باشد."
            ) from exc
        if chat.chat_type not in {"group", "supergroup", "channel"}:
            raise ValidationError("فقط گروه، سوپرگروه یا کانال می‌تواند منبع باشد.")
        source, created = await self.repos.media.add_source(
            chat_id,
            title=title or chat.title,
            chat_type=chat.chat_type,
            added_by=added_by,
        )
        await self.repos.audit.log(
            added_by,
            "source_chat.register",
            entity_type="source_chat",
            entity_id=chat_id,
            details={"created": created},
        )
        return source, created

    async def ingest(self, incoming: IncomingMedia) -> IngestResult:
        if not await self.repos.settings.get_bool("auto_ingest_enabled", True):
            return IngestResult("ignored", None, "دریافت خودکار در تنظیمات عمومی خاموش است.")
        source = await self.repos.media.get_source(incoming.chat_id)
        if source is None:
            return IngestResult("ignored", None, "گروه منبع ثبت نشده است.")
        if not source.is_active:
            return IngestResult("ignored", None, "گروه منبع غیرفعال است.")
        if not source.auto_ingest:
            return IngestResult("ignored", None, "دریافت خودکار برای این گروه خاموش است.")

        duplicate = await self.repos.media.find_by_message(source.id, incoming.message_id)
        if duplicate is not None:
            return IngestResult("duplicate_message", duplicate, "این پیام قبلاً ثبت شده است.")
        duplicate = await self.repos.media.find_by_unique_id(incoming.file_unique_id)
        if duplicate is not None:
            return IngestResult("duplicate_file", duplicate, "این فایل قبلاً از جای دیگری ثبت شده است.")

        if not incoming.file_id or not incoming.file_unique_id:
            raise MediaError("فایل ویدیویی شناسه معتبر ندارد.")

        is_video_mime = bool(incoming.mime_type and incoming.mime_type.startswith("video/"))
        suffix = ""
        if incoming.file_name and "." in incoming.file_name:
            suffix = "." + incoming.file_name.rsplit(".", 1)[-1].lower()
        if incoming.media_type == "document" and not is_video_mime:
            if suffix not in _ALLOWED_VIDEO_EXTENSIONS:
                raise MediaError("نوع فایل پشتیبانی نمی‌شود؛ فقط ویدیو یا document ویدیویی مجاز است.")

        too_large = bool(
            incoming.file_size and incoming.file_size > self.settings.max_media_size_bytes
        )
        status = MediaStatus.INVALID if too_large else MediaStatus.READY
        error = "حجم فایل از حد مجاز بیشتر است." if too_large else None
        try:
            media = await self.repos.media.add(
                source_chat_id=source.id,
                source_message_id=incoming.message_id,
                file_id=incoming.file_id,
                file_unique_id=incoming.file_unique_id,
                media_type=incoming.media_type,
                mime_type=incoming.mime_type,
                file_name=incoming.file_name,
                file_size=incoming.file_size,
                duration_seconds=incoming.duration_seconds,
                width=incoming.width,
                height=incoming.height,
                thumbnail_file_id=incoming.thumbnail_file_id,
                original_caption=incoming.caption,
                status=status,
                error_message=error,
            )
        except IntegrityError:
            existing = await self.repos.media.find_by_unique_id(incoming.file_unique_id)
            if existing is None:
                existing = await self.repos.media.find_by_message(
                    source.id, incoming.message_id
                )
            return IngestResult("duplicate_file", existing, "فایل تکراری است.")
        await self.repos.media.touch_source(source.id)
        if too_large:
            return IngestResult("invalid", media, error or "فایل نامعتبر است.")
        logger.info("media %s ingested from source chat %s", media.id, incoming.chat_id)
        return IngestResult("created", media)
