"""MemoryStateStore 单元测试 - 微信 OAuth state 存储

覆盖：正常存取、一次性消费、过期清理、并发安全、空 state 处理。
"""

from __future__ import annotations

import time
from threading import Thread

import pytest


class TestMemoryStateStore:
    def test_put_and_verify_success(self):
        """正常存入并校验成功"""
        from packages.application.auth.wechat_oauth_service import MemoryStateStore

        store = MemoryStateStore()
        store.put("test_state_123")
        assert store.verify_and_consume("test_state_123") is True

    def test_verify_nonexistent_state_fails(self):
        """不存在的 state 校验失败"""
        from packages.application.auth.wechat_oauth_service import MemoryStateStore

        store = MemoryStateStore()
        assert store.verify_and_consume("nonexistent") is False

    def test_state_single_use(self):
        """state 只能消费一次（防重放）"""
        from packages.application.auth.wechat_oauth_service import MemoryStateStore

        store = MemoryStateStore()
        store.put("single_use_state")
        assert store.verify_and_consume("single_use_state") is True
        assert store.verify_and_consume("single_use_state") is False

    def test_empty_state_rejected(self):
        """空字符串 state 校验失败"""
        from packages.application.auth.wechat_oauth_service import MemoryStateStore

        store = MemoryStateStore()
        store.put("")
        # 空字符串作为 key 技术上可以存，但业务层应该拒绝
        # 这里验证 store 本身行为一致性
        assert store.verify_and_consume("") is True  # 存入了就能通过一次
        assert store.verify_and_consume("") is False  # 消费后就没了

    def test_expired_state_cleaned(self):
        """过期 state 会被清理，校验失败"""
        from packages.application.auth.wechat_oauth_service import MemoryStateStore

        # TTL 设为 0.01 秒，快速过期
        store = MemoryStateStore(ttl_seconds=0.01)
        store.put("expire_me")
        time.sleep(0.02)
        assert store.verify_and_consume("expire_me") is False

    def test_multiple_states_independent(self):
        """多个 state 互不影响"""
        from packages.application.auth.wechat_oauth_service import MemoryStateStore

        store = MemoryStateStore()
        store.put("state_a")
        store.put("state_b")
        store.put("state_c")

        # 消费 b
        assert store.verify_and_consume("state_b") is True
        assert store.verify_and_consume("state_b") is False

        # a 和 c 仍然有效
        assert store.verify_and_consume("state_a") is True
        assert store.verify_and_consume("state_c") is True

    def test_clean_expired_doesnt_touch_valid(self):
        """过期清理不影响未过期的 state"""
        from packages.application.auth.wechat_oauth_service import MemoryStateStore

        store = MemoryStateStore(ttl_seconds=10)
        store.put("valid_state")

        # 手动触发清理（通过 verify 触发内部 clean_expired）
        # 由于所有 state 都没过期，清理不影响
        assert store.verify_and_consume("valid_state") is True

    def test_thread_safety_concurrent_put(self):
        """并发写入不丢数据"""
        from packages.application.auth.wechat_oauth_service import MemoryStateStore

        store = MemoryStateStore(ttl_seconds=60)
        states = [f"state_{i}" for i in range(100)]

        def put_states(states_list):
            for s in states_list:
                store.put(s)

        threads = [Thread(target=put_states, args=(states[i * 20 : (i + 1) * 20],)) for i in range(5)]
        for t in threads:
            t.start()
        for t in threads:
            t.join()

        # 每个 state 都能消费一次
        for s in states:
            assert store.verify_and_consume(s) is True

    def test_thread_safety_concurrent_consume(self):
        """并发消费同一个 state 只有一个能成功"""
        from packages.application.auth.wechat_oauth_service import MemoryStateStore

        store = MemoryStateStore()
        store.put("contested_state")

        results = []

        def try_consume():
            results.append(store.verify_and_consume("contested_state"))

        threads = [Thread(target=try_consume) for _ in range(10)]
        for t in threads:
            t.start()
        for t in threads:
            t.join()

        # 只有一个成功，其余失败
        assert sum(1 for r in results if r) == 1
        assert sum(1 for r in results if not r) == 9

    def test_default_ttl_is_10_minutes(self):
        """默认 TTL 是 600 秒（10分钟）"""
        from packages.application.auth.wechat_oauth_service import (
            STATE_TTL_SECONDS,
            MemoryStateStore,
        )

        assert STATE_TTL_SECONDS == 600
        store = MemoryStateStore()
        # 验证默认值生效：存入后立即验证应该通过
        store.put("default_ttl_test")
        assert store.verify_and_consume("default_ttl_test") is True
