"""Tests for the text_to_speech skill."""

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

import pytest

from fliiq.runtime.package_data import bundled_skills_dir
from fliiq.runtime.skills.base import SkillBase

SKILLS_DIR = str(bundled_skills_dir())


def _load_skill() -> SkillBase:
    return SkillBase(os.path.join(SKILLS_DIR, "text_to_speech"))


def test_tts_schema():
    skill = _load_skill()
    schema = skill.schema()
    assert schema["name"] == "text_to_speech"
    assert "text" in schema["parameters"]["properties"]
    assert schema["parameters"]["required"] == ["text"]


async def test_tts_missing_api_key(monkeypatch):
    monkeypatch.delenv("MINIMAX_API_KEY", raising=False)
    monkeypatch.delenv("MINIMAX_GROUP_ID", raising=False)
    skill = _load_skill()
    with pytest.raises(ValueError, match="MINIMAX_API_KEY"):
        await skill.execute({"text": "hello"})


async def test_tts_missing_group_id(monkeypatch):
    monkeypatch.setenv("MINIMAX_API_KEY", "fake-key")
    monkeypatch.delenv("MINIMAX_GROUP_ID", raising=False)
    skill = _load_skill()
    with pytest.raises(ValueError, match="MINIMAX_GROUP_ID"):
        await skill.execute({"text": "hello"})


async def test_tts_empty_text(monkeypatch):
    monkeypatch.setenv("MINIMAX_API_KEY", "fake-key")
    monkeypatch.setenv("MINIMAX_GROUP_ID", "fake-group")
    skill = _load_skill()
    with pytest.raises(ValueError, match="empty"):
        await skill.execute({"text": "  "})


async def test_tts_invalid_speed(monkeypatch):
    monkeypatch.setenv("MINIMAX_API_KEY", "fake-key")
    monkeypatch.setenv("MINIMAX_GROUP_ID", "fake-group")
    skill = _load_skill()
    with pytest.raises(ValueError, match="speed"):
        await skill.execute({"text": "hello", "speed": 5.0})


async def test_tts_success(monkeypatch):
    monkeypatch.setenv("MINIMAX_API_KEY", "fake-key")
    monkeypatch.setenv("MINIMAX_GROUP_ID", "fake-group")
    skill = _load_skill()

    fake_audio = b"\xff\xfb\x90\x00" * 100
    fake_hex = fake_audio.hex()

    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"data": {"audio": fake_hex}}

    with patch("httpx.AsyncClient") as mock_client_cls:
        mock_client = AsyncMock()
        mock_client.post.return_value = mock_response
        mock_client_cls.return_value.__aenter__ = AsyncMock(return_value=mock_client)
        mock_client_cls.return_value.__aexit__ = AsyncMock(return_value=False)
        result = await skill.execute({"text": "nei hou"})

    assert "audio_file" in result
    assert result["voice_used"] == "Cantonese_GentleLady"
    assert result["audio_bytes_size"] == len(fake_audio)
    os.unlink(result["audio_file"])


async def test_tts_custom_voice(monkeypatch):
    monkeypatch.setenv("MINIMAX_API_KEY", "fake-key")
    monkeypatch.setenv("MINIMAX_GROUP_ID", "fake-group")
    skill = _load_skill()

    fake_audio = b"\xff\xfb\x90\x00" * 10
    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"data": {"audio": fake_audio.hex()}}

    with patch("httpx.AsyncClient") as mock_client_cls:
        mock_client = AsyncMock()
        mock_client.post.return_value = mock_response
        mock_client_cls.return_value.__aenter__ = AsyncMock(return_value=mock_client)
        mock_client_cls.return_value.__aexit__ = AsyncMock(return_value=False)
        result = await skill.execute(
            {"text": "hello", "voice_id": "female-shaonv", "speed": 0.8}
        )

    assert result["voice_used"] == "female-shaonv"
    os.unlink(result["audio_file"])


async def test_tts_api_error(monkeypatch):
    monkeypatch.setenv("MINIMAX_API_KEY", "fake-key")
    monkeypatch.setenv("MINIMAX_GROUP_ID", "fake-group")
    skill = _load_skill()

    mock_response = MagicMock()
    mock_response.status_code = 401
    mock_response.text = "Unauthorized"

    with patch("httpx.AsyncClient") as mock_client_cls:
        mock_client = AsyncMock()
        mock_client.post.return_value = mock_response
        mock_client_cls.return_value.__aenter__ = AsyncMock(return_value=mock_client)
        mock_client_cls.return_value.__aexit__ = AsyncMock(return_value=False)
        with pytest.raises(ValueError, match="MiniMax API error"):
            await skill.execute({"text": "hello"})
