import 'package:dart_framework/utils/system_util.dart';
import 'package:oto/cli/cli.dart';
import 'package:oto/oto/application.dart';
import 'package:oto/oto/core/tag_system.dart';
import 'package:oto/oto/data/pipeline_data.dart';
import 'package:oto/oto/pipeline/pipeline.dart';
import 'package:oto/oto/pipeline/pipeline_exe.dart';

/// Iterates over a List or Map and executes on-do pipeline for each element.
/// - List: sets setValue for each item.
/// - Map: sets setKey (optional) and setValue for each key-value pair.
///
/// Example YAML:
/// ```yaml
/// # List iteration
/// - foreach:
///     iterator: <!property.arr>
///     setValue: <@property.item>
///     on-do:
///       - exe: processItem
///
/// # Map iteration
/// - foreach:
///     iterator: <!property.map>
///     setKey: <@property.key>     # optional
///     setValue: <@property.value>
///     on-do:
///       - exe: processEntry
/// ```
class PipelineForeach extends PipelineExecutor {
  late Pipeline? _pipelineOnDo;
  late DataForeach data;

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

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

    return PipelineValidateResult();
  }

  @override
  Future execute() async {
    var iterator = TagSystem.replaceTagValue(data.iterator!, context: runtimeContext);
    var iteratorType = '';
    if(iterator != null)
    {
      if(iterator is List)
      {
        iteratorType = 'List';
        var elementTag = data.setValue;
        for(var item in iterator)
        {
          await TagSystem.setPropertyValue(elementTag, item, context: runtimeContext);
          await _pipelineOnDo?.execute();
        }
      }

      if(iterator is Map)
      {
        iteratorType = 'Map';
        var keyTag = data.setKey;
        var elementTag = data.setValue;
        for(var pair in iterator.entries)
        {
          if(keyTag != null)
          {
            await TagSystem.setPropertyValue(keyTag, pair.key, context: runtimeContext);
          }
          await TagSystem.setPropertyValue(elementTag, pair.value, context: runtimeContext);
          await _pipelineOnDo?.execute();
        }
      }
      await CLI.println('[Pipeline-Foreach ($iteratorType)]', color: Color.magentaStrong);
      Application.log(' - Foreach complete. Loop out');
    }
    return simpleFuture;
  }
}
