import 'dart:async';

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

enum PrintType { error, warning, information }

abstract class CommandBase {
  Map<String, List<String>> get arguments => {};
  String get name;
  String get usage => '';

  Future execute(List<String> parameters);

  bool shouldPrintExecuteLog(List<String> parameters) => true;

  bool shouldExecuteWithoutParameters() => false;

  String getCommandDescription() {
    return '  $name'.padRight(CLI.commandNameSpace) + getDescription();
  }

  String getDescription();

  //==================== print ======================
  final messageTypeMap = {
    PrintType.error: {"color": Color.red, "message": "Error:"},
    PrintType.warning: {"color": Color.yellow, "message": "Warning:"},
    PrintType.information: {"color": Color.green, "message": "Information:"}
  };

  void printOut(String message, PrintType type) {
    var color = messageTypeMap[type]!["color"]! as Color;
    var typeStr = messageTypeMap[type]!["message"]! as String;
    message = '${CLI.style(typeStr, background: color)} $message';
    if (type == PrintType.error) {
      printHelp(append: [message]);
    } else {
      CLI.print([message]);
    }
  }

  void printWarning(String message) {
    printHelp(append: [
      '${CLI.style('Warning:', background: Color.yellow)} $message'
    ]);
  }

  void printInfo(String message) {
    printHelp(
        append: ['${CLI.style('Error:', background: Color.blue)} $message']);
  }

  void printHelp({List<String>? append}) {
    var exeName = CLI.executableFileName;
    final argumentTag = '{ARGUMENTS}';
    final argumentDesc = arguments.isEmpty ? '' : '[arguments]';
    var list = [
      '',
      getDescription(),
      '',
      'Usage: ${CLI.style('$exeName $name $usage', color: Color.greenStrong)}$argumentDesc',
      argumentTag,
    ];

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

    if (arguments.isNotEmpty) {
      List<String> argsDescs = ['', 'Available arguments:'];
      for (var item in arguments.entries) {
        var addedArg = false;
        for (var argDesc in item.value) {
          if (!addedArg) {
            argDesc = '  ${item.key}'.padRight(CLI.commandNameSpace) + argDesc;
            addedArg = true;
          } else {
            argDesc = '  '.padRight(CLI.commandNameSpace) + argDesc;
          }
          argsDescs.add(argDesc);
        }
      }
      argsDescs.add('');
      list.insertAll(index, argsDescs);
    }

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