import 'dart:async';

import 'package:dart_framework/utils/system_util.dart';

import 'command_base.dart';
import 'package:oto/cli/cli.dart';

class CommandManager {
  Map<String, CommandBase> commandMap = {};
  CommandManager(List<CommandBase> commands) {
    for (var command in commands) {
      commandMap[command.name] = command;
    }
  }

  Future execute(String? command, List<String> parameters) async {
    if (command == null) {
      printHelp();
    } else {
      if (commandMap.containsKey(command)) {
        var argStr = '';
        for (var arg in parameters) {
          argStr += '$arg, ';
        }
        var printHelp = false;
        var commandItem = commandMap[command]!;
        if (argStr.isNotEmpty) {
          if (parameters[0].contains('-h')) {
            commandItem.printHelp();
            printHelp = true;
          } else {
            argStr = argStr.replaceFirst(', ', '', argStr.length - 3);
            argStr = ', Arguments: [$argStr]';
          }
        }

        if (!printHelp) {
          if (parameters.isEmpty && !commandItem.shouldExecuteWithoutParameters()) {
            commandItem.printHelp();
          } else {
            if (commandItem.shouldPrintExecuteLog(parameters)) {
              await CLI.println('Execute command: $command$argStr',
                  color: Color.green);
            }
            try {
              await commandItem.execute(parameters);
            } on Exception catch (e) {
              print('');
              var message = e.toString().replaceAll('Exception:', '');
              await CLI.println(
                  '${CLI.style('Error:', background: Color.red)} $message');
              print('');
            }
          }
        }
      } else {
        printHelp(append: [
          '${CLI.style('Error:', background: Color.red)} The ${CLI.style('"$command"', color: Color.red, style: Style.bold)} command does not exist.'
        ]);
      }
    }
    return simpleFuture;
  }

  void printHelp({List<String>? append}) {
    var serviceName = CLI.current.config.serviceName;
    var exeName = CLI.executableFileName;
    final commandTag = '{COMMAND}';
    var list = [
      '',
      'A command-line $serviceName.',
      '',
      'Usage: ${CLI.style('$exeName <command> <-h|[arguments]>', color: Color.greenStrong)}',
      '',
      'Available Command:',
      commandTag,
      '',
      'Command options:',
      '  -h              Print help for the current command.',
      '',
      '',
      "Run `$exeName <command> -h` for more information about a command.",
    ];

    var index = list.indexOf(commandTag);
    list.removeAt(index);

    if (commandMap.isNotEmpty) {
      List<String> commandDescs = [];
      for (var item in commandMap.entries) {
        commandDescs.add(item.value.getCommandDescription());
      }
      list.insertAll(index, commandDescs);
    }

    if (append != null) {
      list.insertAll(0, append);
      list.insert(0, '');
    }
    CLI.print(list);
  }
}
