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


def test_send_sms_schema():
    skill = _load_skill()
    schema = skill.schema()
    assert schema["name"] == "send_sms"
    assert "to" in schema["parameters"]["properties"]
    assert "body" in schema["parameters"]["properties"]
    assert set(schema["parameters"]["required"]) == {"to", "body"}


async def test_send_sms_missing_account_sid(monkeypatch):
    monkeypatch.delenv("TWILIO_ACCOUNT_SID", raising=False)
    monkeypatch.delenv("TWILIO_AUTH_TOKEN", raising=False)
    monkeypatch.delenv("TWILIO_PHONE_NUMBER", raising=False)
    skill = _load_skill()
    with pytest.raises(ValueError, match="TWILIO_ACCOUNT_SID"):
        await skill.execute({"to": "+14155551234", "body": "Test"})


async def test_send_sms_missing_auth_token(monkeypatch):
    monkeypatch.setenv("TWILIO_ACCOUNT_SID", "ACfake")
    monkeypatch.delenv("TWILIO_AUTH_TOKEN", raising=False)
    monkeypatch.delenv("TWILIO_PHONE_NUMBER", raising=False)
    skill = _load_skill()
    with pytest.raises(ValueError, match="TWILIO_AUTH_TOKEN"):
        await skill.execute({"to": "+14155551234", "body": "Test"})


async def test_send_sms_missing_phone_number(monkeypatch):
    monkeypatch.setenv("TWILIO_ACCOUNT_SID", "ACfake")
    monkeypatch.setenv("TWILIO_AUTH_TOKEN", "fake-token")
    monkeypatch.delenv("TWILIO_PHONE_NUMBER", raising=False)
    skill = _load_skill()
    with pytest.raises(ValueError, match="TWILIO_PHONE_NUMBER"):
        await skill.execute({"to": "+14155551234", "body": "Test"})


async def test_send_sms_body_too_long(monkeypatch):
    monkeypatch.setenv("TWILIO_ACCOUNT_SID", "ACfake")
    monkeypatch.setenv("TWILIO_AUTH_TOKEN", "fake-token")
    monkeypatch.setenv("TWILIO_PHONE_NUMBER", "+15005550006")
    skill = _load_skill()
    with pytest.raises(ValueError, match="too long"):
        await skill.execute({"to": "+14155551234", "body": "x" * 1601})


async def test_send_sms_success(monkeypatch):
    monkeypatch.setenv("TWILIO_ACCOUNT_SID", "ACfake")
    monkeypatch.setenv("TWILIO_AUTH_TOKEN", "fake-token")
    monkeypatch.setenv("TWILIO_PHONE_NUMBER", "+15005550006")
    skill = _load_skill()

    mock_response = MagicMock()
    mock_response.status_code = 201
    mock_response.json.return_value = {"sid": "SMfake123"}

    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({"to": "+14155551234", "body": "Hello"})

    assert "sent" in result["status"].lower()
    assert result["sid"] == "SMfake123"


async def test_send_sms_api_error(monkeypatch):
    monkeypatch.setenv("TWILIO_ACCOUNT_SID", "ACfake")
    monkeypatch.setenv("TWILIO_AUTH_TOKEN", "fake-token")
    monkeypatch.setenv("TWILIO_PHONE_NUMBER", "+15005550006")
    skill = _load_skill()

    mock_response = MagicMock()
    mock_response.status_code = 400
    mock_response.json.return_value = {"message": "Invalid phone number"}
    mock_response.text = "Invalid phone number"

    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="Twilio API error"):
            await skill.execute({"to": "+14155551234", "body": "Hello"})
