import 'dart:convert';
import 'dart:io';
import 'package:oto/cli/commands/command_base.dart';
import 'package:oto/oto/application.dart';

class CommandValidateCli extends CommandBase {
  final Future<void> Function(String) _printString;

  CommandValidateCli({Future<void> Function(String)? printString})
      : _printString = printString ??
            ((value) async {
              stdout.writeln(value);
            });

  @override
  String get name => 'validate';

  @override
  String get usage => '[arguments]';

  @override
  String getDescription() =>
      'Validate the pipeline yaml file structure and semantics without executing it.';

  @override
  Map<String, List<String>> get arguments => {
        '-f {file path}': ['Validate the yaml file without executing it.'],
        '--json': ['Output validation result as structured JSON format.'],
      };

  @override
  bool shouldPrintExecuteLog(List<String> parameters) {
    return !parameters.contains('--json');
  }

  @override
  bool shouldExecuteWithoutParameters() => false;

  @override
  Future execute(List<String> parameters) async {
    String? filePath;
    bool isJson = false;

    for (int i = 0; i < parameters.length; i++) {
      final param = parameters[i];
      if (param == '--json') {
        isJson = true;
      } else if (param.startsWith('-f')) {
        if (param == '-f') {
          if (i + 1 < parameters.length) {
            filePath = parameters[++i];
          } else {
            throw Exception('Missing value for -f');
          }
        } else {
          filePath = param.substring(2);
        }
      } else if (param.startsWith('--file=')) {
        filePath = param.substring('--file='.length);
      } else if (param == '--file') {
        if (i + 1 < parameters.length) {
          filePath = parameters[++i];
        } else {
          throw Exception('Missing value for --file');
        }
      } else {
        throw Exception('Unknown option: $param');
      }
    }

    if (filePath == null) {
      throw Exception('Missing required option: -f {file path}');
    }

    final file = File(filePath);
    YamlValidationResult result;

    if (!file.existsSync()) {
      result = YamlValidationResult.failure(
        phase: 'Read YAML file',
        message: 'There are no files in path "$filePath"',
        exitCode: 10,
      );
    } else {
      try {
        final content = file.readAsStringSync();
        result = Application.validateYamlContent(content);
      } catch (e) {
        result = YamlValidationResult.failure(
          phase: 'Read YAML file',
          message: e.toString(),
          exitCode: 10,
        );
      }
    }

    exitCode = result.exitCode;

    if (isJson) {
      final jsonMap = result.toJson();
      await _printString(const JsonEncoder.withIndent('  ').convert(jsonMap));
    } else {
      if (result.valid) {
        await _printString('Valid YAML.');
      } else {
        await _printString('Invalid YAML: [${result.phase}] ${result.message}');
      }
    }
  }
}
