"""
再接続ロジック統合テスト

パブリッシャーを停止・再起動した際に、
レシーバーが自動的に再接続してデータ受信を再開することを検証する。
"""

import sys
import time
import threading

from rich.console import Console
from rich.table import Table

from rithmic_bridge.config import BridgeConfig, ZmqConfig
from rithmic_bridge.models import (
    MBOEvent, MBOAction, Side,
    TOPIC_MBO, TOPIC_HEARTBEAT,
)
from rithmic_bridge.publisher.server import ZmqPublisher
from rithmic_bridge.client.receiver import ZmqReceiver

console = Console()


def run_reconnect_test():
    """再接続ロジックの統合テスト"""

    console.print("\n[bold blue]═══════════════════════════════════════════════[/]")
    console.print("[bold blue]  再接続テスト: パブリッシャー停止→再起動[/]")
    console.print("[bold blue]═══════════════════════════════════════════════[/]\n")

    test_port = 15800
    config = BridgeConfig(
        zmq=ZmqConfig(
            pub_addr=f"tcp://127.0.0.1:{test_port}",
            pub_port=test_port,
            client_host="127.0.0.1",
            client_port=test_port,
            hwm=10000,
            recv_timeout=2000,  # Heartbeat検出を速くするため短めのタイムアウト
        )
    )

    # ===== Phase 1: 初期接続 =====
    console.print("[cyan]Phase 1: 初期接続・データ受信[/]")

    received_phase1 = []
    received_phase2 = []
    reconnect_count = [0]
    current_phase = [1]

    def on_mbo(event: MBOEvent):
        if current_phase[0] == 1:
            received_phase1.append(event)
        else:
            received_phase2.append(event)

    def on_reconnect():
        reconnect_count[0] += 1
        console.print(f"  [yellow]再接続コールバック実行 #{reconnect_count[0]}[/]")

    # レシーバー起動（パブリッシャーより先に起動してOK - ZMQはオーダー不問）
    receiver = ZmqReceiver(config)
    # Heartbeatタイムアウトを短く設定（テスト高速化）
    receiver._heartbeat_timeout = 3.0
    receiver._reconnect_interval = 1.0
    receiver.on_mbo(on_mbo)
    receiver.on_reconnect(on_reconnect)
    receiver.start(topics=[TOPIC_MBO, TOPIC_HEARTBEAT])
    time.sleep(0.3)

    # パブリッシャー1起動
    pub1 = ZmqPublisher(config)
    pub1.start(enable_heartbeat=True)
    time.sleep(1.0)  # 接続確立とHeartbeat受信を待つ

    # データ送信
    for i in range(20):
        event = MBOEvent(
            symbol="GCJ6.COMEX",
            action=MBOAction.ADD,
            order_id=str(i),
            side=Side.BID,
            price=2500.0 + i * 0.1,
            size=5,
        )
        pub1.enqueue_mbo(event.to_json())
        time.sleep(0.05)

    time.sleep(1.0)  # 受信待ち
    phase1_count = len(received_phase1)
    console.print(f"  Phase 1 受信数: {phase1_count}")

    # ===== Phase 2: パブリッシャー停止 =====
    console.print("\n[cyan]Phase 2: パブリッシャー停止[/]")
    pub1.stop()
    console.print("  パブリッシャー停止完了")

    # Heartbeatタイムアウト + 再接続を待つ
    console.print("  Heartbeatタイムアウト待ち (6秒)...")
    time.sleep(6)

    # ===== Phase 3: パブリッシャー再起動 =====
    console.print("\n[cyan]Phase 3: パブリッシャー再起動[/]")
    current_phase[0] = 2

    pub2 = ZmqPublisher(config)
    pub2.start(enable_heartbeat=True)
    time.sleep(2.0)  # 再接続とHeartbeat受信を待つ

    # データ再送信
    for i in range(20):
        event = MBOEvent(
            symbol="GCJ6.COMEX",
            action=MBOAction.ADD,
            order_id=str(100 + i),
            side=Side.ASK,
            price=2501.0 + i * 0.1,
            size=3,
        )
        pub2.enqueue_mbo(event.to_json())
        time.sleep(0.05)

    time.sleep(2.0)  # 受信待ち
    phase2_count = len(received_phase2)
    console.print(f"  Phase 2 受信数: {phase2_count}")

    # ===== 結果表示 =====
    console.print()
    table = Table(title="再接続テスト結果")
    table.add_column("項目", style="cyan", width=30)
    table.add_column("値", style="green", width=20)
    table.add_column("判定", style="bold", width=10)

    # Phase 1: 初期受信
    p1_ok = phase1_count > 0
    table.add_row(
        "Phase 1: 初期受信数",
        str(phase1_count),
        "[green]✓ PASS[/]" if p1_ok else "[red]✗ FAIL[/]",
    )

    # 再接続回数
    rc_ok = reconnect_count[0] >= 1
    table.add_row(
        "再接続回数",
        str(reconnect_count[0]),
        "[green]✓ PASS[/]" if rc_ok else "[red]✗ FAIL[/]",
    )

    # Phase 2: 再起動後受信
    p2_ok = phase2_count > 0
    table.add_row(
        "Phase 2: 再起動後受信数",
        str(phase2_count),
        "[green]✓ PASS[/]" if p2_ok else "[red]✗ FAIL[/]",
    )

    # 接続状態
    conn_ok = receiver.is_publisher_connected
    table.add_row(
        "パブリッシャー接続",
        "[green]● 接続中[/]" if conn_ok else "[red]● 切断[/]",
        "[green]✓ PASS[/]" if conn_ok else "[red]✗ FAIL[/]",
    )

    # 統計
    stats = receiver.stats
    table.add_row("総再接続数 (stats)", str(stats.get("reconnects", 0)), "")

    console.print(table)

    # クリーンアップ
    receiver.stop()
    pub2.stop()

    # 総合判定
    all_passed = all([p1_ok, rc_ok, p2_ok, conn_ok])
    console.print()
    if all_passed:
        console.print("[bold green]═══════════════════════════════════════════════[/]")
        console.print("[bold green]  ✓ 再接続テスト: 全項目パス！[/]")
        console.print("[bold green]═══════════════════════════════════════════════[/]")
    else:
        console.print("[bold red]═══════════════════════════════════════════════[/]")
        console.print("[bold red]  ✗ 再接続テスト: 一部項目が失敗[/]")
        console.print("[bold red]═══════════════════════════════════════════════[/]")

    return 0 if all_passed else 1


if __name__ == "__main__":
    sys.exit(run_reconnect_test())
