// vpn_bridge.dart — Dart↔原生桥接 API 契约（冻结字段）
//
// ═══════════════════════════════════════════════════════════════
// 通道名称（Channel names）
// ═══════════════════════════════════════════════════════════════
//   MethodChannel : pangolin/vpn
//   EventChannel  : pangolin/vpn/status
//   EventChannel  : pangolin/vpn/stats
//
// ═══════════════════════════════════════════════════════════════
// MethodChannel 方法签名（Method signatures）—— 不得私改
// ═══════════════════════════════════════════════════════════════
//   start(String configJson)         → void
//   stop()                           → void
//   getStatus()                      → String ("off"|"connecting"|"on"|"error")
//   selectOutbound(String tag)       → void
//   getActiveOutbound()              → String tag
//   setKillSwitch(bool on)           → void
//
// ═══════════════════════════════════════════════════════════════
// EventChannel 事件 schema —— 不得私改
// ═══════════════════════════════════════════════════════════════
//   pangolin/vpn/status → String
//     值：  "off" | "connecting" | "on" | "error"
//     来源：内核回调（严禁 UI 乐观显示；start 返回 ≠ on）
//
//   pangolin/vpn/stats → Map<String, dynamic>
//     {
//       "uploadBytes"    : int,        // 本次隧道累计上传字节
//       "downloadBytes"  : int,        // 本次隧道累计下载字节
//       "uploadSpeed"    : double,     // bytes/s 瞬时上行速率
//       "downloadSpeed"  : double,     // bytes/s 瞬时下行速率
//       "urltestResults" : [           // urltest 延迟结果列表
//         { "tag": String, "delayMs": int },
//         ...
//       ]
//     }
//     周期：约 1 秒一帧（内核驱动，非固定间隔）
//
// 最后修订：任务 tsk_iP5-_Ztq5THx（桥接 API 面定稿）
// ═══════════════════════════════════════════════════════════════

import 'dart:async';
import 'package:flutter/services.dart';

// ── 状态枚举 ────────────────────────────────────────────────────
// 与 design/flutter/widgets/connect_button.dart VpnStatus 对齐。
// error 为桥接层扩展态，仅由内核回调产生，UI 层按需处理。
enum VpnStatus {
  off,
  connecting,
  on,
  error;

  /// 从原生侧字符串解析
  static VpnStatus fromString(String s) => switch (s) {
        'off' => VpnStatus.off,
        'connecting' => VpnStatus.connecting,
        'on' => VpnStatus.on,
        'error' => VpnStatus.error,
        _ => VpnStatus.error,
      };

  /// 序列化为原生侧字符串
  String toNativeString() => switch (this) {
        VpnStatus.off => 'off',
        VpnStatus.connecting => 'connecting',
        VpnStatus.on => 'on',
        VpnStatus.error => 'error',
      };
}

// ── stats 数据模型 ───────────────────────────────────────────────

class UrltestResult {
  const UrltestResult({required this.tag, required this.delayMs});

  final String tag;
  final int delayMs;

  factory UrltestResult.fromMap(Map<String, dynamic> m) => UrltestResult(
        tag: m['tag'] as String? ?? '',
        delayMs: (m['delayMs'] as num?)?.toInt() ?? -1,
      );

  Map<String, dynamic> toMap() => {'tag': tag, 'delayMs': delayMs};

  @override
  String toString() => 'UrltestResult(tag=$tag, delayMs=$delayMs)';
}

class VpnStatsEvent {
  const VpnStatsEvent({
    required this.uploadBytes,
    required this.downloadBytes,
    required this.uploadSpeed,
    required this.downloadSpeed,
    required this.urltestResults,
  });

  final int uploadBytes;
  final int downloadBytes;
  final double uploadSpeed;
  final double downloadSpeed;
  final List<UrltestResult> urltestResults;

  factory VpnStatsEvent.fromMap(Map<String, dynamic> m) => VpnStatsEvent(
        uploadBytes: (m['uploadBytes'] as num?)?.toInt() ?? 0,
        downloadBytes: (m['downloadBytes'] as num?)?.toInt() ?? 0,
        uploadSpeed: (m['uploadSpeed'] as num?)?.toDouble() ?? 0.0,
        downloadSpeed: (m['downloadSpeed'] as num?)?.toDouble() ?? 0.0,
        urltestResults: ((m['urltestResults'] as List?)
                ?.where((e) => e is Map)
                .map((e) => UrltestResult.fromMap(
                      Map<String, dynamic>.from(e as Map),
                    ))
                .toList()) ??
            const [],
      );

