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


import 'package:dio/dio.dart';
import 'package:get/get.dart';
import 'package:naiyouwl/app/bean/ClashServiceInfo.dart';
import 'package:naiyouwl/app/common/LogHelper.dart';
import 'package:naiyouwl/app/const/const.dart';
import 'package:naiyouwl/app/controller/controllers.dart';
import 'package:naiyouwl/app/utils/logger.dart';
import 'package:naiyouwl/app/utils/shell.dart';
import 'package:naiyouwl/app/utils/system_dns.dart';
import 'package:naiyouwl/app/utils/system_proxy.dart';
import 'package:naiyouwl/app/utils/utils.dart';

import 'package:path/path.dart' as path;
import 'package:flutter/foundation.dart';
import 'package:bot_toast/bot_toast.dart';

import 'package:web_socket_channel/io.dart';



final headers = {"User-Agent": "ccore-for-flutter/0.0.1"};

class ServiceController extends GetxController {
  late final _dio = Dio(BaseOptions(baseUrl: 'http://127.0.0.1:9899', headers: headers));
  var serviceMode = false.obs;
  var coreStatus = RunningState.stoped.obs;
  var serviceStatus = RunningState.stoped.obs;

  Process? clashServiceProcess;
  Process? clashCoreProcess;

  bool get isRunning => serviceStatus.value == RunningState.running && coreStatus.value == RunningState.running;
  bool get isCanOperationService =>
      ![RunningState.starting, RunningState.stopping].contains(serviceStatus.value) &&
      ![RunningState.starting, RunningState.stopping].contains(coreStatus.value);
  bool get isCanOperationCore =>
      serviceStatus.value == RunningState.running && ![RunningState.starting, RunningState.stopping].contains(coreStatus.value);

  ServiceController(

  );

  Future<void> initConfig() async{
    _dio.options.baseUrl = 'http://127.0.0.1:${controllers.config.config.value.servicePort}';
  }

  Future<void> startTunService() async {

    try {
      while (true) {
        final data = await fetchInfo();
        if( data.mode != 'service-mode')
        {
          if (serviceStatus.value == RunningState.running) {
            await stopService();
          }
          await install();
        } else {
          break;
        }
      }

    } catch (e) {

      serviceStatus.value = RunningState.error;
      log.debug(e.toString());
     // BotToast.showText(text: e.toString());
    }

  }

  Future<void> isService() async {
    //controllers.global.updateMsg("判断是不是 service-mode");
    //serviceStatus.value = RunningState.starting;
    if (Platform.isLinux) {
      await fixBinaryExecutePermissions(Files.assetsClashService);
      await fixBinaryExecutePermissions(Files.assetsClashCore);
    }
    try {
      final data = await fetchInfo();
      if(data.mode == 'service-mode'){
        serviceMode.value = true;
        controllers.global.updateMsg("服务模式");
        //await serviceModeSwitch(false);
      }

    } catch (_) {

    }
    //serviceStatus.value = RunningState.running;
  }

  Future<void> startService() async {
    //controllers.global.updateMsg("开启服务");
    serviceStatus.value = RunningState.starting;
    if (Platform.isLinux) {
      await fixBinaryExecutePermissions(Files.assetsClashService);
      await fixBinaryExecutePermissions(Files.assetsClashCore);
    }
    // bool isAvailable = await isPortAvailable(controllers.config.servicePort.value);
    // if (!isAvailable) {
    //   controllers.global.updateMsg("端口${controllers.config.servicePort.value}被占用，启动服务失败。");
    //   serviceStatus.value = RunningState.error;
    //   return; // 端口被占用，返回失败
    // }
    try {
      final data = await fetchInfo();
      serviceMode.value = data.mode == 'service-mode';
      controllers.global.updateMsg("服务模式");
    } catch (e) {
      await startUserModeService();
      controllers.global.updateMsg("开启用户服务");
      if (serviceStatus.value == RunningState.error) return;
    }
    serviceStatus.value = RunningState.running;
  }

  Future<void> fixBinaryExecutePermissions(File file) async {
    final stat = await file.stat();
    // 0b001000000
    final has = (stat.mode & 64) == 64;
    if (has) return;
    await Process.run('chmod', ['+x', file.path]);
  }

  Future<void> startUserModeService() async {
    serviceMode.value = false;
    try {
      int? exitCode;
      clashServiceProcess = await Process.start(Files.assetsClashService.path, ['-port','${controllers.config.config.value.servicePort}','user-mode'], mode: ProcessStartMode.inheritStdio);
      clashServiceProcess!.exitCode.then((code) => exitCode = code);

      while (true) {
        await Future.delayed(const Duration(milliseconds: 200));
        if (exitCode == 101) {
          BotToast.showText(text: 'clash-service exit with code: $exitCode,After 10 seconds, try to restart');
          log.error('After 10 seconds, try to restart');
          await Future.delayed(const Duration(seconds: 10));
          await startUserModeService();
          break;
        } else if (exitCode != null) {
          serviceStatus.value = RunningState.error;
          break;
        }
        try {
          await _dio.post('/info');
          break;
        } catch (_) {}
      }
    } catch (e) {
      serviceStatus.value = RunningState.error;
      BotToast.showText(text: e.toString());
    }
  }

