#!/usr/bin/env python3
# coding:utf8
"""
测试 P2: 后台健康检查线程功能
演示：
1. 健康检查线程自动启动
2. 失败的数据源被自动探测
3. 恢复的数据源自动重新加入轮询
4. 健康检查间隔可配置
"""

import sys
import os
import time
import logging
import threading

# 添加项目根目录到Python路径
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import pqquotation
from pqquotation.roundrobin import RoundRobinQuotation

# 配置日志以便查看详细信息
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)


def test_health_check_thread_startup():
    """测试1: 健康检查线程自动启动"""
    print("=" * 70)
    print("【测试1：健康检查线程自动启动】")
    print("=" * 70)

    # 创建 roundrobin 实例（默认启用健康检查）
    print("\n创建 RoundRobin 实例（启用健康检查）...")
    rr = RoundRobinQuotation(enable_health_check=True)

    # 检查线程是否启动
    print(f"\n健康检查线程状态：")
    print(f"  是否启用: {rr._enable_health_check}")
    print(f"  线程对象: {rr._health_check_thread}")
    print(f"  线程存活: {rr._health_check_thread.is_alive() if rr._health_check_thread else False}")
    print(f"  检查间隔: {rr._health_check_interval} 秒")
    print(f"  探测超时: {rr._probe_timeout} 秒")
    print(f"  探测股票: {rr._probe_stock_code}")

    if rr._health_check_thread and rr._health_check_thread.is_alive():
        print("\n✓ 健康检查线程已成功启动")
    else:
        print("\n✗ 健康检查线程未启动")

    return rr


def test_health_check_disabled():
    """测试2: 禁用健康检查"""
    print("\n" + "=" * 70)
    print("【测试2：禁用健康检查】")
    print("=" * 70)

    # 创建实例，禁用健康检查
    print("\n创建 RoundRobin 实例（禁用健康检查）...")
    rr_disabled = RoundRobinQuotation(enable_health_check=False)

    print(f"\n健康检查线程状态：")
    print(f"  是否启用: {rr_disabled._enable_health_check}")
    print(f"  线程对象: {rr_disabled._health_check_thread}")

    if not rr_disabled._health_check_thread:
        print("\n✓ 健康检查已正确禁用")
    else:
        print("\n✗ 健康检查应该被禁用但仍在运行")


def test_manual_source_failure_and_recovery():
    """测试3: 手动标记失败并观察自动恢复"""
    print("\n" + "=" * 70)
    print("【测试3：手动标记失败并观察自动恢复】")
    print("=" * 70)

    # 创建实例，设置较短的检查间隔便于测试
    rr = RoundRobinQuotation(enable_health_check=True)
    rr._health_check_interval = 10  # 设置为10秒检查一次

    print(f"\n【初始状态】")
    stats = rr.get_source_stats()
    print(f"  可用数据源: {stats['available_sources']}")
    print(f"  失败数据源: {stats['failed_sources']}")

    # 手动标记 sina 为失败（模拟超时）
    print(f"\n手动标记 'sina' 为失败（模拟超时）...")
    rr._mark_source_failed('sina', is_timeout=True)

    print(f"\n【标记失败后】")
    stats = rr.get_source_stats()
    print(f"  可用数据源: {stats['available_sources']}")
    print(f"  失败数据源: {stats['failed_sources']}")

    if 'sina' in stats['failed_sources']:
        print("\n✓ sina 已被正确标记为失败")
    else:
        print("\n✗ sina 标记失败")

    # 等待健康检查自动恢复
    print(f"\n等待健康检查线程自动恢复（最多等待15秒）...")
    print(f"健康检查间隔: {rr._health_check_interval} 秒")

    max_wait = 15
    recovered = False
    for i in range(max_wait):
        time.sleep(1)
        stats = rr.get_source_stats()

        if 'sina' not in stats['failed_sources']:
            recovered = True
            print(f"\n✓ sina 在 {i+1} 秒后自动恢复！")
            break

        if (i + 1) % 5 == 0:
            print(f"  ... 等待中 {i+1}/{max_wait} 秒")

    if not recovered:
        print(f"\n⚠ sina 在 {max_wait} 秒内未自动恢复")
        print(f"  注意：这可能是因为 sina 数据源确实不可用")

    print(f"\n【最终状态】")
    final_stats = rr.get_source_stats()
    print(f"  可用数据源: {final_stats['available_sources']}")
    print(f"  失败数据源: {final_stats['failed_sources']}")

    return rr


