"""渲染结果内部下载接口单元测试。

测试 internal_render 路由的核心逻辑，mock 掉 repository 和 storage 依赖。
"""

from __future__ import annotations

from unittest.mock import MagicMock

import pytest
from app.api.routes.internal_render import (
    InternalRenderDownloadUrlResponse,
    InternalRenderTaskVideosResponse,
    _video_to_item,
    get_render_task_videos,
    get_render_video_download_url,
)

# ── Helpers ────────────────────────────────────────────────────────────────


class MockVideo:
    """模拟 GeneratedVideo 领域对象。"""

    def __init__(self, **kwargs):
        self.id = kwargs.get("id", "video-1")
        self.generation_task_id = kwargs.get("generation_task_id", "task-1")
        self.project_id = kwargs.get("project_id", "proj-1")
        self.name = kwargs.get("name", "test_video.mp4")
        self.file_url = kwargs.get("file_url", "videos/test/output.mp4")
        self.file_size = kwargs.get("file_size", 1024000)
        self.duration = kwargs.get("duration", 30.5)
        self.width = kwargs.get("width", 1080)
        self.height = kwargs.get("height", 1920)
        self.fps = kwargs.get("fps", 30.0)
        self.status = kwargs.get("status", "completed")


# ── _video_to_item 测试 ────────────────────────────────────────────────────


class TestVideoToItem:
    """测试视频对象转响应项。"""

    def test_basic_conversion(self):
        video = MockVideo(id="v1", generation_task_id="t1", status="completed")
        item = _video_to_item(video, "https://oss.example.com/download?v1")
        assert item.video_id == "v1"
        assert item.generation_task_id == "t1"
        assert item.status == "completed"
        assert item.download_url == "https://oss.example.com/download?v1"

    def test_missing_optional_fields(self):
        """缺可选字段时返回 None。"""
        video = MockVideo()
        # 去掉可选字段
        del video.file_size
        del video.duration
        item = _video_to_item(video, "https://example.com/dl")
        assert item.file_size is None
        assert item.duration is None
        assert item.width == 1080  # 还在


# ── 路由函数测试 ────────────────────────────────────────────────────────────


class TestGetRenderVideoDownloadUrl:
    """测试单个视频下载URL接口。"""

    def test_video_exists(self):
        video = MockVideo(id="v-abc", file_url="videos/abc/out.mp4")
        mock_repo = MagicMock()
        mock_repo.get.return_value = video
        mock_storage = MagicMock()
        mock_storage.get_download_url.return_value = "https://oss.test/signed?v=abc"

        result = get_render_video_download_url(
            video_id="v-abc",
            _=True,
            generated_video_repository=mock_repo,
            storage_service=mock_storage,
        )

        assert isinstance(result, InternalRenderDownloadUrlResponse)
        assert result.video_id == "v-abc"
        assert result.download_url == "https://oss.test/signed?v=abc"
        mock_repo.get.assert_called_once_with("v-abc")
        mock_storage.get_download_url.assert_called_once()

    def test_video_not_found_raises_404(self):
        from fastapi import HTTPException

        mock_repo = MagicMock()
        mock_repo.get.return_value = None
        mock_storage = MagicMock()

        with pytest.raises(HTTPException) as exc_info:
            get_render_video_download_url(
                video_id="nonexistent",
                _=True,
                generated_video_repository=mock_repo,
                storage_service=mock_storage,
            )
        assert exc_info.value.status_code == 404

    def test_download_url_long_expiry(self):
        """过期时间应为 24 小时（86400s）。"""
        video = MockVideo(id="v1")
        mock_repo = MagicMock()
        mock_repo.get.return_value = video
        mock_storage = MagicMock()
        mock_storage.get_download_url.return_value = "https://oss.test/signed"

        get_render_video_download_url(
            video_id="v1",
            _=True,
            generated_video_repository=mock_repo,
            storage_service=mock_storage,
        )

        # 验证 expires_seconds=86400
        call_kwargs = mock_storage.get_download_url.call_args
        assert call_kwargs.kwargs.get("expires_seconds") == 86400 or call_kwargs[1].get("expires_seconds") == 86400


class TestGetRenderTaskVideos:
    """测试任务视频列表接口。"""

    def test_list_multiple_videos(self):
        videos = [
            MockVideo(id="v1", status="completed"),
            MockVideo(id="v2", status="completed"),
            MockVideo(id="v3", status="failed"),
        ]
        mock_repo = MagicMock()
        mock_repo.list_by_generation_task.return_value = videos
        mock_storage = MagicMock()
        mock_storage.get_download_url.return_value = "https://oss.test/signed"

        result = get_render_task_videos(
            task_id="task-1",
            status=None,
            _=True,
            generated_video_repository=mock_repo,
            storage_service=mock_storage,
        )

        assert isinstance(result, InternalRenderTaskVideosResponse)
        assert result.task_id == "task-1"
        assert result.count == 3
        assert len(result.videos) == 3

    def test_filter_by_status(self):
        videos = [
            MockVideo(id="v1", status="completed"),
            MockVideo(id="v2", status="completed"),
            MockVideo(id="v3", status="failed"),
        ]
        mock_repo = MagicMock()
        mock_repo.list_by_generation_task.return_value = videos
        mock_storage = MagicMock()
        mock_storage.get_download_url.return_value = "https://oss.test/signed"

        result = get_render_task_videos(
            task_id="task-1",
            status="completed",
            _=True,
            generated_video_repository=mock_repo,
            storage_service=mock_storage,
        )

        assert result.count == 2
        assert all(v.status == "completed" for v in result.videos)

    def test_empty_task(self):
        mock_repo = MagicMock()
        mock_repo.list_by_generation_task.return_value = []
        mock_storage = MagicMock()

        result = get_render_task_videos(
            task_id="empty-task",
            status=None,
            _=True,
            generated_video_repository=mock_repo,
            storage_service=mock_storage,
        )

        assert result.count == 0
        assert result.videos == []
