import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:flashlink/app/controllers/windows/window_service.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import 'package:uuid/uuid.dart';

import '../../config/translations/strings_enum.dart';
import '../../utils/log/logger.dart';
import '../constants/configs.dart';
import '../constants/enums.dart';
import '../constants/errors.dart';
import 'base_core_api.dart';
import 'windows/menu_base/src/menu.dart';
import 'windows/menu_base/src/menu_item.dart';
import 'windows/stat_log_entry.dart';
import 'windows/vpn_service.dart';

/// Windows 实现
class WindowsCoreApi implements BaseCoreApi {
  static const _tag = 'WindowsCoreApi';

  WindowsCoreApi._() {
    // 初始化事件通道
    _initEventChannel();
    // 初始化vpn服务
    _initVpnService();
    // 初始化窗口服务
    _initWindowService();
  }

  // 创建vpn服务
  static final _vpn = VpnService();
  // 创建窗口服务
  static final _windowService = WindowService();

  // 检查定时器
  Timer? _checkTimer;

  bool _hasConnectedOnce = false;
  bool _isVpnInited = false;

  int _remainTime = 0x7FFFFFFFFFFFFFFF; // 会员剩余时间
  int _sessionCountUp = 0; // session计时
  bool _isCountdown = false; // 汇报计时类型 倒计时还是正计时

  int _locationId = 0;
  String _locationCode = '';
  String _boostSessionId = '';

  /// 内部构造方法，供 BaseCoreApi 工厂使用
  factory WindowsCoreApi.create() => WindowsCoreApi._();

  // Windows Method Channel
  static const MethodChannel _channel = MethodChannel(
    'com.flashlink.vpn/core_api',
  );

  // Windows 事件流控制器
  static final StreamController<String> _eventController =
      StreamController<String>.broadcast();

  // Windows 事件流
  static Stream<String> get eventStream => _eventController.stream;

  // 初始化事件监听
  void _initEventChannel() {
    // 监听来自 Windows 原生端的方法调用
    _channel.setMethodCallHandler(_handleMethodCall);
  }

  // 处理来自 Windows 原生端的方法调用
  Future<dynamic> _handleMethodCall(MethodCall call) async {
    switch (call.method) {
      case 'onEventChange':
        // 原生端发送事件，转发到事件流
        final String event = call.arguments as String;
        _eventController.add(event);
        return null;
      default:
        throw PlatformException(
          code: 'Unimplemented',
          message: 'Method ${call.method} not implemented',
        );
    }
  }

  void _initWindowService() {
    _windowService.initialize();

    _updatTrayIcon();
    _setTrayMenu();
  }

  void _initVpnService() {
    if (_isVpnInited) {
      return;
    }
    _isVpnInited = true;

    // 初始化vpn服务 10秒超时
    _vpn.initialize(10, false);

    // 监听VPN服务状态
    _vpn.onStatusChanged.listen((event) async {
      final (status, data) = event;
      // 处理VPN连接状态
      switch (status) {
        case VpnStatus.connecting:
          _handleStateConnecting();
          break;
        case VpnStatus.connected:
          _handleStateConnected();
          break;
        case VpnStatus.error:
          final code = data != null ? data as int : -1;
          _handleStateError(code);
          break;
        case VpnStatus.idle:
          _handleStateDisconnected();
          break;
      }
      // 更新托盘图标
      _updatTrayIcon();
    });
  }

  void _handleStateConnecting() {
    _hasConnectedOnce = false;
    _sessionCountUp = 0;
    // 正在连接
    _eventController.add(
      '{"type":"vpn_status","status":1,"code":0,"message":""}',
    );
  }

