"""测试用例"""

import pytest
from unittest.mock import Mock, patch
from shinny_quant import ShinnyQuantClient, Period
from shinny_quant.exceptions import AuthenticationError, ApiError


class TestShinnyQuantClient:
    """客户端测试"""

    def test_client_initialization(self):
        """测试客户端初始化"""
        client = ShinnyQuantClient()
        assert client.token is None
        assert not client.is_authenticated
        assert client._timeout == 30

    def test_client_with_custom_timeout(self):
        """测试自定义超时时间"""
        client = ShinnyQuantClient(timeout=60)
        assert client._timeout == 60

    @patch("shinny_quant.client.requests.Session.post")
    def test_client_with_auth_auto_login(self, mock_post):
        """测试使用 auth 参数自动登录"""
        mock_response = Mock()
        mock_response.ok = True
        mock_response.json.return_value = {"token": "auto_login_token"}
        mock_post.return_value = mock_response

        client = ShinnyQuantClient(auth=("test_user", "test_pass"))

        assert client.token == "auto_login_token"
        assert client.is_authenticated
        mock_post.assert_called_once()

    @patch("shinny_quant.client.requests.Session.post")
    def test_client_with_auth_and_timeout(self, mock_post):
        """测试同时使用 auth 和 timeout 参数"""
        mock_response = Mock()
        mock_response.ok = True
        mock_response.json.return_value = {"token": "test_token"}
        mock_post.return_value = mock_response

        client = ShinnyQuantClient(auth=("user", "pass"), timeout=60)

        assert client.token == "test_token"
        assert client._timeout == 60

    @patch("shinny_quant.client.requests.Session.post")
    def test_login_success(self, mock_post):
        """测试登录成功"""
        mock_response = Mock()
        mock_response.ok = True
        mock_response.json.return_value = {"token": "test_token_123"}
        mock_post.return_value = mock_response

        client = ShinnyQuantClient()
        token = client.login("test_user", "test_pass")

        assert token == "test_token_123"
        assert client.token == "test_token_123"
        assert client.is_authenticated

    @patch("shinny_quant.client.requests.Session.post")
    def test_login_unauthorized(self, mock_post):
        """测试登录失败 - 401"""
        mock_response = Mock()
        mock_response.ok = False
        mock_response.status_code = 401
        mock_post.return_value = mock_response

        client = ShinnyQuantClient()
        with pytest.raises(AuthenticationError, match="用户名或密码错误"):
            client.login("wrong_user", "wrong_pass")

    def test_logout(self):
        """测试登出"""
        client = ShinnyQuantClient()
        client._token = "test_token"
        assert client.is_authenticated

        client.logout()
        assert client.token is None
        assert not client.is_authenticated

    @patch("shinny_quant.client.requests.Session.get")
    def test_get_kline_with_dataframe(self, mock_get):
        """测试获取 K 线数据 DataFrame"""
        csv_data = """datetime_nano,open,high,low,close,volume,open_oi,close_oi
1690851600000000000,38520,38610,38480,38590,1234,456789,456999
1690855200000000000,38590,38650,38550,38620,1567,456999,457200"""

        mock_response = Mock()
        mock_response.ok = True
        mock_response.text = csv_data
        mock_get.return_value = mock_response

        client = ShinnyQuantClient()
        df = client.get_kline(
            symbol="SHFE.rb2501",
            period=Period.DAILY,
            start_time="2023-08-01 09:00:00",
            end_time="2023-08-31 15:00:00",
        )

        assert len(df) == 2
        assert "datetime" in df.index.name or df.index.name is None
        assert "open" in df.columns
        assert "close" in df.columns

    @patch("shinny_quant.client.requests.Session.get")
    def test_get_kline_raw(self, mock_get):
        """测试获取原始 CSV 数据"""
        csv_data = """datetime_nano,open,close
1690851600000000000,38520,38590"""

        mock_response = Mock()
        mock_response.ok = True
        mock_response.text = csv_data
        mock_get.return_value = mock_response

        client = ShinnyQuantClient()
        result = client.get_kline_raw(
            symbol="SHFE.rb2501",
            period=Period.MINUTE,
        )

        assert result == csv_data

    @patch("shinny_quant.client.requests.Session.get")
    def test_get_kline_with_error(self, mock_get):
        """测试 API 错误"""
        mock_response = Mock()
        mock_response.ok = False
        mock_response.status_code = 400
        mock_response.text = "400,invalid period"
        mock_get.return_value = mock_response

        client = ShinnyQuantClient()
        with pytest.raises(ApiError) as exc_info:
            client.get_kline(
                symbol="SHFE.rb2501",
                period=999,  # 无效周期
            )

        assert exc_info.value.status_code == 400
        assert "invalid period" in exc_info.value.message

    def test_context_manager(self):
        """测试上下文管理器"""
        with ShinnyQuantClient() as client:
            assert client is not None
            assert hasattr(client, "get_kline")


class TestPeriod:
    """周期枚举测试"""

    def test_period_values(self):
        """测试周期值"""
        assert Period.MINUTE == 60
        assert Period.DAILY == 86400
        assert int(Period.MINUTE) == 60
        assert int(Period.DAILY) == 86400


class TestModels:
    """模型测试"""

    def test_make_symbol(self):
        """测试构造合约标识"""
        from shinny_quant.models import make_symbol, Exchange

        symbol = make_symbol(Exchange.SHFE, "rb2501")
        assert symbol == "SHFE.rb2501"

    def test_make_continuous_symbol(self):
        """测试构造主连合约标识"""
        from shinny_quant.models import make_continuous_symbol, Exchange

        symbol = make_continuous_symbol(Exchange.CFFEX, "IF")
        assert symbol == "KQ.m@CFFEX.IF"

    def test_make_index_symbol(self):
        """测试构造指数合约标识"""
        from shinny_quant.models import make_index_symbol, Exchange

        symbol = make_index_symbol(Exchange.SHFE, "bu")
        assert symbol == "KQ.i@SHFE.bu"

    def test_exchange_constants(self):
        """测试交易所常量"""
        from shinny_quant.models import Exchange

        assert Exchange.SHFE == "SHFE"
        assert Exchange.DCE == "DCE"
        assert Exchange.CZCE == "CZCE"
        assert Exchange.CFFEX == "CFFEX"
        assert Exchange.INE == "INE"
        assert Exchange.GFEX == "GFEX"


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
