import 'package:dart_framework/utils/system_util.dart';
import 'package:oto/oto/data/pipeline_data.dart';
import 'package:oto/oto/pipeline/pipeline.dart';
import 'package:oto/oto/pipeline/pipeline_condition.dart';
import 'package:oto/oto/pipeline/pipeline_exe.dart';

/// Repeatedly executes on-do pipeline while the condition is true.
///
/// Example YAML:
/// ```yaml
/// - while:
///     condition-bool: "<!property.isRunning>"
///     on-do:
///       - exe: checkStatus
/// ```
class PipelineWhile extends PipelineCondition {
  late Pipeline? _pipelineOnDo;

  @override
  PipelineValidateResult initialize(Map<String, dynamic> set) {
    var result = super.initialize(set);
    final raw = set.values.first;
    if (raw is! Map) {
      result.enable = false;
      result.message = 'while: value must be a map.';
      return result;
    }
    final rawMap = Map<String, dynamic>.from(raw);
    final onDo = rawMap['on-do'];
    if (onDo != null && onDo is! List) {
      result.enable = false;
      result.message =
          'while: "on-do" must be a list, got: ${onDo.runtimeType}.';
      return result;
    }
    DataWhile data;
    try {
      data = DataWhile.fromJson(rawMap);
    } on TypeError catch (_) {
      result.enable = false;
      result.message = 'while: invalid field type in YAML definition.';
      return result;
    }
    var dataValidateResult = data.validate();
    if (!dataValidateResult.enable) {
      return dataValidateResult;
    }
    this.data = data;
    var conditionValidateResult = validateConditionExpression('while');
    if (!conditionValidateResult.enable) {
      return conditionValidateResult;
    }

    //set do task
    var validateResult =
        PipelineExecutor.validateTasks(data.on_do, context: context);
    if (!validateResult.enable) {
      return validateResult;
    }
    _pipelineOnDo = validateResult.pipeline;

    return result;
  }

  @override
  Future execute() async {
    var condition = data.condition!;
    var result = checkCondition(condition);
    while (result.result) {
      await PipelineExecutor.printCondition(
          'While', condition, 'Execute: on-do', result);
      await _pipelineOnDo?.execute();
      result = checkCondition(data.condition!);
    }
    await PipelineExecutor.printCondition(
        'While', condition, 'Loop escaped.', result);
    return simpleFuture;
  }
}