  Future<void> stopService() async {
    serviceStatus.value = RunningState.stopping;
    if (coreStatus.value == RunningState.running) await stopClashCore();
    if (!serviceMode.value) {
      if (clashServiceProcess != null) {
        clashServiceProcess!.kill();
        clashServiceProcess = null;
      } else if (kDebugMode) {
        await killProcess(path.basename(Files.assetsClashService.path));
      }
    }
    serviceStatus.value = RunningState.stoped;
  }

    // for macos
    Future<void> waitServiceStart() async {
      while (true) {
        await Future.delayed(const Duration(milliseconds: 100));
        try {
          await _dio.post('/info');
          break;
        } catch (_) {}
      }
    }

    // for windows
    Future<void> waitServiceStop() async {
      while (true) {
        await Future.delayed(const Duration(milliseconds: 100));
        try {
          await _dio.post('/info');
        } catch (e) {
          break;
        }
      }
    }

    Future<ClashServiceInfo> fetchInfo() async {
      final res = await _dio.post('/info');
      return ClashServiceInfo.fromJson(res.data);
    }

    IOWebSocketChannel fetchLogWs() {
      return IOWebSocketChannel.connect(Uri.parse('ws://127.0.0.1:${controllers.config.config.value.servicePort}/logs'), headers: headers);
    }

    Future<void> fetchStart(String name) async {
      await fetchStop();
      final res = await _dio.post<String>('/start', data: {
        "args": ['-d', Paths.config.path, '-f', path.join(Paths.config.path, name)]
      });
      if (json.decode(res.data!)["code"] != 0) throw json.decode(res.data!)["msg"];
    }

    Future<void> fetchStop() async {
      try {
        await _dio.post('/stop');
      } catch (e) {
        return;
      }
    }

    Future<void> install() async {
      final res = await runAsAdmin(Files.assetsClashService.path, ["-port","${controllers.config.config.value.servicePort}","stop", "uninstall", "install", "start"]);
      await initConfig();
      log.debug('install', res.stdout, res.stderr);
      if (res.exitCode != 0) throw res.stderr;
      await waitServiceStart();
    }

    Future<void> uninstall() async {
      final res = await runAsAdmin(Files.assetsClashService.path, ["stop", "uninstall"]);
      log.debug('uninstall', res.stdout, res.stderr);
      if (res.exitCode != 0) throw res.stderr;
      await waitServiceStop();
    }

    Future<void> serviceModeSwitch(bool open) async {
      if (serviceStatus.value == RunningState.running) await stopService();
      if (coreStatus.value == RunningState.running) await stopClashCore();
      try {
        controllers.global.updateMsg(open ? "安装服务" : "卸载服务");
        open ? await install() : await uninstall();
      } catch (e) {
        BotToast.showText(text: e.toString());
      }
      if(open){
        await startService();
        await startClashCore();
      }else{
        serviceMode.value = false;
        await startClashCore();
      }
      //await startClashCore();
    }
  Future<bool> isPortAvailable(int port) async {
    try {
      // 尝试绑定一个socket到指定的端口
      var server = await ServerSocket.bind(InternetAddress.anyIPv4, port);
      // 成功绑定后立即关闭
      await server.close();
      // 如果成功绑定并关闭了服务器，那么端口是可用的
      return true;
    } on SocketException {
      // 如果绑定失败，端口被占用
      return false;
    }
  }
    Future<bool> startClashCore() async {
      final timeout = const Duration(seconds: 30); // 设置超时时间为30秒
      final checkInterval = const Duration(milliseconds: 200);
      var startTime = DateTime.now();
      await controllers.config.readClashCoreApi();
      // bool isAvailable = await isPortAvailable(controllers.config.mixedPort.value);
      // if (!isAvailable) {
      //   controllers.global.updateMsg("端口 被占用，启动内核失败,等待几秒后重新测试。");
      //   return false; // 端口被占用，返回失败
      // }
      // isAvailable = await isPortAvailable(controllers.config.ApiAddressPort.value);
      // if (!isAvailable) {
      //   controllers.global.updateMsg("端口 被占用，启动内核失败,等待几秒后重新测试。");
      //   return false; // 端口被占用，返回失败
      // }

      try {
        controllers.global.updateMsg("启动内核---${controllers.config.config.value.selected}");
        if( controllers.config.config.value.selected == 'init_proxy.yaml'){
          controllers.global.updateMsg("启动内核初始化");
        } else {
          controllers.global.updateMsg("启动内核");
        }
        coreStatus.value = RunningState.starting;

        if(serviceMode.value == true){
          await fetchStart(controllers.config.config.value.selected);
        }
        else
        {
          int? exitCode;
          clashCoreProcess = await Process.start(Files.assetsCCore.path, ['-d', Paths.config.path, '-f', path.join(Paths.config.path, controllers.config.config.value.selected)], mode: ProcessStartMode.inheritStdio);
          clashCoreProcess!.exitCode.then((code) => exitCode = code);
          if (exitCode != null && exitCode != 0) {
            // 非零退出代码通常表示错误
            controllers.global.updateMsg("启动内核错误,请重启点电脑测试");
            return false;
          }
        }

        //
        log.debug("api${controllers.config.clashCoreApiAddress.value}");
        controllers.core.setApi(controllers.config.clashCoreApiAddress.value, controllers.config.clashCoreApiSecret.value);

        while (DateTime.now().difference(startTime) < timeout) {
          try {
            controllers.global.updateMsg("等待内核启动..");
            final ret = await controllers.core.fetchHello();
            // 如果fetchHello成功，跳出循环
            break;
          } catch (_) {
            // 如果fetchHello失败，等待200毫秒后重试
            await Future.delayed(checkInterval);
          }
        }

        // 检查是否超时
        if (DateTime.now().difference(startTime) >= timeout) {
          // 如果超时，更新状态并抛出异常
          coreStatus.value = RunningState.error;
          controllers.global.updateMsg("内核启动超时，重新点击加速后尝试。");
          return false; // 提前退出函数
        }
        await controllers.core.updateConfig();
        coreStatus.value = RunningState.running;
        controllers.global.updateMsg("内核状态:${coreStatus.value == RunningState.running} ");
        controllers.global.updateDate();
        return true;
      } catch (e) {
        log.error("core -- $e");
        controllers.global.updateMsg("启动内核错误");
        //controllers.global.handleApiError(e);
       // BotToast.showText(text: e.toString());
        coreStatus.value = RunningState.error;
        return false;
      }
    }

