from __future__ import annotations

import unittest
from pathlib import Path
from tempfile import TemporaryDirectory
from unittest.mock import patch

from fastapi.testclient import TestClient

from backend.api.server import AgentState, _normalize_model_list, create_app


class ModelListTests(unittest.TestCase):
    def test_normalize_model_list_uses_provider_prefixed_llm_ids(self) -> None:
        payload = {
            'data': [
                {
                    'id': 'ASR_NonStreaming',
                    'object': 'model',
                    'owned_by': 'xiaomi',
                    'model_type': 'speech2text',
                },
                {
                    'id': 'DeepSeek-R1-0528',
                    'object': 'model',
                    'owned_by': 'xiaomi',
                    'model_type': 'llm',
                },
                {
                    'id': 'gpt-5',
                    'object': 'model',
                    'owned_by': 'azure_openai',
                    'model_type': 'llm',
                },
                {
                    'id': 'gpt-5.5',
                    'object': 'model',
                    'owned_by': 'azure_openai',
                    'model_type': 'llm',
                },
                {
                    'id': 'gpt-4o-audio-preview',
                    'object': 'model',
                    'owned_by': 'azure_openai',
                    'model_type': 'llm',
                },
                {
                    'id': 'embedding-v1',
                    'object': 'model',
                    'owned_by': 'example',
                    'model_type': 'text-embedding',
                },
                {
                    'id': 'ernie-4.0-turbo-128k',
                    'object': 'model',
                    'owned_by': 'baidu_qianfan',
                    'model_type': 'llm',
                },
                {
                    'id': 'Pro/deepseek-ai/DeepSeek-V3',
                    'object': 'model',
                    'owned_by': 'siliconflow',
                    'model_type': 'llm',
                },
                {
                    'id': 'pa/claude-opus-4-7',
                    'object': 'model',
                    'owned_by': 'ppio',
                    'model_type': 'llm',
                },
                {
                    'id': 'gemini-2.5-flash',
                    'object': 'model',
                    'owned_by': 'ppio',
                    'model_type': 'llm',
                },
            ]
        }

        models = _normalize_model_list(payload)

        self.assertEqual(
            [model['id'] for model in models],
            [
                'azure_openai/gpt-5',
                'ppio/gemini-2.5-flash',
                'ppio/pa/claude-opus-4-7',
                'siliconflow/Pro/deepseek-ai/DeepSeek-V3',
                'xiaomi/DeepSeek-R1-0528',
            ],
        )
        self.assertEqual(models[0]['provider'], 'azure_openai')
        self.assertEqual(models[0]['model_type'], 'llm')

    def test_models_endpoint_returns_provider_prefixed_llm_models(self) -> None:
        class FakeResponse:
            def __enter__(self) -> 'FakeResponse':
                return self

            def __exit__(self, *args: object) -> None:
                return None

            def read(self) -> bytes:
                return (
                    b'{"object":"list","data":['
                    b'{"id":"mimo-v2-flash","object":"model","owned_by":"xiaomi","model_type":"llm"},'
                    b'{"id":"ASR_Streaming","object":"model","owned_by":"xiaomi","model_type":"speech2text"},'
                    b'{"id":"gpt-5","object":"model","owned_by":"azure_openai","model_type":"llm"}'
                    b']}'
                )

        with TemporaryDirectory() as tmp_dir:
            state = AgentState(
                cwd=Path(tmp_dir),
                model='xiaomi/mimo-v2-flash',
                base_url='http://model.example/v1',
                api_key='token',
                timeout_seconds=120.0,
                allow_shell=False,
                allow_write=False,
                session_directory=Path(tmp_dir) / 'sessions',
            )
            client = TestClient(create_app(state))
            with patch('backend.api.server.request.urlopen', return_value=FakeResponse()):
                response = client.get('/api/models')

        self.assertEqual(response.status_code, 200)
        payload = response.json()
        self.assertEqual(payload['raw_count'], 3)
        self.assertEqual(payload['filtered_count'], 2)
        self.assertEqual(
            [model['id'] for model in payload['models']],
            ['azure_openai/gpt-5', 'xiaomi/mimo-v2-flash'],
        )


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