"""Tests for the speech_to_text 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, "speech_to_text"))


def test_stt_schema():
    skill = _load_skill()
    schema = skill.schema()
    assert schema["name"] == "speech_to_text"
    assert "audio_file" in schema["parameters"]["properties"]
    assert schema["parameters"]["required"] == ["audio_file"]


async def test_stt_missing_api_key(monkeypatch, tmp_path):
    monkeypatch.delenv("OPENAI_API_KEY", raising=False)
    skill = _load_skill()
    audio = tmp_path / "test.ogg"
    audio.write_bytes(b"\x00" * 100)
    with pytest.raises(ValueError, match="OPENAI_API_KEY"):
        await skill.execute({"audio_file": str(audio)})


async def test_stt_file_not_found(monkeypatch):
    monkeypatch.setenv("OPENAI_API_KEY", "fake-key")
    skill = _load_skill()
    with pytest.raises(ValueError, match="not found"):
        await skill.execute({"audio_file": "/nonexistent/audio.ogg"})


async def test_stt_success(monkeypatch, tmp_path):
    monkeypatch.setenv("OPENAI_API_KEY", "fake-key")
    skill = _load_skill()

    audio = tmp_path / "test.ogg"
    audio.write_bytes(b"\x00" * 100)

    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"text": "Hello world"}

    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({"audio_file": str(audio)})

    assert result["text"] == "Hello world"
    assert result["language"] == "auto"


async def test_stt_with_language(monkeypatch, tmp_path):
    monkeypatch.setenv("OPENAI_API_KEY", "fake-key")
    skill = _load_skill()

    audio = tmp_path / "test.ogg"
    audio.write_bytes(b"\x00" * 100)

    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"text": "nei hou", "language": "zh"}

    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({"audio_file": str(audio), "language": "zh"})

    assert result["text"] == "nei hou"
    assert result["language"] == "zh"


async def test_stt_api_error(monkeypatch, tmp_path):
    monkeypatch.setenv("OPENAI_API_KEY", "fake-key")
    skill = _load_skill()

    audio = tmp_path / "test.ogg"
    audio.write_bytes(b"\x00" * 100)

    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="Whisper API error"):
            await skill.execute({"audio_file": str(audio)})


async def test_stt_empty_transcription(monkeypatch, tmp_path):
    monkeypatch.setenv("OPENAI_API_KEY", "fake-key")
    skill = _load_skill()

    audio = tmp_path / "test.ogg"
    audio.write_bytes(b"\x00" * 100)

    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"text": ""}

    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="empty transcription"):
            await skill.execute({"audio_file": str(audio)})