  void _handleStateConnected() {
    // 只记录第一次连接成功的时间戳
    if (!_hasConnectedOnce) {
      _sessionCountUp = 0;
    }
    _hasConnectedOnce = true;
    // 创建检测定时器
    _checkTimer ??= Timer.periodic(const Duration(seconds: 1), (_) {
      // 累加1秒
      _sessionCountUp += 1000;
      // 累减1秒
      _remainTime -= 1000;
      // 检查用户会员剩余时间
      _checkMembershipRemaining();
      // 更新连接时长
      _updateSessionDuration();
    });
    // 通知 已经连接
    _eventController.add(
      '{"type":"vpn_status","status":2,"code":0,"message":""}',
    );

    // 获取统计
    _vpn.queryStat().then((stat) {
      log(_tag, 'stat: $stat');
      try {
        final ts = DateTime.now().millisecondsSinceEpoch;
        final connectionHistory = List<ConnectionHistory>.from(
          (stat?['connectionHistory'] ?? []).map(
            (x) => ConnectionHistory.fromJson(x),
          ),
        );

        final param = jsonEncode([
          StatLogEntry(
            id: Uuid().v4(),
            time: ts,
            level: 'info',
            module: 'NM_BoostResult',
            category: 'flashlink',
            fields: Fields(
              code: 0,
              boostSessionId: _boostSessionId,
              success: true,
              locationId: _locationId,
              locationCode: _locationCode,
              generatedTime: ts,
              connectionHistory: connectionHistory,
            ),
          ),
        ]);

        final nodeId = connectionHistory.last.nodeId ?? '';
        final msg = jsonEncode({
          "type": "boost_result",
          "locationCode": _locationCode,
          "nodeId": nodeId,
          "success": true,
          "param": param,
        });
        log(_tag, msg);
        _eventController.add(msg);
      } catch (e) {
        log(_tag, 'parse stat json error: $e');
      }
    });
  }

  void _handleStateError(int code) {
    _eventController.add(
      '{"type":"vpn_status","status":3,"code":$code,"message":""}',
    );
    // 获取统计
    _vpn.queryStat().then((stat) {
      log(_tag, 'stat: $stat');
      try {
        final ts = DateTime.now().millisecondsSinceEpoch;
        final connectionHistory = List<ConnectionHistory>.from(
          (stat?['connectionHistory'] ?? []).map(
            (x) => ConnectionHistory.fromJson(x),
          ),
        );

        final param = jsonEncode([
          StatLogEntry(
            id: Uuid().v4(),
            time: ts,
            level: 'info',
            module: 'NM_BoostResult',
            category: 'flashlink',
            fields: Fields(
              code: code,
              boostSessionId: _boostSessionId,
              success: false,
              locationId: _locationId,
              locationCode: _locationCode,
              generatedTime: ts,
              connectionHistory: connectionHistory,
            ),
          ),
        ]);

        final nodeId = connectionHistory.last.nodeId ?? '';
        final msg =
            '{"type":"boost_result","locationCode":"$_locationCode","nodeId":"$nodeId","success":false, "param": $param}';

        _eventController.add(msg);
      } catch (e) {
        log(_tag, 'parse stat json error: $e');
      }
    });
    _vpn.stop();
  }

  void _handleStateDisconnected() {
    _checkTimer?.cancel();
    _checkTimer = null;
    final isNoRemainTime = _remainTime <= 0;
    if (isNoRemainTime) {
      _eventController.add(
        '{"type":"vpn_status","status":3,"code":${Errors.ERROR_REMAIN_TIME},"message":""}',
      );
    } else {
      _eventController.add(
        '{"type":"vpn_status","status":0,"code":0,"message":""}',
      );
    }
  }

  void _checkMembershipRemaining() {
    // 没有会员时间
    if (_remainTime < 1000) {
      log(_tag, 'no remain time, need to disconnect.');
      // 断开vpn
      _vpn.stop();
    }
  }

  void _updateSessionDuration() {
    if (_isCountdown) {
      _eventController.add(
        '{"type":"timer_update","currentTime":$_remainTime,"mode":1}',
      );
    } else {
      _eventController.add(
        '{"type":"timer_update","currentTime":$_sessionCountUp,"mode":0}',
      );
    }
  }

  void _updatTrayIcon() {
    final isDark = Get.theme.brightness == Brightness.dark;
    // 更新提示栏
    _windowService.setSystemTrayIcon(
      _vpn.status == VpnStatus.connected,
      isDark,
      Configs.appName,
    );
  }

