import 'dart:convert';

class CreateAutomationModel {
  String spaceUuid;
  String automationName;
  String decisionExpr;
  EffectiveTime effectiveTime;
  List<Condition> conditions;
  List<AutomationAction> actions;

  CreateAutomationModel({
    required this.spaceUuid,
    required this.automationName,
    required this.decisionExpr,
    required this.effectiveTime,
    required this.conditions,
    required this.actions,
  });

  Map<String, dynamic> toMap([String? automationId]) {
    return {
      'spaceUuid': spaceUuid,
      'automationName': automationName,
      'decisionExpr': decisionExpr,
      'effectiveTime': effectiveTime.toMap(),
      'conditions': conditions.map((x) => x.toMap()).toList(),
      'actions': actions.map((x) => x.toMap()).toList(),
    };
  }

  factory CreateAutomationModel.fromMap(Map<String, dynamic> map) {
    return CreateAutomationModel(
      spaceUuid: map['spaceUuid'] ?? '',
      automationName: map['automationName'] ?? '',
      decisionExpr: map['decisionExpr'] ?? '',
      effectiveTime: EffectiveTime.fromMap(map['effectiveTime']),
      conditions: List<Condition>.from(
          map['conditions']?.map((x) => Condition.fromMap(x)) ?? []),
      actions: List<AutomationAction>.from(
          map['actions']?.map((x) => AutomationAction.fromMap(x)) ?? []),
    );
  }

  String toJson(String? automationId) => json.encode(toMap(automationId));

  factory CreateAutomationModel.fromJson(String source) =>
      CreateAutomationModel.fromMap(json.decode(source));
}

class EffectiveTime {
  String start;
  String end;
  String loops;

  EffectiveTime({
    required this.start,
    required this.end,
    required this.loops,
  });

  Map<String, dynamic> toMap() {
    return {
      'start': start,
      'end': end,
      'loops': loops,
    };
  }

  factory EffectiveTime.fromMap(Map<String, dynamic> map) {
    return EffectiveTime(
      start: map['start'] ?? '',
      end: map['end'] ?? '',
      loops: map['loops'] ?? '',
    );
  }
}

class Condition {
  int code;
  String entityId;
  String entityType;
  ConditionExpr expr;

  Condition({
    required this.code,
    required this.entityId,
    required this.entityType,
    required this.expr,
  });

  Map<String, dynamic> toMap() {
    return {
      'code': code,
      'entityId': entityId,
      'entityType': 'device_report',
      'expr': expr.toMap(),
    };
  }

  factory Condition.fromMap(Map<String, dynamic> map) {
    return Condition(
      code: map['code']?.toInt() ?? 0,
      entityId: map['entityId'] ?? '',
      entityType: map['entityType'] ?? '',
      expr: ConditionExpr.fromMap(map['expr']),
    );
  }
}

class ConditionExpr {
  String statusCode;
  String comparator;
  dynamic statusValue;

  ConditionExpr({
    required this.statusCode,
    required this.comparator,
    required this.statusValue,
  });

  Map<String, dynamic> toMap() {
    return {
      'statusCode': statusCode,
      'comparator': comparator,
      'statusValue': statusValue,
    };
  }

  factory ConditionExpr.fromMap(Map<String, dynamic> map) {
    return ConditionExpr(
      statusCode: map['statusCode'] ?? '',
      comparator: map['comparator'] ?? '',
      statusValue: map['statusValue'],
    );
  }
}

class AutomationAction {
  String entityId;
  String? actionType;
  String actionExecutor;
  ExecutorProperty? executorProperty;

  AutomationAction({
    required this.entityId,
    this.actionType,
    required this.actionExecutor,
    this.executorProperty,
  });

  Map<String, dynamic> toMap() {
    return {
      'entityId': entityId,
      'actionExecutor': actionExecutor,
      if (executorProperty != null)
        'executorProperty': executorProperty?.toMap(),
      'actionType': actionType
    };
  }

  factory AutomationAction.fromMap(Map<String, dynamic> map) {
    return AutomationAction(
      actionType: map['actionType'],
      entityId: map['entityId'] ?? '',
      actionExecutor: map['actionExecutor'] ?? '',
      executorProperty: map['executorProperty'] != null
          ? ExecutorProperty.fromMap(map['executorProperty'])
          : null,
    );
  }
}

class ExecutorProperty {
  String? functionCode;
  dynamic functionValue;
  int? delaySeconds;

  ExecutorProperty({
    this.functionCode,
    this.functionValue,
    this.delaySeconds,
  });

  Map<String, dynamic> toMap() {
    return {
      if (functionCode != null) 'functionCode': functionCode,
      if (functionValue != null) 'functionValue': functionValue,
      if (delaySeconds != null) 'delaySeconds': delaySeconds,
    };
  }

  factory ExecutorProperty.fromMap(Map<String, dynamic> map) {
    return ExecutorProperty(
      functionCode: map['functionCode'],
      functionValue: map['functionValue'],
      delaySeconds: map['delaySeconds']?.toInt(),
    );
  }
}
