import 'dart:io';

import 'package:dart_framework/utils/system_util.dart';
import '../../../oto/core/system_runtime.dart';

class RegistPath {
  final SystemRuntime runtime;

  RegistPath([this.runtime = const DefaultSystemRuntime()]);

  static RegistPath? _instance;
  // ignore: library_private_types_in_public_api, non_constant_identifier_names
  static RegistPath? get OS {
    if (_instance == null) {
      const defaultRuntime = DefaultSystemRuntime();
      if (defaultRuntime.isMacOS) {
        _instance = _RegistPathOSX(defaultRuntime);
      } else if (defaultRuntime.isLinux) {
        _instance = _RegistPathLinux(defaultRuntime);
      } else {
        _instance = _RegistPathWindows(defaultRuntime);
      }
    }
    return _instance;
  }

  factory RegistPath.create(
      {SystemRuntime runtime = const DefaultSystemRuntime()}) {
    if (runtime.isMacOS) {
      return _RegistPathOSX(runtime);
    } else if (runtime.isLinux) {
      return _RegistPathLinux(runtime);
    } else {
      return _RegistPathWindows(runtime);
    }
  }

  Future add(String path) async {
    return await _instance?.add(path);
  }

  Future remove(String path) async {
    return await _instance?.remove(path);
  }
}

/// ************* MAC ***************
class _RegistPathOSX extends RegistPath {
  _RegistPathOSX(super.runtime);

  String getTargetPath(String targetPath) {
    return 'export PATH=\${PATH}:$targetPath';
  }

  String get zprofile {
    var userPath = runtime.environment['HOME'];
    return '$userPath/.zprofile';
  }

  String get bprofile {
    var userPath = runtime.environment['HOME'];
    return '$userPath/.bash_profile';
  }

  @override
  Future add(String path) async {
    await addProfile(zprofile, path);
    await addProfile(bprofile, path);
    await runtime
        .runShell(StringBuffer('source $zprofile && source $bprofile'));
    return simpleFuture;
  }

  Future addProfile(String profilePath, String targetPath) async {
    var file = File(profilePath);
    var contents = '';
    if (file.existsSync()) {
      contents = await file.readAsString();
    } else {
      file.createSync();
    }
    if (contents.lastIndexOf('\n') != contents.length - 1) {
      contents += '\n';
    }
    var addItem = getTargetPath(targetPath);
    if (!contents.contains(addItem)) {
      contents += addItem;
    }

    await file.writeAsString(contents, flush: true);
    return simpleFuture;
  }

  @override
  Future remove(String path) async {
    await removeProfile(zprofile, path);
    await removeProfile(bprofile, path);
    await runtime
        .runShell(StringBuffer('source $zprofile && source $bprofile'));
    return simpleFuture;
  }

  Future removeProfile(String profilePath, String targetPath) async {
    var file = File(profilePath);
    var contents = '';
    if (file.existsSync()) {
      contents = await file.readAsString();
      var removeItem = getTargetPath(targetPath);
      if (contents.contains(removeItem)) {
        contents = contents.replaceAll(removeItem, '');
        await file.writeAsString(contents, flush: true);
      }
    }
    return simpleFuture;
  }
}

/// ************* LINUX ***************
class _RegistPathLinux extends RegistPath {
  _RegistPathLinux(super.runtime);

  @override
  Future add(String path) async {
    return null;
  }

  @override
  Future remove(String path) async {
    return null;
  }
}

/// ************* WINDOWS ***************
class _RegistPathWindows extends RegistPath {
  _RegistPathWindows(super.runtime);
  var setUserPath = '''
@echo off
set "PathUser="
for /F "skip=2 tokens=1,2*" %%G in ('%SystemRoot%\\System32\\reg.exe query "HKCU\\Environment" /v "Path" 2^>nul') do if /I "%%G" == "Path" (
    if /I "%%H" == "REG_EXPAND_SZ" (set "PathExpand=1" & set "PathUser=%%I") else if /I "%%H" == "REG_SZ" set "PathUser=%%I"
)
''';

  @override
  Future add(String path) async {
    var shell = StringBuffer(setUserPath);
    shell.writeln('setx path "%PathUser%;$path');
    await runtime.runShell(shell);
    return simpleFuture;
  }

  @override
  Future remove(String path) async {
    var userPath = runtime.environment['UserProfile'];
    var pathTxt = File('$userPath/path.txt');
    var shell = StringBuffer(setUserPath);
    shell.writeln('echo "%PathUser%" > ${pathTxt.path}');
    await runtime.runShell(StringBuffer(shell));

    await Future.delayed(Duration(seconds: 1));

    if (pathTxt.existsSync()) {
      var contents = pathTxt.readAsStringSync();
      contents = contents.replaceAll(';$path', '');
      contents = contents.trimLeft();
      contents = contents.trimRight();
      print('New User Path =====> $contents');
      await runtime.runShell(StringBuffer('setx path "$contents"'));
      pathTxt.deleteSync();
    }
    return simpleFuture;
  }
}
