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';

/// Executes one of two pipelines based on a condition.
/// Condition types: condition-string, condition-int, condition-float,
///                  condition-bool, condition-date, condition-version, condition-object
///
/// Example YAML:
/// ```yaml
/// - if:
///     condition-string: "<!property.env> == prod"
///     on-true:
///       - exe: deployProd
///     on-false:
///       - exe: deployDev
/// ```
class PipelineIf extends PipelineCondition {
  late Pipeline? _pipelineTrue;
  late Pipeline? _pipelineFalse;

  @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 = 'if: value must be a map.';
      return result;
    }
    final rawMap = Map<String, dynamic>.from(raw);
    final onTrue = rawMap['on-true'];
    if (onTrue != null && onTrue is! List) {
      result.enable = false;
      result.message =
          'if: "on-true" must be a list, got: ${onTrue.runtimeType}.';
      return result;
    }
    final onFalse = rawMap['on-false'];
    if (onFalse != null && onFalse is! List) {
      result.enable = false;
      result.message =
          'if: "on-false" must be a list, got: ${onFalse.runtimeType}.';
      return result;
    }
    DataIf data;
    try {
      data = DataIf.fromJson(rawMap);
    } on TypeError catch (_) {
      result.enable = false;
      result.message = 'if: invalid field type in YAML definition.';
      return result;
    }
    var dataValidateResult = data.validate();
    if (!dataValidateResult.enable) {
      return dataValidateResult;
    }
    this.data = data;
    var conditionValidateResult = validateConditionExpression('if');
    if (!conditionValidateResult.enable) {
      return conditionValidateResult;
    }

    //set true task
    var validateResult =
        PipelineExecutor.validateTasks(data.on_true, context: context);
    if (!validateResult.enable) {
      return validateResult;
    }
    _pipelineTrue = validateResult.pipeline;

    //set false task
    validateResult =
        PipelineExecutor.validateTasks(data.on_false, context: context);
    if (!validateResult.enable) {
      return validateResult;
    }
    _pipelineFalse = validateResult.pipeline;

    return result;
  }

  @override
  Future execute() async {
    var condition = data.condition!;
    var result = checkCondition(condition);
    await PipelineExecutor.printCondition(
        'IF', condition, getPostfix(result.result), result);
    if (result.result) {
      await _pipelineTrue?.execute();
    } else {
      await _pipelineFalse?.execute();
    }
    return simpleFuture;
  }

  String getPostfix(bool condition) {
    if (condition) {
      return _pipelineTrue == null
          ? 'on-true not exist. Passed'
          : 'Execute: on-true ';
    } else {
      return _pipelineFalse == null
          ? 'on-false not exist. Passed'
          : 'Execute: on-false ';
    }
  }
}
