"""SMS 短信服务单元测试."""

from __future__ import annotations

import os

import pytest

from packages.adapters.sms.sms_service import (
    AliyunSmsService,
    NoopSmsService,
    get_sms_service,
)


class TestNoopSmsService:
    """NoopSmsService 空实现测试."""

    def test_send_verification_code_returns_true(self):
        """发送验证码返回True."""
        svc = NoopSmsService()
        result = svc.send_verification_code("13800138000", "123456")
        assert result is True

    def test_send_template_sms_returns_true(self):
        """发送模板短信返回True."""
        svc = NoopSmsService()
        result = svc.send_template_sms(
            "13800138000",
            "SMS_123456",
            {"code": "123456"},
        )
        assert result is True

    def test_send_verification_code_empty_code(self):
        """空验证码也返回True（空实现不做校验）."""
        svc = NoopSmsService()
        result = svc.send_verification_code("13800138000", "")
        assert result is True

    def test_send_template_sms_empty_params(self):
        """空参数也返回True."""
        svc = NoopSmsService()
        result = svc.send_template_sms("13800138000", "TPL_001", {})
        assert result is True


class TestAliyunSmsServiceInit:
    """AliyunSmsService 初始化测试."""

    def test_default_config_from_env(self, monkeypatch):
        """默认从环境变量读取配置."""
        monkeypatch.setenv("ALIYUN_SMS_ACCESS_KEY_ID", "test_key")
        monkeypatch.setenv("ALIYUN_SMS_ACCESS_KEY_SECRET", "test_secret")
        monkeypatch.setenv("ALIYUN_SMS_SIGN_NAME", "测试签名")
        monkeypatch.setenv("ALIYUN_SMS_VERIFY_TEMPLATE_ID", "SMS_TEST_001")

        svc = AliyunSmsService()
        assert svc.access_key_id == "test_key"
        assert svc.access_key_secret == "test_secret"
        assert svc.sign_name == "测试签名"
        assert svc.verify_template_id == "SMS_TEST_001"

    def test_explicit_config_overrides_env(self, monkeypatch):
        """显式参数覆盖环境变量."""
        monkeypatch.setenv("ALIYUN_SMS_ACCESS_KEY_ID", "env_key")
        svc = AliyunSmsService(access_key_id="explicit_key")
        assert svc.access_key_id == "explicit_key"

    def test_default_values_when_no_env(self, monkeypatch):
        """无环境变量时使用默认值."""
        for key in [
            "ALIYUN_SMS_ACCESS_KEY_ID",
            "ALIYUN_SMS_ACCESS_KEY_SECRET",
            "ALIYUN_SMS_SIGN_NAME",
            "ALIYUN_SMS_VERIFY_TEMPLATE_ID",
        ]:
            monkeypatch.delenv(key, raising=False)

        svc = AliyunSmsService()
        assert svc.access_key_id == ""
        assert svc.access_key_secret == ""
        assert svc.sign_name == "小应剪辑"
        assert svc.verify_template_id == "SMS_123456789"

    def test_send_verification_code_delegates_to_template(self):
        """send_verification_code 委托给 send_template_sms."""
        svc = AliyunSmsService(
            access_key_id="key",
            access_key_secret="secret",
            verify_template_id="SMS_VERIFY",
        )
        called_with = {}

        def mock_template_sms(phone, template_id, params):
            called_with["phone"] = phone
            called_with["template_id"] = template_id
            called_with["params"] = params
            return True

        svc.send_template_sms = mock_template_sms
        result = svc.send_verification_code("13800138000", "654321")
        assert result is True
        assert called_with["phone"] == "13800138000"
        assert called_with["template_id"] == "SMS_VERIFY"
        assert called_with["params"] == {"code": "654321"}

    def test_send_template_sms_import_error_returns_false(self):
        """SDK未安装时返回False（ImportError路径）."""
        svc = AliyunSmsService(access_key_id="k", access_key_secret="s")
        # 没有安装SDK时会返回False
        # 由于测试环境可能安装了SDK，这里不强制断言具体结果
        # 只验证函数不会抛异常
        try:
            result = svc.send_template_sms("13800138000", "TPL_001", {"code": "123"})
            assert isinstance(result, bool)
        except Exception as e:
            # SDK可用时可能因为凭证无效而返回False，不应抛未预期的异常
            pytest.fail(f"Unexpected exception: {e}")


class TestGetSmsService:
    """短信服务工厂函数测试."""

    def test_default_noop(self, monkeypatch):
        """默认使用NoopSmsService."""
        monkeypatch.delenv("SMS_PROVIDER", raising=False)
        svc = get_sms_service()
        assert isinstance(svc, NoopSmsService)

    def test_noop_provider(self, monkeypatch):
        """显式指定noop provider."""
        monkeypatch.setenv("SMS_PROVIDER", "noop")
        svc = get_sms_service()
        assert isinstance(svc, NoopSmsService)

    def test_aliyun_provider(self, monkeypatch):
        """指定aliyun provider返回AliyunSmsService."""
        monkeypatch.setenv("SMS_PROVIDER", "aliyun")
        monkeypatch.setenv("ALIYUN_SMS_ACCESS_KEY_ID", "k")
        monkeypatch.setenv("ALIYUN_SMS_ACCESS_KEY_SECRET", "s")
        svc = get_sms_service()
        assert isinstance(svc, AliyunSmsService)

    def test_unknown_provider_falls_back_to_noop(self, monkeypatch):
        """未知provider回退到NoopSmsService."""
        monkeypatch.setenv("SMS_PROVIDER", "unknown_provider_xyz")
        svc = get_sms_service()
        assert isinstance(svc, NoopSmsService)

    def test_provider_case_insensitive(self, monkeypatch):
        """provider大小写不敏感."""
        monkeypatch.setenv("SMS_PROVIDER", "ALIYUN")
        monkeypatch.setenv("ALIYUN_SMS_ACCESS_KEY_ID", "k")
        monkeypatch.setenv("ALIYUN_SMS_ACCESS_KEY_SECRET", "s")
        svc = get_sms_service()
        assert isinstance(svc, AliyunSmsService)
