import 'dart:convert';

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

class TestflightUpload extends Command {
  Function? get error => null;

  @override
  Future execute(DataCommand command) async {
    var data = DataTestflightUpload.fromJson(getParam(command));
    var apiKeyPath = Command.getPathNormal(data.apiKeyPath);
    var ipaPath = Command.getPathNormal(data.ipaPath);

    var shell = StringBuffer();
    shell.write(
        'FASTLANE_DISABLE_PRECHECK=1 fastlane deliver upload_binary --ipa "$ipaPath" --api_key_path "$apiKeyPath" --force --skip_app_version_update true --run_precheck_before_submit false --skip_metadata true --skip_screenshots true');

    var process = await runtime.start(shell,
        workspace: workspace,
        printStderr: false,
        logHandler: Application.logWithType);

    return await completeProcess(process, command, passExitCodes: [1]);
  }
}

class TestflightStatusCheck extends Command {
  Function? get error => null;

  @override
  Future execute(DataCommand command) async {
    var data = DataTestflightStatusCheck.fromJson(getParam(command));

    var fastFile = await BuildiOS.initializeFastlane(
        data.workspace!, data.apiKeyPath, data.appID,
        runtime: runtime);
    var fastlaneContent = fastFile.readAsStringSync();

    fastlaneContent = fastlaneContent
        .replaceFirst('[TARGET_VERSION]', data.version)
        .replaceFirst('[TARGET_BUILD_NUMBER]', data.buildNumber);
    fastFile.writeAsStringSync(fastlaneContent, flush: true);

    var messageInReview = 'Review in progress.';
    var messageComplete = 'Your review has been completed 🎉';
    const result = '[RESULT]: ';
    var isProcessing = true;
    while (isProcessing) {
      var shell = StringBuffer();
      shell.write('cd ${data.workspace}/fastlane');
      shell.write(' && fastlane testflight_status');

      var process = await runtime.run(shell);
      var arr = process.stdout.toString().split('\n');
      for (var item in arr) {
        if (item.contains(result)) {
          var json =
              jsonDecode(item.substring(item.indexOf(result) + result.length));
          if (json['state'] == 'VALID') {
            isProcessing = false;
          }
          break;
        }
      }

      if (isProcessing) {
        print(messageInReview);
        messageInReview += '.';
      } else {
        print(messageComplete);
      }
    }
    return await complete(0, command);
  }
}

class TestflightDistribute extends Command {
  Function? get error => null;

  @override
  Future execute(DataCommand command) async {
    var data = DataTestflightDistribute.fromJson(getParam(command));

    var testers = data.testers != null && data.testers!.isNotEmpty
        ? ' --groups "${data.testers}"'
        : '';
    var message = data.message != null && data.message!.isNotEmpty
        ? ' --changelog "${data.message}"'
        : '';
    var buildNumber = data.buildNumber != null && data.buildNumber!.isNotEmpty
        ? ' --build_number ${data.buildNumber}'
        : '';
    var platform = data.platform ?? 'ios';

    print('Distribute is processing...');
    var shell = StringBuffer();
    shell.write('cd ${data.workspace}/fastlane');
    shell.write(
        ' && fastlane pilot distribute --api_key_path ${data.apiKeyPath} --app_identifier ${data.appID}$testers$message$buildNumber --app-platform $platform');

    var process =
        await runtime.start(shell, logHandler: Application.logWithType);

    return await completeProcess(process, command, passExitCodes: [1]);
  }
}

void registerTestflightCommands() {
  Command.register(
    CommandType.TestflightUpload,
    () => TestflightUpload(),
    spec: const CommandSpec(
      type: CommandType.TestflightUpload,
      category: 'build',
      dataModel: 'DataTestflightUpload',
      samplePath: 'assets/yaml/sample/10_build_ios.yaml',
    ),
  );
  Command.register(
    CommandType.TestflightStatusCheck,
    () => TestflightStatusCheck(),
    spec: const CommandSpec(
      type: CommandType.TestflightStatusCheck,
      category: 'build',
      dataModel: 'DataTestflightStatusCheck',
      samplePath: 'assets/yaml/sample/10_build_ios.yaml',
    ),
  );
  Command.register(
    CommandType.TestflightDistribute,
    () => TestflightDistribute(),
    spec: const CommandSpec(
      type: CommandType.TestflightDistribute,
      category: 'build',
      dataModel: 'DataTestflightDistribute',
      samplePath: 'assets/yaml/sample/10_build_ios.yaml',
    ),
  );
}
