from __future__ import annotations

from dataclasses import replace

import pytest

from app.database.models import MediaStatus
from app.errors import MediaError, ValidationError
from app.gateways.base import ChatInfo
from tests.helpers import ingest


@pytest.mark.asyncio
async def test_register_source_and_ingest_video(ctx, gateway, incoming):
    gateway.chats[incoming.chat_id] = ChatInfo(
        chat_id=incoming.chat_id, title="Source Group", username=None, chat_type="supergroup"
    )
    source, created = await ctx.media.register_source(
        incoming.chat_id, added_by=111_000_001, title=None
    )
    assert created is True
    assert source.title == "Source Group"

    result = await ctx.media.ingest(incoming)
    assert result.status == "created"
    assert result.media is not None
    assert result.media.status == MediaStatus.READY
    assert result.media.file_name == "clip.mp4"
    assert await ctx.repos.media.count() == 1


@pytest.mark.asyncio
async def test_ingest_deduplicates_by_message_and_file(ctx, incoming):
    first = await ingest(ctx, incoming)
    assert first.status == "created"

    same_message = replace(incoming, file_id="other-file", file_unique_id="other-unique")
    result = await ctx.media.ingest(same_message)
    assert result.status == "duplicate_message"

    same_file = replace(incoming, message_id=11)
    result = await ctx.media.ingest(same_file)
    assert result.status == "duplicate_file"
    assert await ctx.repos.media.count() == 1


@pytest.mark.asyncio
async def test_ingest_ignores_unregistered_inactive_and_auto_disabled_sources(ctx, incoming):
    result = await ctx.media.ingest(incoming)
    assert result.status == "ignored"

    await ingest(ctx, incoming)
    source = await ctx.repos.media.get_source(incoming.chat_id)
    assert source is not None
    await ctx.repos.media.update_source_by_id(source.id, auto_ingest=False)
    result = await ctx.media.ingest(replace(incoming, message_id=20, file_unique_id="u20"))
    assert result.status == "ignored"

    await ctx.repos.media.update_source_by_id(source.id, auto_ingest=True, is_active=False)
    result = await ctx.media.ingest(replace(incoming, message_id=21, file_unique_id="u21"))
    assert result.status == "ignored"


@pytest.mark.asyncio
async def test_ingest_rejects_non_video_document(ctx, incoming):
    document = replace(
        incoming,
        message_id=30,
        file_unique_id="doc-1",
        media_type="document",
        mime_type="text/plain",
        file_name="notes.txt",
    )
    with pytest.raises(MediaError):
        await ingest(ctx, document)
    assert await ctx.repos.media.count() == 0


@pytest.mark.asyncio
async def test_ingest_marks_oversized_media_invalid(ctx, incoming):
    ctx.settings.max_media_size_mb = 1
    too_large = replace(
        incoming,
        message_id=31,
        file_unique_id="large-1",
        file_size=2 * 1024 * 1024,
    )
    result = await ingest(ctx, too_large)
    assert result.status == "invalid"
    assert result.media is not None
    assert result.media.status == MediaStatus.INVALID
    assert result.media.error_message


@pytest.mark.asyncio
async def test_register_source_rejects_private_chat(ctx, gateway):
    gateway.chats[42] = ChatInfo(chat_id=42, title="Private", username=None, chat_type="private")
    with pytest.raises(ValidationError):
        await ctx.media.register_source(42, added_by=111_000_001)
