// system_tray.dart — 桌面端系统托盘 + 关闭即最小化到托盘。
//
// macOS/Windows/Linux:关闭主窗口不退出,而是隐藏到托盘;托盘图标点击/菜单
// 可重新显示或真正退出。移动端/web 不涉及。
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:tray_manager/tray_manager.dart';
import 'package:window_manager/window_manager.dart';

bool get isDesktop =>
    !kIsWeb && (Platform.isMacOS || Platform.isWindows || Platform.isLinux);

// 单实例锁端口(仅 loopback)。第二个实例绑定失败 → 通知首实例显示窗口后退出。
const _singleInstancePort = 47654;

/// 保证一台机器只有一个 Pangolin 进程。返回 false 表示已有实例在跑
/// (本进程应退出,首实例已被唤起显示)。
Future<bool> ensureSingleInstance() async {
  if (!isDesktop) return true;
  try {
    final server = await ServerSocket.bind(InternetAddress.loopbackIPv4, _singleInstancePort);
    // 首实例:监听后续实例的"唤起"请求 → 显示并聚焦窗口。
    server.listen((socket) {
      socket.destroy();
      windowManager.show();
      windowManager.focus();
    });
    return true;
  } on SocketException {
    // 端口被占 = 已有实例 → 连过去让它显示,然后本进程退出。
    try {
      final s = await Socket.connect(InternetAddress.loopbackIPv4, _singleInstancePort,
          timeout: const Duration(seconds: 1));
      s.destroy();
    } catch (_) {}
    return false;
  }
}

class TrayService with TrayListener, WindowListener {
  TrayService._();
  static final TrayService instance = TrayService._();

  /// 真正退出前的清理钩子(由 app 注册,用于先停内核拆隧道再退出)。
  Future<void> Function()? onBeforeQuit;

  /// 在 runApp 前调用(仅桌面端)。设置窗口拦截关闭 + 托盘图标与菜单。
  Future<void> init() async {
    await windowManager.ensureInitialized();
    // 关闭窗口转为隐藏到托盘(见 onWindowClose)。
    await windowManager.setPreventClose(true);
    windowManager.addListener(this);

    trayManager.addListener(this);
    await trayManager.setIcon('assets/tray_icon.png');
    await trayManager.setToolTip('穿山甲 Pangolin');
    await trayManager.setContextMenu(Menu(items: [
      MenuItem(key: 'show', label: '显示主界面'),
      MenuItem.separator(),
      MenuItem(key: 'quit', label: '退出'),
    ]));
  }

  Future<void> _show() async {
    await windowManager.show();
    await windowManager.focus();
  }

  // ── 托盘事件 ──────────────────────────────────────────────────
  @override
  void onTrayIconMouseDown() => _show();

  @override
  void onTrayIconRightMouseDown() => trayManager.popUpContextMenu();

  @override
  void onTrayMenuItemClick(MenuItem menuItem) async {
    switch (menuItem.key) {
      case 'show':
        _show();
      case 'quit':
        // 退出前先停内核拆隧道(避免 sudo sing-box 孤儿 + TUN 残留)。
        await onBeforeQuit?.call();
        await windowManager.setPreventClose(false);
        await windowManager.destroy();
    }
  }

  // ── 窗口事件 ──────────────────────────────────────────────────
  @override
  void onWindowClose() async {
    // 点关闭 → 隐藏到托盘而非退出(常驻保持隧道)。
    if (await windowManager.isPreventClose()) {
      await windowManager.hide();
    }
  }
}
