import 'dart:convert';

import 'package:flutter/foundation.dart';

class CreateSceneModel {
  String spaceUuid;
  String iconId;
  bool showInDevice;
  String sceneName;
  String decisionExpr;
  List<CreateSceneAction> actions;

  CreateSceneModel({
    required this.spaceUuid,
    required this.iconId,
    required this.showInDevice,
    required this.sceneName,
    required this.decisionExpr,
    required this.actions,
  });

  CreateSceneModel copyWith({
    String? spaceUuid,
    String? iconId,
    bool? showInDevice,
    String? sceneName,
    String? decisionExpr,
    List<CreateSceneAction>? actions,
    bool? showInHomePage,
  }) {
    return CreateSceneModel(
      spaceUuid: spaceUuid ?? this.spaceUuid,
      iconId: iconId ?? this.iconId,
      showInDevice: showInDevice ?? this.showInDevice,
      sceneName: sceneName ?? this.sceneName,
      decisionExpr: decisionExpr ?? this.decisionExpr,
      actions: actions ?? this.actions,
    );
  }

  Map<String, dynamic> toMap([String? sceneId]) {
    return {
      if (sceneId == null) 'spaceUuid': spaceUuid,
      if (iconId.isNotEmpty) 'iconUuid': iconId,
      'showInHomePage': showInDevice,
      'sceneName': sceneName,
      'decisionExpr': decisionExpr,
      'actions': actions.map((x) => x.toMap()).toList(),
    };
  }

  factory CreateSceneModel.fromMap(Map<String, dynamic> map) {
    return CreateSceneModel(
      spaceUuid: map['spaceUuid'] ?? '',
      showInDevice: map['showInHomePage'] ?? false,
      iconId: map['iconUuid'] ?? '',
      sceneName: map['sceneName'] ?? '',
      decisionExpr: map['decisionExpr'] ?? '',
      actions: List<CreateSceneAction>.from(
          map['actions']?.map((x) => CreateSceneAction.fromMap(x))),
    );
  }

  String toJson([String? sceneId]) => json.encode(toMap(sceneId));

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

  @override
  String toString() {
    return 'CreateSceneModel(unitUuid: $spaceUuid, sceneName: $sceneName, decisionExpr: $decisionExpr, actions: $actions)';
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;

    return other is CreateSceneModel &&
        other.spaceUuid == spaceUuid &&
        other.iconId == iconId &&
        other.showInDevice == showInDevice &&
        other.sceneName == sceneName &&
        other.decisionExpr == decisionExpr &&
        listEquals(other.actions, actions);
  }

  @override
  int get hashCode {
    return spaceUuid.hashCode ^
        sceneName.hashCode ^
        decisionExpr.hashCode ^
        actions.hashCode;
  }
}

class CreateSceneAction {
  final String? productType;

  String entityId;
  String? actionType;
  String actionExecutor;
  CreateSceneExecutorProperty? executorProperty;

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

  CreateSceneAction copyWith({
    String? productType,
    String? actionType,
    String? entityId,
    String? actionExecutor,
    CreateSceneExecutorProperty? executorProperty,
  }) {
    return CreateSceneAction(
      productType: productType,
      actionType: actionType,
      entityId: entityId ?? this.entityId,
      actionExecutor: actionExecutor ?? this.actionExecutor,
      executorProperty: executorProperty ?? this.executorProperty,
    );
  }

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

  factory CreateSceneAction.fromMap(Map<String, dynamic> map) {
    return CreateSceneAction(
      productType: map['productType'] ?? '',
      entityId: map['entityId'] ?? '',
      actionExecutor: map['actionExecutor'] ?? '',
      executorProperty:
          CreateSceneExecutorProperty.fromMap(map['executorProperty']),
    );
  }

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

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

  @override
  String toString() =>
      'CreateSceneAction(entityId: $entityId, actionExecutor: $actionExecutor, executorProperty: $executorProperty)';

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;

    return other is CreateSceneAction &&
        other.entityId == entityId &&
        other.actionExecutor == actionExecutor &&
        other.executorProperty == executorProperty;
  }

  @override
  int get hashCode =>
      entityId.hashCode ^ actionExecutor.hashCode ^ executorProperty.hashCode;
}

class CreateSceneExecutorProperty {
  String functionCode;
  dynamic functionValue;
  int delaySeconds;

  CreateSceneExecutorProperty({
    required this.functionCode,
    required this.functionValue,
    required this.delaySeconds,
  });

  CreateSceneExecutorProperty copyWith({
    String? functionCode,
    dynamic functionValue,
    int? delaySeconds,
  }) {
    return CreateSceneExecutorProperty(
      functionCode: functionCode ?? this.functionCode,
      functionValue: functionValue ?? this.functionValue,
      delaySeconds: delaySeconds ?? this.delaySeconds,
    );
  }

  Map<String, dynamic> toMap(String actionExecutor) {
    final map = <String, dynamic>{};
    if (functionCode.isNotEmpty) map['functionCode'] = functionCode;
    if (functionValue != null) map['functionValue'] = functionValue;
    if (actionExecutor == 'delay' && delaySeconds > 0) {
      map['delaySeconds'] = delaySeconds;
    }
    return map;
  }

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

  String toJson(String actionExecutor) => json.encode(toMap(actionExecutor));

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

  @override
  String toString() =>
      'CreateSceneExecutorProperty(functionCode: $functionCode, functionValue: $functionValue, delaySeconds: $delaySeconds)';

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;

    return other is CreateSceneExecutorProperty &&
        other.functionCode == functionCode &&
        other.functionValue == functionValue &&
        other.delaySeconds == delaySeconds;
  }

  @override
  int get hashCode =>
      functionCode.hashCode ^ functionValue.hashCode ^ delaySeconds.hashCode;
}