def test_stop_and_restart():
    """测试4: 停止和重启健康检查线程"""
    print("\n" + "=" * 70)
    print("【测试4：停止和重启健康检查线程】")
    print("=" * 70)

    rr = RoundRobinQuotation(enable_health_check=True)

    print(f"\n【初始状态】")
    print(f"  线程存活: {rr._health_check_thread.is_alive()}")

    # 停止健康检查
    print(f"\n停止健康检查线程...")
    rr.stop_health_check()
    time.sleep(1)

    print(f"\n【停止后】")
    print(f"  线程存活: {rr._health_check_thread.is_alive()}")

    if not rr._health_check_thread.is_alive():
        print("\n✓ 健康检查线程已成功停止")
    else:
        print("\n✗ 健康检查线程未能停止")

    # 重启健康检查
    print(f"\n重启健康检查线程...")
    rr.restart_health_check()
    time.sleep(1)

    print(f"\n【重启后】")
    print(f"  线程存活: {rr._health_check_thread.is_alive()}")

    if rr._health_check_thread.is_alive():
        print("\n✓ 健康检查线程已成功重启")
    else:
        print("\n✗ 健康检查线程未能重启")


def test_probe_source_directly():
    """测试5: 直接测试探测方法"""
    print("\n" + "=" * 70)
    print("【测试5：直接测试探测方法】")
    print("=" * 70)

    rr = RoundRobinQuotation(enable_health_check=True)

    print(f"\n开始探测各数据源...")

    for source_name in rr._source_names:
        print(f"\n探测 {source_name}...")
        start_time = time.time()
        result = rr._probe_source(source_name)
        elapsed = time.time() - start_time

        status = "✓ 可用" if result else "✗ 不可用"
        print(f"  结果: {status}")
        print(f"  耗时: {elapsed:.2f} 秒")


def test_health_check_statistics():
    """测试6: 查看健康检查统计信息"""
    print("\n" + "=" * 70)
    print("【测试6：健康检查统计信息】")
    print("=" * 70)

    rr = RoundRobinQuotation(enable_health_check=True)

    # 进行几次正常请求
    print(f"\n执行3次正常请求...")
    for i in range(3):
        data = rr.real('000001')
        if data:
            print(f"  第{i+1}次: ✓ 成功")
        else:
            print(f"  第{i+1}次: ✗ 失败")
        time.sleep(0.5)

    # 显示统计信息
    print(f"\n【统计信息】")
    stats = rr.get_source_stats()

    print(f"\n总体状态:")
    print(f"  可用数据源: {len(stats['available_sources'])}/{stats['total_sources']}")
    print(f"  失败数据源: {len(stats['failed_sources'])}")

    print(f"\n各数据源详情:")
    for source_name in rr._source_names:
        source_stats = stats['sources'][source_name]
        success = source_stats['success']
        failure = source_stats['failure']
        avg_time = source_stats['avg_response_time']
        is_failed = source_name in stats['failed_sources']

        status = "✗ 失败" if is_failed else "✓ 正常"
        print(f"  {source_name:10s} {status:8s} | 成功:{success}次, 失败:{failure}次, 平均:{avg_time:.3f}秒")

    print(f"\n健康摘要:")
    print(f"  {rr.get_health_summary()}")


def main():
    """主测试函数"""
    print("\n")
    print("╔" + "═" * 68 + "╗")
    print("║" + " " * 18 + "P2: 后台健康检查线程测试" + " " * 18 + "║")
    print("╚" + "═" * 68 + "╝")

    try:
        # 测试1: 线程启动
        rr = test_health_check_thread_startup()

        # 测试2: 禁用健康检查
        test_health_check_disabled()

        # 测试3: 手动失败和自动恢复
        test_manual_source_failure_and_recovery()

        # 测试4: 停止和重启
        test_stop_and_restart()

        # 测试5: 直接探测
        test_probe_source_directly()

        # 测试6: 统计信息
        test_health_check_statistics()

        print("\n" + "=" * 70)
        print("【测试总结】")
        print("=" * 70)
        print("\n✓ P2: 后台健康检查线程功能测试完成")
        print("\n功能特性:")
        print("  1. ✓ 健康检查线程自动启动")
        print("  2. ✓ 失败数据源自动探测")
        print("  3. ✓ 恢复数据源自动重新加入")
        print("  4. ✓ 线程可以停止和重启")
        print("  5. ✓ 健康检查间隔可配置")
        print("  6. ✓ 探测超时独立设置")

        # 清理：停止健康检查线程
        if rr and rr._health_check_thread:
            rr.stop_health_check()

    except KeyboardInterrupt:
        print("\n\n用户中断测试")
    except Exception as e:
        print(f"\n\n测试出错: {e}")
        import traceback
        traceback.print_exc()


if __name__ == "__main__":
    main()
