import 'package:dart_framework/utils/system_util.dart';
import 'package:oto/oto/application.dart';
import 'package:oto/oto/commands/command.dart';
import 'package:oto/oto/data/command_data.dart';

class Git extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataGit.fromJson(getParam(command));
    Application.log(workspace);

    var shell = StringBuffer(getCDPath(workspace));
    var commands = data.commands;
    for (var item in commands) {
      shell.write(' $and git ${Command.getPathNormal(item)}');
    }

    var process = await runtime.start(shell);
    return await completeProcess(process, command);
  }
}

// Ignorable errors are suppressed
class GitCommit extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataGitCommit.fromJson(getParam(command));

    var shell = StringBuffer(getCDPath(workspace));
    var addNewFile = data.addNewFile == null ? false : data.addNewFile!;
    var message = data.message;

    if (addNewFile) {
      shell.write(' $and git add -A $and git commit -m "$message"');
    } else {
      shell.write(' $and git commit -am "$message"');
    }

    var process = await runtime.start(shell);
    return await completeProcess(process, command);
  }
}

class GitPull extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataGitPull.fromJson(getParam(command));

    var shell = StringBuffer(getCDPath(workspace));
    shell.write(
        ' $and git switch -c ${data.branch} || git switch ${data.branch}');
    shell.write(' $and git pull origin ${data.branch}');

    var process = await runtime.start(shell);
    return await completeProcess(process, command);
  }
}

// Ignorable errors are suppressed
class GitPush extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataGitPush.fromJson(getParam(command));

    var shell = StringBuffer(getCDPath(workspace));
    if (data.branch == null) {
      shell.write(' $and git push');
    } else {
      shell.write(
          ' $and git switch -c ${data.branch!} || git switch ${data.branch!}');
      shell.write(' $and git push origin ${data.branch!}');
    }

    var process = await runtime.start(shell);
    return await completeProcess(process, command);
  }
}

// Checks out branch if not present locally; switches to it if it exists; optionally pulls
class GitCheckout extends Git {
  @override
  Future execute(DataCommand command) async {
    var data = DataGitCheckout.fromJson(getParam(command));
    var branch = data.branch;

    var shell = StringBuffer(getCDPath(workspace));
    shell.write(' $and git checkout origin/$branch');
    shell.write(' $and git checkout -b $branch');

    var process = await runtime.start(shell);
    var exitCode = process.exitCode ?? await process.process.exitCode;
    var ignores = [128 /*Already exists*/];
    if (ignores.contains(exitCode)) {
      exitCode = 0;
    }

    if (exitCode == 0) {
      shell = StringBuffer(getCDPath(workspace));
      shell.write(' $and git checkout $branch');

      if (data.executePull == null ? true : data.executePull!) {
        shell.write(' $and git pull origin $branch');
      }

      process = await runtime.start(shell);
      exitCode = process.exitCode ?? await process.process.exitCode;
    }

    return await completeProcess(process, command);
  }
}
