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

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

class Copy extends Command {
  @override
  Future execute(DataCommand command) async {
    var data = DataCopy.fromJson(getParam(command));
    var isMove = data.isMove == null ? false : data.isMove!;
    var isOverwrite = data.isOverwrite == null ? true : data.isOverwrite!;
    var entries = data.copyMap.entries;
    try {
      var ignoredList = <String>[];
      for (var entry in entries) {
        var start = Command.getPathNormal(entry.key);
        var dest = Command.getPathNormal(entry.value);
        var destDir = Directory(dest);
        var name = Path.getName(start);
        if (name == "*") {
          //Delete & recreate dest folder
          if (!destDir.existsSync())
          {
            destDir.createSync(recursive: true);
          }
          var startParentStr = Path.getParent(start);
          if (startParentStr != null) {
            var startParent = Directory(startParentStr);
            if (startParent.existsSync()) {
              var files = startParent.listSync();
              for (var file in files) {
                if (file is File) {
                  await Path.copy(file.path, dest, false,
                      ignorePattern: data.ignorePattern,
                      ignoredList: ignoredList,
                      isMove: isMove);
                } else if (file is Directory) {
                  await Path.copy(file.path, dest, true,
                      ignorePattern: data.ignorePattern,
                      ignoredList: ignoredList,
                      isMove: isMove, isOverwrite: isOverwrite);
                }
              }
            } else {
              throw ArgumentError('Start - $start is not exist');
            }
          }
        } else {
          if (!destDir.existsSync()) destDir.createSync(recursive: true);

          var type = Path.getType(start);
          if (FileType.none == type) {
            throw ArgumentError('[FileNotFound] - $start is not exist');
          } else {
            await Path.copy(start, dest, FileType.directory == type,
                ignorePattern: data.ignorePattern,
                ignoredList: ignoredList,
                isMove: isMove);
          }
        }
      }

      if (ignoredList.isNotEmpty) {
        Application.log('==================== Ignored list ====================');
        for (var element in ignoredList) {
          Application.log(element);
        }
        Application.log('======================================================');
      }
    } on Exception catch (e) {
      throw Exception('Copy General Exception: $e');
    }
    return complete(0, command);
  }
}

void registerCopyCommand() {
  Command.register(
    CommandType.Copy,
    () => Copy(),
    spec: const CommandSpec(
      type: CommandType.Copy,
      category: 'file',
      dataModel: 'DataCopy',
      samplePath: 'assets/yaml/sample/07_file.yaml',
    ),
  );
}