    Future<void> stopClashCore() async {
      coreStatus.value = RunningState.stopping;
      await controllers.global.closeProxy();
      if(serviceMode.value == true){
        await fetchStop();
      }
      else{
        if(clashCoreProcess != null){
          clashCoreProcess?.kill();
        }
      }

      // killProcess(ClashName.name);
      // if (Platform.isMacOS &&
      //     controllers.service.serviceMode.value &&
      //     controllers.config.clashCoreTunEnable.value &&
      //     controllers.config.clashCoreDns.isNotEmpty) {
      //   await MacSystemDns.instance.set([]);
      // }
      //if (controllers.config.config.value.setSystemProxy) await SystemProxy.instance.set(SystemProxyConfig());
      //await stopClash();

      coreStatus.value = RunningState.stoped;
    }
    Future<void> initClashCoreConfig() async {
      controllers.config.config.value.selected = 'init_proxy.yaml';
       //await stopClashCore();
       await startClashCore();
       if (coreStatus.value == RunningState.error) {
         controllers.global.updateMsg("启动内核失败...");
         //BotToast.showText(text: '重启失败');
       } else {
         await controllers.core.updateVersion();
         controllers.global.updateMsg("启动内核成功...");
         //BotToast.showText(text: '重启成功');
       }
    }

  Future<void> stopClash() async {
    controllers.config.config.value.selected = 'init_proxy.yaml';
    if( coreStatus.value == RunningState.running){
      await controllers.config.readClashCoreApi();
      controllers.core.setApi(controllers.config.clashCoreApiAddress.value, controllers.config.clashCoreApiSecret.value);
      await controllers.core.changeConfig(path.join(Paths.config.path, controllers.config.config.value.selected));
    }
  }
    Future<void> reloadClashCore() async {
      try
        {
          controllers.config.config.value.selected = 'proxy.yaml';
          if( coreStatus.value == RunningState.running){
            controllers.global.updateMsg("切换配置...");
            await controllers.config.readClashCoreApi();
            //controllers.global.updateMsg("${controllers.config.clashCoreApiAddress.value}...");
            controllers.core.setApi(controllers.config.clashCoreApiAddress.value, controllers.config.clashCoreApiSecret.value);
            //controllers.global.updateMsg("setApi${controllers.config.clashCoreApiAddress.value}...");
            await controllers.core.changeConfig(path.join(Paths.config.path, controllers.config.config.value.selected));
            controllers.global.updateMsg("fetchReloadConfig${controllers.config.clashCoreApiAddress.value}...");
          }
        } catch(e){
          controllers.global.updateMsg("重新配置...");
          await controllers.config.readClashCoreApi();
          //controllers.global.updateMsg("${controllers.config.clashCoreApiAddress.value}...");
          controllers.core.setApi(controllers.config.clashCoreApiAddress.value, controllers.config.clashCoreApiSecret.value);
          //controllers.global.updateMsg("setApi${controllers.config.clashCoreApiAddress.value}...");
          await controllers.core.changeConfig(path.join(Paths.config.path, controllers.config.config.value.selected));
      }
      //BotToast.showText(text: '正在重启 Core ……');
      // controllers.global.updateMsg("停止内核...");
      // await stopClashCore();
      // await controllers.config.readClashCoreApi();
      // await startClashCore();
      // if (coreStatus.value == RunningState.error) {
      //   controllers.global.updateMsg("启动内核失败...");
      // } else {
      //   await controllers.core.updateVersion();
      //   controllers.global.updateMsg("启动内核成功...");
      // }
    }

  Future<int> getFreePort() async {
    var server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
    int port = server.port;
    await server.close();
    return port;
  }
}
