import asyncio
from unittest.mock import AsyncMock, MagicMock, patch

import pytest
from fastapi import HTTPException

from app import schemas
from app.api.endpoints.plugin import plugin_rating, plugin_ratings, rate_plugin
from app.adapters.external.server import MoviePilotServerHelper


def test_server_helper_uses_plugin_rating_endpoints() -> None:
    """评分辅助方法应使用独立中心端路径并传递评分载荷。"""

    async def run_scenario() -> None:
        with (
            patch("app.adapters.external.server.settings.MP_SERVER_HOST", "https://movie-pilot.org"),
            patch.object(
                MoviePilotServerHelper,
                "_async_get",
                new=AsyncMock(),
            ) as get_request,
            patch.object(
                MoviePilotServerHelper,
                "_async_post_json",
                new=AsyncMock(),
            ) as post_request,
        ):
            await MoviePilotServerHelper.async_plugin_ratings(["DemoPlugin", "OtherPlugin"])
            await MoviePilotServerHelper.async_plugin_rating("Demo Plugin")
            await MoviePilotServerHelper.async_rate_plugin("Demo Plugin", 4.5)

        assert get_request.await_args_list[0].args == (
            "https://movie-pilot.org/plugin/rating",
        )
        assert get_request.await_args_list[0].kwargs == {
            "params": {"plugin_ids": "DemoPlugin,OtherPlugin"},
            "timeout": 10,
        }
        assert get_request.await_args_list[1].args == (
            "https://movie-pilot.org/plugin/rating/Demo%20Plugin",
        )
        assert post_request.await_args.args == (
            "https://movie-pilot.org/plugin/rating/Demo%20Plugin",
            {"rating": 4.5},
        )

    asyncio.run(run_scenario())


def test_plugin_rating_endpoints_return_center_results() -> None:
    """评分查询和提交接口应返回中心端结果并校验安装状态。"""

    async def run_scenario() -> None:
        rating_result = {
            "plugin_id": "DemoPlugin",
            "average_rating": 4.3,
            "rating_count": 12,
            "user_rating": 4.5,
        }
        with patch.object(
            MoviePilotServerHelper,
            "async_get_plugin_ratings",
            new=AsyncMock(return_value={"DemoPlugin": rating_result}),
        ) as batch_query:
            batch = await plugin_ratings("DemoPlugin", None)

        assert batch["DemoPlugin"].average_rating == 4.3
        batch_query.assert_awaited_once_with(["DemoPlugin"])

        with patch.object(
            MoviePilotServerHelper,
            "async_get_plugin_rating",
            new=AsyncMock(return_value=rating_result),
        ):
            single = await plugin_rating("DemoPlugin", None)

        assert single.user_rating == 4.5

        system_config = MagicMock()
        system_config.get.return_value = ["DemoPlugin"]
        with (
            patch("app.api.endpoints.plugin.get_configured_system_config", return_value=system_config),
            patch.object(
                MoviePilotServerHelper,
                "async_submit_plugin_rating",
                new=AsyncMock(return_value=rating_result),
            ) as submit_rating,
        ):
            response = await rate_plugin(
                "DemoPlugin",
                schemas.PluginRatingRequest(rating=4.5),
                None,
            )

        assert response.success is True
        assert response.data == rating_result
        submit_rating.assert_awaited_once_with("DemoPlugin", 4.5)

    asyncio.run(run_scenario())


def test_plugin_rating_rejects_uninstalled_plugin() -> None:
    """未安装插件不能借助 MoviePilot 接口向中心端提交评分。"""

    async def run_scenario() -> None:
        system_config = MagicMock()
        system_config.get.return_value = []
        with (
            patch("app.api.endpoints.plugin.get_configured_system_config", return_value=system_config),
            patch.object(
                MoviePilotServerHelper,
                "async_submit_plugin_rating",
                new=AsyncMock(),
            ) as submit_rating,
        ):
            with pytest.raises(HTTPException) as error:
                await rate_plugin(
                    "DemoPlugin",
                    schemas.PluginRatingRequest(rating=4.5),
                    None,
                )

        assert error.value.status_code == 400
        submit_rating.assert_not_awaited()

    asyncio.run(run_scenario())
