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

import 'package:dart_framework/platform/process.dart';
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 ProcessPortUse extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataProcessPortUse.fromJson(getParam(command));
    try {
      var process = await findUsePortPid(int.parse(data.port));
      var pid = process?.pid.toString();
      setProperty(data.setPid, pid);
    } on Exception {
      rethrow;
    }
    return complete(0, command);
  }
}

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

    var exe = data.executable;
    Application.log('Process Start: $exe');
    var shell = StringBuffer(getCDPath(data.workspace!));
    var dontKillme =
        Platform.isWindows ? 'SET BUILD_ID=dontKillMe' : 'BUILD_ID=dontKillMe';
    var param = data.param == null ? '' : ' ${data.param}';
    shell.writeln(' $and $dontKillme $and $exe$param');
    await runtime.startDetached(shell, workspace: data.workspace!);
    return complete(0, command);
  }
}

class ProcessKill extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataProcessKill.fromJson(getParam(command));
    if (Process.killPid(int.parse(data.pid))) {
      Application.log('Process killed');
    } else {
      Application.log('Process not exist');
    }
    return complete(0, command);
  }
}

void registerProcessCommands() {
  Command.register(
    CommandType.ProcessPortUse,
    () => ProcessPortUse(),
    spec: const CommandSpec(
      type: CommandType.ProcessPortUse,
      category: 'process',
      dataModel: 'DataProcessPortUse',
      samplePath: 'assets/yaml/sample/14_shell_process.yaml',
    ),
  );
  Command.register(
    CommandType.ProcessRun,
    () => ProcessRun(),
    spec: const CommandSpec(
      type: CommandType.ProcessRun,
      category: 'process',
      dataModel: 'DataProcessRun',
      samplePath: 'assets/yaml/sample/14_shell_process.yaml',
    ),
  );
  Command.register(
    CommandType.ProcessKill,
    () => ProcessKill(),
    spec: const CommandSpec(
      type: CommandType.ProcessKill,
      category: 'process',
      dataModel: 'DataProcessKill',
      samplePath: 'assets/yaml/sample/14_shell_process.yaml',
    ),
  );
}
