import 'dart:io';
import 'package:naiyouwl/app/common/LogHelper.dart';
import 'package:path/path.dart' as path;
import 'package:process_run/shell_run.dart';
enum OS { windows, linux, macos }
enum Architecture { amd64, arm64 }
class ClashName {
  static late final OS os;
  static late final Architecture architecture;
  static late final bool isRoot;
  static void init() {
    os = determineOS();
    architecture = determineArchitecture();
    isRoot = determineIsRoot();
  }
  static String get platform {
    if (Platform.isWindows) return 'windows';
    if (Platform.isMacOS) return 'darwin';
    if (Platform.isLinux) return 'linux';
    return 'unknown';
  }

  static OS determineOS() {
    if(Platform.isWindows) {
      return OS.windows;
    } else if (Platform.isLinux) {
      return OS.linux;
    } else if (Platform.isMacOS){
      return OS.macos;
    } else {
      LogHelper().e('Unsupported OS');
      throw Exception('Unsupported OS');
    }
  }

  static Architecture determineArchitecture() {
    if (os == OS.windows) {
      final arch = Platform.environment['PROCESSOR_ARCHITECTURE'];
      // https://learn.microsoft.com/en-us/windows/win32/winprog64/wow64-implementation-details
      if (arch == 'AMD64') {
        return Architecture.amd64;
      } else if (arch == 'ARM64') {
        return Architecture.arm64;
      } else {
        LogHelper().e('Unsupported Architecture');
        throw Exception('Unsupported Architecture');
      }
    } else {
      final result = Process.runSync('uname', ['-m']);
      if (result.exitCode == 0) {
        final arch = result.stdout.toString().trim();
        if (arch == 'x86_64') {
          return Architecture.amd64;
        } else if (arch == 'aarch64' || arch == 'arm64') {
          return Architecture.arm64;
        } else {
          LogHelper().e('Unsupported Architecture');
          throw Exception('Unsupported Architecture');
        }
      } else {
        LogHelper().e('Unsupported Architecture');
        throw Exception('Unsupported Architecture');
      }
    }
  }

  static bool determineIsRoot() {
    if (os == OS.windows) {
      final result = Process.runSync('net', ['session']);
      if (result.exitCode == 0) {
        return true;
      } else {
        return false;
      }
    } else {
      final result = Process.runSync('id', ['-u']);
      if (result.exitCode == 0) {
        return result.stdout.toString().trim() == '0';
      } else {
        return false;
      }
    }
  }


  static String get arch {
    return architecture.name; //amd64
  }

  static String get ext {
    if (Platform.isWindows) return '.exe';
    return '';
  }

  static String get name {
    return 'ccore-$platform-$arch$ext';
  }
}

class Paths {
  static Directory get assets {
    File mainFile = File(Platform.resolvedExecutable);
    String assetsPath = '../data/flutter_assets/assets';
    if (Platform.isMacOS) assetsPath = '../../Frameworks/App.framework/Resources/flutter_assets/assets';
    return Directory(path.normalize(path.join(mainFile.path, assetsPath)));
  }

  static Directory get assetsBin {
    return Directory(path.join(assets.path, 'bin'));
  }

  static Directory get assetsDep {
    return Directory(path.join(assets.path, 'dep'));
  }

  static Directory get config {
    return Directory(path.join(userHomePath, '.config', 'ccore'));
  }
}

class Files {
  static File get assetsClashCore {
    return File(path.join(Paths.assetsBin.path, ClashName.name));
  }

  static File get assetsClashService {
    if (Platform.isMacOS){
      return File(path.join(Paths.assetsBin.path, 'service-${ClashName.platform}'));
    }
    return File(path.join(Paths.assetsBin.path, 'service-${ClashName.platform}-${ClashName.arch}'));
  }
  static File get assetsCCore {
    if (Platform.isMacOS){
      return File(path.join(Paths.assetsBin.path, 'core-${ClashName.platform}'));
    }
    return File(path.join(Paths.assetsBin.path, 'core-${ClashName.platform}-${ClashName.arch}'));
  }

  static File get assetsSysProxyWin {
    return File(path.join(Paths.assetsBin.path, 'sysproxy64.exe'));
  }

  static File get assetsCountryMmdb {
    return File(path.join(Paths.assetsDep.path, 'Country.mmdb'));
  }
  static File get assetsGeosite {
    return File(path.join(Paths.assetsDep.path, 'geosite.dat'));
  }
  static File get assetsGeoIP {
    return File(path.join(Paths.assetsDep.path, 'geoip.dat'));
  }
  static File get assetsWintun {
    return File(path.join(Paths.assetsDep.path, 'wintun.dll'));
  }

  static File get assetsExample {
    return File(path.join(Paths.assetsDep.path, 'example.yaml'));
  }

  static File get configConfig {
    return File(path.join(Paths.config.path, '.config.json'));
  }

  static File get makeProxyConfig {
    return File(path.join(Paths.config.path, 'proxy.yaml'));
  }

  static File get makeInitProxyConfig {
    return File(path.join(Paths.config.path, 'init_proxy.yaml'));
  }

  static File get versionConfig {
    return File(path.join(Paths.config.path, '.versions.json'));
  }

  static File get configCountryMmdb {
    return File(path.join(Paths.config.path, 'Country.mmdb'));
  }

  static File get configGeoIP {
    return File(path.join(Paths.config.path, 'geoip.dat'));
  }
  static File get configGeosite {
    return File(path.join(Paths.config.path, 'geosite.dat'));
  }

  static File get configWintun {
    return File(path.join(Paths.config.path, 'wintun.dll'));
  }

  static File get configExample {
    return File(path.join(Paths.config.path, 'example.yaml'));
  }
}