  /// 从平台通道原始 Map（Map<Object?, Object?>）解析，自动转换键类型。
  static VpnStatsEvent fromNativeMap(Map<Object?, Object?> raw) =>
      VpnStatsEvent.fromMap(raw.cast<String, dynamic>());

  Map<String, dynamic> toMap() => {
        'uploadBytes': uploadBytes,
        'downloadBytes': downloadBytes,
        'uploadSpeed': uploadSpeed,
        'downloadSpeed': downloadSpeed,
        'urltestResults': urltestResults.map((r) => r.toMap()).toList(),
      };

  @override
  String toString() =>
      'VpnStatsEvent(up=${uploadBytes}B, down=${downloadBytes}B, '
      'upSpeed=${uploadSpeed.toStringAsFixed(0)}B/s, '
      'downSpeed=${downloadSpeed.toStringAsFixed(0)}B/s, '
      'urltest=${urltestResults.length}nodes)';
}

// ── 抽象接口 ─────────────────────────────────────────────────────

/// Dart 侧 VPN 桥接接口。
/// 实现方：[VpnNativeBridge]（真实原生通道）与 [VpnBridgeMock]（UI 联调）。
abstract class VpnBridge {
  // ── MethodChannel 方法 ──

  /// 启动 VPN。[configJson] 为 sing-box 兼容 JSON 配置字符串。
  /// 返回不代表连接已建立，实际状态由 [statusStream] 驱动。
  Future<void> start(String configJson);

  /// 停止 VPN。
  Future<void> stop();

  /// 查询当前状态（一次性拉取，实时监听用 [statusStream]）。
  Future<VpnStatus> getStatus();

  /// 切换出口节点。[tag] 为 sing-box outbound tag。
  Future<void> selectOutbound(String tag);

  /// 获取当前激活出口节点 tag。
  Future<String> getActiveOutbound();

  /// 设置 Kill Switch 开关。
  Future<void> setKillSwitch({required bool on});

  // ── EventChannel 流 ──

  /// 实时 VPN 状态流（来自内核回调）。
  Stream<VpnStatus> get statusStream;

  /// 约每秒推一帧统计数据流（来自内核计时器）。
  Stream<VpnStatsEvent> get statsStream;

  /// 释放资源。
  void dispose();
}

// ── 原生实现 ─────────────────────────────────────────────────────

/// 生产实现：使用 Flutter MethodChannel / EventChannel 与原生侧通信。
class VpnNativeBridge implements VpnBridge {
  VpnNativeBridge()
      : _method = const MethodChannel('pangolin/vpn'),
        _statusRaw = const EventChannel('pangolin/vpn/status'),
        _statsRaw = const EventChannel('pangolin/vpn/stats');

  // 允许测试注入
  VpnNativeBridge.withChannels({
    required MethodChannel method,
    required EventChannel status,
    required EventChannel stats,
  })  : _method = method,
        _statusRaw = status,
        _statsRaw = stats;

  final MethodChannel _method;
  final EventChannel _statusRaw;
  final EventChannel _statsRaw;

  @override
  Future<void> start(String configJson) =>
      _method.invokeMethod<void>('start', configJson);

  @override
  Future<void> stop() => _method.invokeMethod<void>('stop');

  @override
  Future<VpnStatus> getStatus() async {
    final s = await _method.invokeMethod<String>('getStatus') ?? 'off';
    return VpnStatus.fromString(s);
  }

  @override
  Future<void> selectOutbound(String tag) =>
      _method.invokeMethod<void>('selectOutbound', tag);

  @override
  Future<String> getActiveOutbound() async =>
      await _method.invokeMethod<String>('getActiveOutbound') ?? 'auto';

  @override
  Future<void> setKillSwitch({required bool on}) =>
      _method.invokeMethod<void>('setKillSwitch', on);

  @override
  Stream<VpnStatus> get statusStream => _statusRaw
      .receiveBroadcastStream()
      .map((e) => VpnStatus.fromString(e?.toString() ?? 'error'));

  @override
  Stream<VpnStatsEvent> get statsStream => _statsRaw
      .receiveBroadcastStream()
      .where((e) => e is Map)
      .map((e) => VpnStatsEvent.fromNativeMap(
            Map<Object?, Object?>.from(e as Map),
          ));

  @override
  void dispose() {
    // EventChannel 由 Flutter 引擎管理，无需手动关闭
  }
}
