import 'package:oto/oto/commands/command.dart';
import 'package:oto/oto/data/command_data.dart';

class StringSub extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataStringSub.fromJson(getParam(command));
    var text = data.text;
    var exitCode = 0;

    try {
      int startIndex = data.startIndex == null ? 0 : data.startIndex!;
      int lastIndex =
          data.lastIndex == null ? text.length - startIndex : data.lastIndex!;
      text = text.substring(startIndex, lastIndex);
      await setProperty(data.setValue, text, showPrint: data.showPrint);
    } on Exception {
      rethrow;
    }

    return await complete(exitCode, command);
  }
}

class StringReplace extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataStringReplace.fromJson(getParam(command));
    var text = data.text;
    var exitCode = 0;

    var list = data.pair;
    for (var pair in list) {
      try {
        if (pair.fromRegExp != null) {
          text = text.replaceAll(RegExp(pair.fromRegExp!), pair.to);
        }
        if (pair.from != null) {
          text = text.replaceAll(pair.from!, pair.to);
        }
      } on Exception {
        rethrow;
      }
    }
    await setProperty(data.setValue, text, showPrint: data.showPrint);

    return await complete(exitCode, command);
  }
}

class StringReplacePattern extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataStringReplacePattern.fromJson(getParam(command));
    
    var startAt = data.startAt ?? 0;
    var text = data.text;
    var value = data.value;
    var exitCode = 0;

    var start = text.indexOf(data.startPattern, startAt);
    var end = text.indexOf(data.endPattern, start);
    text = text.replaceRange(start, end + data.endPattern.length, value);

    await setProperty(data.setValue, text, showPrint: data.showPrint);

    return await complete(exitCode, command);
  }
}

class StringIndex extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataStringIndex.fromJson(getParam(command));
    
    var startAt = data.startAt ?? 0;
    var text = data.text;
    var exitCode = 0;
    var index = text.indexOf(data.value, startAt);

    await setProperty(data.setValue, index, showPrint: data.showPrint);

    return await complete(exitCode, command);
  }
}

class URLInfo extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataURLInfo.fromJson(getParam(command));
    var uri = Uri.parse(data.url);

    if(data.setScheme != null) {
      await setProperty(data.setScheme!, uri.scheme, showPrint: data.showPrint);
    }
    if(data.setHost != null) {
      await setProperty(data.setHost!, uri.host, showPrint: data.showPrint);
    }
    if(data.setPort != null) {
      await setProperty(data.setPort!, uri.port, showPrint: data.showPrint);
    }
    if(data.setPath != null) {
      await setProperty(data.setPath!, uri.path, showPrint: data.showPrint);
    }
    if(data.setQuery != null) {
      await setProperty(data.setQuery!, uri.query, showPrint: data.showPrint);
    }
    if(data.setFragment != null) {
      await setProperty(data.setFragment!, uri.fragment, showPrint: data.showPrint);
    }

    return await complete(0, command);
  }
}


void registerStringUtilCommands() {
  Command.register(
    CommandType.StringSub,
    () => StringSub(),
    spec: const CommandSpec(
      type: CommandType.StringSub,
      category: 'util',
      dataModel: 'DataStringSub',
      samplePath: 'assets/yaml/sample/13_string_json.yaml',
    ),
  );
  Command.register(
    CommandType.StringReplace,
    () => StringReplace(),
    spec: const CommandSpec(
      type: CommandType.StringReplace,
      category: 'util',
      dataModel: 'DataStringReplace',
      samplePath: 'assets/yaml/sample/13_string_json.yaml',
    ),
  );
  Command.register(
    CommandType.StringReplacePattern,
    () => StringReplacePattern(),
    spec: const CommandSpec(
      type: CommandType.StringReplacePattern,
      category: 'util',
      dataModel: 'DataStringReplacePattern',
      samplePath: 'assets/yaml/sample/13_string_json.yaml',
    ),
  );
  Command.register(
    CommandType.StringIndex,
    () => StringIndex(),
    spec: const CommandSpec(
      type: CommandType.StringIndex,
      category: 'util',
      dataModel: 'DataStringIndex',
      samplePath: 'assets/yaml/sample/13_string_json.yaml',
    ),
  );
  Command.register(
    CommandType.URLInfo,
    () => URLInfo(),
    spec: const CommandSpec(
      type: CommandType.URLInfo,
      category: 'util',
      dataModel: 'DataURLInfo',
      samplePath: 'assets/yaml/sample/11_utils.yaml',
    ),
  );
}
