// ignore_for_file: non_constant_identifier_names

import 'package:json_annotation/json_annotation.dart';
import 'package:oto/oto/pipeline/pipeline.dart';
part 'pipeline_data.g.dart';

/// ***************************** Base Data ****************************///
abstract class DataValidator {
  PipelineValidateResult validate();
}

@JsonSerializable()
class DataPipeline {
  late String id;
  late List<dynamic> workflow;

  DataPipeline();

  factory DataPipeline.fromJson(Map<String, dynamic> json) =>
      _$DataPipelineFromJson(json);
  Map<String, dynamic> toJson() => _$DataPipelineToJson(this);
}

@JsonSerializable()
class DataCondition implements DataValidator {
  late String? condition;
  late String? type;
  @JsonKey(name: 'condition-int')
  late String? condition_int;
  @JsonKey(name: 'condition-float')
  late String? condition_float;
  @JsonKey(name: 'condition-string')
  late String? condition_string;
  @JsonKey(name: 'condition-date')
  late String? condition_date;
  @JsonKey(name: 'condition-version')
  late String? condition_version;
  @JsonKey(name: 'condition-bool')
  late String? condition_bool;
  @JsonKey(name: 'condition-object')
  late dynamic condition_object;

  DataCondition();

  @override
  PipelineValidateResult validate() {
    var result = PipelineValidateResult();
    if (condition_int != null) {
      condition = condition_int!;
      type = 'int';
    } else if (condition_float != null) {
      condition = condition_float!;
      type = 'float';
    } else if (condition_string != null) {
      condition = condition_string!;
      type = 'string';
    } else if (condition_date != null) {
      condition = condition_date!;
      type = 'date';
    } else if (condition_version != null) {
      condition = condition_version!;
      type = 'version';
    } else if (condition_bool != null) {
      condition = condition_bool!;
      type = 'bool';
    } else if (condition_object != null) {
      condition = condition_object;
      type = 'object';
    } else {
      result.message = 'Syntax requires a condition.';
      result.enable = false;
      return result;
    }

    return result;
  }

  factory DataCondition.fromJson(Map<String, dynamic> json) =>
      _$DataConditionFromJson(json);
  Map<String, dynamic> toJson() => _$DataConditionToJson(this);
}

@JsonSerializable()
class DataExeHandle implements DataValidator {
  late String? id;
  @JsonKey(name: 'on-success')
  late List<dynamic>? on_success;
  @JsonKey(name: 'on-fail')
  late List<dynamic>? on_fail;

  DataExeHandle();

  @override
  PipelineValidateResult validate() {
    var result = PipelineValidateResult();
    if (id == null || id!.trim().isEmpty) {
      result.message = 'exe-handle syntax requires a non-empty id.';
      result.enable = false;
      return result;
    }
    if (on_success == null || on_success!.isEmpty) {
      result.message = 'exe-handle syntax requires on-success.';
      result.enable = false;
      return result;
    }
    if (on_fail == null || on_fail!.isEmpty) {
      result.message = 'exe-handle syntax requires on-fail.';
      result.enable = false;
      return result;
    }
    return result;
  }

  factory DataExeHandle.fromJson(Map<String, dynamic> json) =>
      _$DataExeHandleFromJson(json);
  Map<String, dynamic> toJson() => _$DataExeHandleToJson(this);
}

@JsonSerializable()
class DataIf extends DataCondition {
  @JsonKey(name: 'on-true')
  late List<dynamic>? on_true;
  @JsonKey(name: 'on-false')
  late List<dynamic>? on_false;

  DataIf();

  @override
  PipelineValidateResult validate() {
    var result = super.validate();
    if (!result.enable) {
      return result;
    }

    if (on_true == null && on_false == null) {
      result.message = 'If syntax requires on-true or on-false.';
      result.enable = false;
      return result;
    }
    return result;
  }

  factory DataIf.fromJson(Map<String, dynamic> json) => _$DataIfFromJson(json);
  @override
  Map<String, dynamic> toJson() => _$DataIfToJson(this);
}

@JsonSerializable()
class DataContain extends DataValidator {
  late dynamic list;
  late String target;
  @JsonKey(name: 'on-true')
  late List<dynamic>? on_true;
  @JsonKey(name: 'on-false')
  late List<dynamic>? on_false;

  DataContain();

  @override
  PipelineValidateResult validate() {
    var result = PipelineValidateResult();
    if (!(list is List || list is String)) {
      result.message = 'list field Must be type of "List" or "String".';
      result.enable = false;
      return result;
    }

    if (on_true == null && on_false == null) {
      result.message = 'If syntax requires on-true or on-false.';
      result.enable = false;
      return result;
    }
    return result;
  }

  factory DataContain.fromJson(Map<String, dynamic> json) =>
      _$DataContainFromJson(json);
  Map<String, dynamic> toJson() => _$DataContainToJson(this);
}

@JsonSerializable()
class DataWhile extends DataCondition {
  @JsonKey(name: 'on-do')
  late List<dynamic>? on_do;

  DataWhile();

  @override
  PipelineValidateResult validate() {
    var result = super.validate();
    if (!result.enable) {
      return result;
    }

    if (on_do == null) {
      result.message = 'While syntax requires on-do.';
      result.enable = false;
      return result;
    }
    return result;
  }

  factory DataWhile.fromJson(Map<String, dynamic> json) =>
      _$DataWhileFromJson(json);
  @override
  Map<String, dynamic> toJson() => _$DataWhileToJson(this);
}

@JsonSerializable()
class DataForeach extends DataValidator {
  late String? iterator;
  late dynamic setKey;
  late dynamic setValue;

  @JsonKey(name: 'on-do')
  late List<dynamic>? on_do;

  DataForeach();

  @override
  PipelineValidateResult validate() {
    var result = PipelineValidateResult();

    if (iterator == null || iterator!.trim().isEmpty) {
      result.message = 'foreach: iterator must be a non-empty string.';
      result.enable = false;
      return result;
    }

    if (setValue == null) {
      result.message = 'Syntax requires a settable element name.';
      result.enable = false;
      return result;
    }

    if (on_do == null) {
      result.message = 'foreach syntax requires on-do.';
      result.enable = false;
      return result;
    }
    return result;
  }

  factory DataForeach.fromJson(Map<String, dynamic> json) =>
      _$DataForeachFromJson(json);
  Map<String, dynamic> toJson() => _$DataForeachToJson(this);
}

@JsonSerializable()
class DataSwitch extends DataCondition {
  late List<DataSwitchValue> cases = [];

  DataSwitch();

  @override
  PipelineValidateResult validate() {
    var result = super.validate();
    if (!result.enable) {
      return result;
    }

    for (var item in cases) {
      result = item.validate();
      if (!result.enable) {
        return result;
      }
    }

    return result;
  }

  factory DataSwitch.fromJson(Map<String, dynamic> json) =>
      _$DataSwitchFromJson(json);
  @override
  Map<String, dynamic> toJson() => _$DataSwitchToJson(this);
}

@JsonSerializable()
class DataSwitchValue implements DataValidator {
  dynamic value;
  late List<dynamic> tasks = [];

  DataSwitchValue();

  @override
  PipelineValidateResult validate() {
    return PipelineValidateResult();
  }

  factory DataSwitchValue.fromJson(Map<String, dynamic> json) =>
      _$DataSwitchValueFromJson(json);
  Map<String, dynamic> toJson() => _$DataSwitchValueToJson(this);
}
