"""
E2Eテストスクリプト

パブリッシャー（ダミーモード）とクライアントを同時起動して、
データの送受信が正しく行われることを検証する。
"""

import sys
import time
import threading

# プロジェクトのモジュールをインポート
from rithmic_bridge.config import BridgeConfig, ZmqConfig
from rithmic_bridge.models import (
    MBOEvent, TradeEvent, HeartbeatEvent,
    Side, TOPIC_MBO, TOPIC_TRADE,
)
from rithmic_bridge.publisher.server import ZmqPublisher
from rithmic_bridge.publisher.dummy import DummyDataGenerator
from rithmic_bridge.client.receiver import ZmqReceiver
from rithmic_bridge.client.order_book import OrderBook
from rithmic_bridge.client.trade_analyzer import TradeAnalyzer
from rithmic_bridge.client.state_builder import StateBuilder

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

console = Console()


def run_e2e_test():
    """パブリッシャー + クライアント エンドツーエンドテスト"""

    console.print("\n[bold blue]═══════════════════════════════════════════════[/]")
    console.print("[bold blue]  E2Eテスト: パブリッシャー → クライアント[/]")
    console.print("[bold blue]═══════════════════════════════════════════════[/]\n")

    # テスト用ポート設定（通常のポートと衝突しないよう別ポートを使用）
    test_port = 15600
    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,  # Heartbeat送信分のバッファ余裕を確保
        )
    )

    # ========== パブリッシャー起動 ==========
    console.print("[cyan]1. パブリッシャー起動中...[/]")
    publisher = ZmqPublisher(config)
    publisher.start()

    # ダミーデータジェネレーター起動 (200 events/s)
    dummy = DummyDataGenerator(
        publisher=publisher,
        config=config,
        events_per_second=200,
    )
    dummy.start()
    console.print("[green]   ✓ パブリッシャー + ダミーデータジェネレーター起動完了[/]")

    # ========== クライアント起動 ==========
    console.print("[cyan]2. クライアント起動中...[/]")
    state_builder = StateBuilder(symbol="GCJ6.COMEX", book_levels=5)
    receiver = ZmqReceiver(config)

    # 受信統計用カウント
    received_mbo = []
    received_trade = []
    received_heartbeat = []
    latency_samples = []  # レイテンシ計測用

    def on_mbo(event: MBOEvent):
        received_mbo.append(event)
        state_builder.process_mbo(event)

    def on_trade(event: TradeEvent):
        received_trade.append(event)
        state_builder.process_trade(event)

    def on_heartbeat(event: HeartbeatEvent, latency_ms: float):
        received_heartbeat.append(event)
        latency_samples.append(latency_ms)

    receiver.on_mbo(on_mbo)
    receiver.on_trade(on_trade)
    receiver.on_heartbeat(on_heartbeat)
    receiver.start()
    console.print("[green]   ✓ クライアント起動完了[/]")

    # ========== データ受信 ==========
    console.print("[cyan]3. データ受信中 (5秒間)...[/]")
    time.sleep(5)

    # ========== 結果表示 ==========
    console.print("[cyan]4. 結果を集計中...[/]\n")

    # 受信統計テーブル
    table = Table(title="E2Eテスト結果")
    table.add_column("項目", style="cyan", width=30)
    table.add_column("値", style="green", width=25)
    table.add_column("判定", style="bold", width=10)

    # MBO受信数
    mbo_ok = len(received_mbo) > 0
    table.add_row(
        "MBOイベント受信数",
        str(len(received_mbo)),
        "[green]✓ PASS[/]" if mbo_ok else "[red]✗ FAIL[/]",
    )

    # Trade受信数
    trade_ok = len(received_trade) > 0
    table.add_row(
        "Tradeイベント受信数",
        str(len(received_trade)),
        "[green]✓ PASS[/]" if trade_ok else "[red]✗ FAIL[/]",
    )

    # OrderBook状態
    book = state_builder.order_book
    book_ok = book.order_count > 0
    table.add_row(
        "OrderBook注文数",
        str(book.order_count),
        "[green]✓ PASS[/]" if book_ok else "[red]✗ FAIL[/]",
    )

    # Best Bid/Ask
    best_bid = book.get_best_bid()
    best_ask = book.get_best_ask()
    bb_str = f"{best_bid[0]:.1f} x {best_bid[1]}" if best_bid else "-"
    ba_str = f"{best_ask[0]:.1f} x {best_ask[1]}" if best_ask else "-"
    spread = book.get_spread()
    spread_ok = spread is not None and spread > 0
    table.add_row("Best Bid", bb_str, "")
    table.add_row("Best Ask", ba_str, "")
    table.add_row(
        "Spread",
        f"{spread:.1f}" if spread else "-",
        "[green]✓ PASS[/]" if spread_ok else "[red]✗ FAIL[/]",
    )

    # インバランス
    imbalance = book.get_book_imbalance()
    table.add_row("Book Imbalance", f"{imbalance:+.3f}", "")

    # TradeAnalyzer
    analyzer = state_builder.trade_analyzer
    stats = analyzer.get_stats()
    table.add_row("Buy Volume", str(stats.buy_volume), "")
    table.add_row("Sell Volume", str(stats.sell_volume), "")
    ofi_ok = stats.total_volume > 0
    table.add_row(
        "OFI",
        f"{stats.ofi:+.3f}",
        "[green]✓ PASS[/]" if ofi_ok else "[red]✗ FAIL[/]",
    )
    cum_delta = analyzer.get_cumulative_delta()
    table.add_row("Cumulative Delta", f"{cum_delta:+d}", "")
    table.add_row("VWAP", f"{stats.vwap:.1f}" if stats.vwap > 0 else "-", "")

    # State生成テスト
    state_np = state_builder.get_state_numpy()
    state_ok = state_np is not None and state_np.shape[0] == state_builder.state_dim
    table.add_row(
        "State vector shape",
        str(state_np.shape) if state_np is not None else "None",
        "[green]✓ PASS[/]" if state_ok else "[red]✗ FAIL[/]",
    )

    # 正規化State
    norm_state = state_builder.get_state_normalized()
    norm_ok = norm_state is not None
    table.add_row(
        "Normalized state",
        "OK" if norm_ok else "FAIL",
        "[green]✓ PASS[/]" if norm_ok else "[red]✗ FAIL[/]",
    )

    # Heartbeat検証
    hb_ok = len(received_heartbeat) >= 1  # 最低1件のHeartbeatが受信されればOK
    table.add_row(
        "Heartbeat受信数",
        str(len(received_heartbeat)),
        "[green]✓ PASS[/]" if hb_ok else "[red]✗ FAIL[/]",
    )

    # レイテンシ
    if latency_samples:
        avg_lat = sum(latency_samples) / len(latency_samples)
        min_lat = min(latency_samples)
        max_lat = max(latency_samples)
        lat_ok = avg_lat < 100.0  # ローカルで100ms以下ならOK
        lat_color = "green" if avg_lat < 5 else "yellow" if avg_lat < 50 else "red"
        table.add_row(
            "レイテンシ (avg/min/max)",
            f"[{lat_color}]{avg_lat:.2f}ms[/] / {min_lat:.2f}ms / {max_lat:.2f}ms",
            "[green]✓ PASS[/]" if lat_ok else "[red]✗ FAIL[/]",
        )
    else:
        lat_ok = False
        table.add_row("レイテンシ", "[dim]-[/]", "[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[/]",
    )

    # レート計算
    total_rx = len(received_mbo) + len(received_trade)
    rate = total_rx / 5.0
    table.add_row("受信レート", f"{rate:.1f} msg/s", "")

    console.print(table)

    # ========== クリーンアップ ==========
    console.print("\n[cyan]5. クリーンアップ中...[/]")
    receiver.stop()
    dummy.stop()
    publisher.stop()

    # ========== 総合判定 ==========
    all_passed = all([mbo_ok, trade_ok, book_ok, spread_ok, ofi_ok, state_ok, norm_ok, hb_ok, lat_ok, conn_ok])

    console.print("")
    if all_passed:
        console.print("[bold green]═══════════════════════════════════════════════[/]")
        console.print("[bold green]  ✓ E2Eテスト: 全項目パス！[/]")
        console.print("[bold green]═══════════════════════════════════════════════[/]")
    else:
        console.print("[bold red]═══════════════════════════════════════════════[/]")
        console.print("[bold red]  ✗ E2Eテスト: 一部項目が失敗[/]")
        console.print("[bold red]═══════════════════════════════════════════════[/]")

    return 0 if all_passed else 1


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