  void _setTrayMenu() {
    final trayMenu = Menu(
      items: [
        MenuItem(label: Strings.showWindow.tr, key: 'active'),
        MenuItem.separator(),
        MenuItem(label: Strings.quitApp.tr, key: 'quit'),
      ],
    );

    _windowService.setSystemTrayMenu(trayMenu, (menuItem) {
      if (menuItem.key == 'quit') {
        _windowService.quitApplication();
      } else if (menuItem.key == 'active') {
        _windowService.activeWindow();
      }
    });
  }

  @override
  Future<String?> getApps() async {
    // Windows 不需要获取应用列表
    return null;
  }

  @override
  Future<String?> getSystemLocale() async {
    return Platform.localeName;
  }

  @override
  Future<bool?> connect(
    String sessionId,
    int socksPort,
    String tunnelConfig,
    String configJson,
    int remainTime,
    bool isCountdown,
    List<String> allowVpnApps,
    List<String> disallowVpnApps,
    String accessToken,
    String aesKey,
    String aesIv,
    int locationId,
    String locationCode,
    List<String> baseUrls,
    String params,
    int peekTimeInterval,
  ) async {
    // 记录会员剩余时间
    _remainTime = remainTime;
    _isCountdown = isCountdown;
    _locationId = locationId;
    _locationCode = locationCode;
    _boostSessionId = sessionId;

    String geoPath = await _getGeoDirectory();

    final selfExecutable = Platform.resolvedExecutable;

    List<String> allowExes = [];
    List<String> disallowExes = [selfExecutable];

    // 连接参数
    Map<String, dynamic> params = {
      'sessionId': sessionId,
      'connectOptions': jsonEncode({
        'geoPath': geoPath,
        'nodesConfig': configJson,
      }),
      'allowExes': allowExes,
      'disallowExes': disallowExes,
    };

    // 连接vpn
    _vpn.start(params);
    return true;
  }

  @override
  Future<bool?> disconnect() async {
    // 实现 Windows 断开连接逻辑
    await _vpn.stop();
    return true;
  }

  @override
  Future<String?> getRemoteIp() async {
    // 实现 Windows 获取远程 IP
    return await _vpn.getRemoteAddress();
  }

  @override
  Future<String?> getAdvertisingId() async {
    // Windows 不支持广告 ID
    return null;
  }

  @override
  Future<bool?> moveTaskToBack() async {
    // Windows 不需要此功能
    return true;
  }

  @override
  Future<bool?> isConnected() async {
    return _vpn.isOnline && _vpn.status == ConnectionState.connected;
  }

  @override
  Future<String?> getSimInfo() async {
    // Windows 不支持 SIM 卡信息
    return null;
  }

  @override
  Future<String?> getChannel() async {
    return 'windows';
  }

  @override
  Future<void> openPackage(String packageName) async {
    // Windows 不支持打开应用
  }

  /// 发送事件（供 Windows 实现内部使用）
  ///
  /// Windows 原生端可以通过 MethodChannel 发送事件：
  /// ```cpp
  /// // C++ 示例
  /// flutter::MethodChannel<flutter::EncodableValue> channel(
  ///     messenger, "com.flashlink.vpn/core_api",
  ///     &flutter::StandardMethodCodec::GetInstance());
  ///
  /// // 发送 VPN 状态变化
  /// channel.InvokeMethod("onEventChange",
  ///     flutter::EncodableValue("{\"type\":\"vpn_status\",\"status\":2}"));
  /// ```
  ///
  /// 事件 JSON 格式：
  /// - vpn_status: {"type":"vpn_status","status":0|1|2|3,"code":0,"message":""}
  ///   - status: 0=idle, 1=connecting, 2=connected, 3=error
  /// - timer_update: {"type":"timer_update","currentTime":123,"mode":"countdown"}
  /// - boost_result: {"type":"boost_result","locationCode":"US","nodeId":"xxx","success":true}
  static void sendEvent(String event) {
    _eventController.add(event);
  }

  /// 释放资源
  static void dispose() {
    _vpn.dispose();
    _windowService.dispose();
    _eventController.close();
  }

  /// 获取 geo 文件目录
  Future<String> _getGeoDirectory() async {
    try {
      final appDir = await getApplicationSupportDirectory();
      final geoDir = Directory(path.join(appDir.path, 'geo'));
      return geoDir.path;
    } catch (_) {
      return '';
    }
  }
}
