import unittest
from types import SimpleNamespace
from unittest.mock import AsyncMock, patch

import httpx
from fastapi import FastAPI

from app.router import profile as profile_router


def make_profile(**overrides):
    data = {
        "device_id": "device-1",
        "client_id": "client-1",
        "name": "Vivi",
        "character_key": "mochi",
        "user_call_name": None,
        "voice_id": None,
        "tts_provider": None,
        "tts_model_id": None,
        "personality": None,
    }
    data.update(overrides)
    return SimpleNamespace(**data)


class ProfileRouterTests(unittest.IsolatedAsyncioTestCase):
    async def test_get_profile_returns_effective_default_name(self):
        app = FastAPI()
        app.include_router(profile_router.router)
        profile = make_profile(name="Vivi", character_key="mochi")

        with patch(
            "app.router.profile.resolve_agent_profile",
            new=AsyncMock(return_value=(profile, None)),
        ):
            async with httpx.AsyncClient(
                transport=httpx.ASGITransport(app=app),
                base_url="http://testserver",
            ) as client:
                response = await client.get(
                    "/xiaozhi/v1/profile",
                    params={"device_id": "device-1", "client_id": "client-1"},
                )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(
            response.json(),
            {
                "device_id": "device-1",
                "client_id": "client-1",
                "character_key": "mochi",
                "name": "Mochi",
                "user_call_name": None,
            },
        )

    async def test_patch_profile_updates_character_and_names(self):
        app = FastAPI()
        app.include_router(profile_router.router)
        profile = make_profile(name="Mochi", character_key="mochi")

        with patch(
            "app.router.profile.resolve_agent_profile",
            new=AsyncMock(return_value=(profile, None)),
        ), patch(
            "app.router.profile.agent_profile_repo.update_profile",
            new=AsyncMock(),
        ) as update_profile:
            async with httpx.AsyncClient(
                transport=httpx.ASGITransport(app=app),
                base_url="http://testserver",
            ) as client:
                response = await client.patch(
                    "/xiaozhi/v1/profile",
                    json={
                        "device_id": "device-1",
                        "client_id": "client-1",
                        "character_key": "lulu",
                        "user_call_name": "babe",
                    },
                )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(profile.character_key, "lulu")
        self.assertEqual(profile.name, "Lulu")
        self.assertEqual(profile.user_call_name, "babe")
        update_profile.assert_awaited_once_with(profile)
        self.assertEqual(response.json()["name"], "Lulu")

    async def test_patch_profile_rejects_unknown_character_key(self):
        app = FastAPI()
        app.include_router(profile_router.router)
        profile = make_profile(name="Mochi", character_key="mochi")

        with patch(
            "app.router.profile.resolve_agent_profile",
            new=AsyncMock(return_value=(profile, None)),
        ):
            async with httpx.AsyncClient(
                transport=httpx.ASGITransport(app=app),
                base_url="http://testserver",
            ) as client:
                response = await client.patch(
                    "/xiaozhi/v1/profile",
                    json={
                        "device_id": "device-1",
                        "client_id": "client-1",
                        "character_key": "unknown",
                    },
                )

        self.assertEqual(response.status_code, 400)
        self.assertEqual(response.json()["detail"], "Unknown character_key.")


if __name__ == "__main__":
    unittest.main()
