import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:syncrow_app/features/scene/enum/operation_dialog_type.dart';
import 'package:uuid/uuid.dart';

class SceneStaticFunction {
  final String icon;
  final String deviceName;
  final String code;
  final List<SceneOperationalValue> operationalValues;
  final String deviceId;
  final String operationName;
  final String? uniqueCustomId;
  dynamic functionValue;
  final String? deviceIcon;
  final OperationDialogType operationDialogType;
  final String? comparator;
  final String? deviceType;

  SceneStaticFunction({
    required this.icon,
    required this.deviceName,
    required this.code,
    required this.operationalValues,
    required this.deviceId,
    required this.operationName,
    required this.functionValue,
    this.deviceIcon,
    required this.operationDialogType,
    this.comparator,
    this.deviceType,
    String? uniqueCustomId,
  }) : uniqueCustomId = uniqueCustomId ?? const Uuid().v4();

  SceneStaticFunction copyWith({
    String? icon,
    String? name,
    String? code,
    List<SceneOperationalValue>? operationalValues,
    String? deviceId,
    String? operationName,
    dynamic functionValue,
    String? deviceIcon,
    String? deviceName,
    OperationDialogType? operationDialogType,
    String? comparator,
    String? uniqueCustomId,
    String? deviceType,
  }) {
    return SceneStaticFunction(
      icon: icon ?? this.icon,
      deviceName: name ?? this.deviceName,
      code: code ?? this.code,
      operationalValues: operationalValues ?? this.operationalValues,
      deviceId: deviceId ?? this.deviceId,
      operationName: operationName ?? this.operationName,
      functionValue: functionValue ?? this.functionValue,
      deviceIcon: deviceIcon ?? this.deviceIcon,
      operationDialogType: operationDialogType ?? this.operationDialogType,
      comparator: comparator ?? this.comparator,
      uniqueCustomId: uniqueCustomId ?? const Uuid().v4(),
      deviceType: deviceType ?? this.deviceType,
    );
  }

  Map<String, dynamic> toMap() {
    return {
      'icon': icon,
      'name': deviceName,
      'code': code,
      'operationalValues': operationalValues.map((x) => x.toMap()).toList(),
      'deviceId': deviceId,
      'operationName': operationName,
      'functionValue': functionValue,
      'deviceIcon': deviceIcon,
      'operationDialogType': operationDialogType.name,
      'comparator': comparator,
      'uniqueCustomId': uniqueCustomId,
      'deviceType': deviceType,
    };
  }

  factory SceneStaticFunction.fromMap(Map<String, dynamic> map) {
    return SceneStaticFunction(
      icon: map['icon'] ?? '',
      deviceName: map['name'] ?? '',
      code: map['code'] ?? '',
      operationalValues: List<SceneOperationalValue>.from(
        map['operationalValues']?.map((x) => SceneOperationalValue.fromMap(x)),
      ),
      deviceId: map['deviceId'] ?? '',
      operationName: map['operationName'] ?? '',
      functionValue: map['functionValue'] ?? '',
      deviceIcon: map['deviceIcon'] ?? '',
      operationDialogType: map['operationDialogType'] != null
          ? OperationDialogType.values.byName(map['operationDialogType'])
          : OperationDialogType.none,
      comparator: map['comparator'],
      uniqueCustomId: map['uniqueCustomId'] ?? const Uuid().v4(),
      deviceType: map['deviceType'] ?? '',
    );
  }

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

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

  @override
  String toString() {
    return 'SceneStaticFunction(icon: $icon, name: $deviceName, code: $code, operationalValues: $operationalValues, deviceId: $deviceId,  operationName: $operationName, functionValue: $functionValue, deviceIcon: $deviceIcon, operationDialogType: $operationDialogType, comparator: $comparator, uniqueCustomId: $uniqueCustomId, deviceType: $deviceType)';
  }

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

    return other is SceneStaticFunction &&
        other.icon == icon &&
        other.deviceName == deviceName &&
        other.code == code &&
        other.operationName == operationName &&
        other.functionValue == functionValue &&
        other.deviceIcon == deviceIcon &&
        other.comparator == comparator &&
        other.uniqueCustomId == uniqueCustomId &&
        other.operationDialogType == operationDialogType &&
        listEquals(other.operationalValues, operationalValues) &&
        other.deviceId == deviceId &&
        other.deviceType == deviceType;
  }

  @override
  int get hashCode {
    return icon.hashCode ^
        deviceName.hashCode ^
        code.hashCode ^
        deviceId.hashCode ^
        operationName.hashCode ^
        functionValue.hashCode ^
        deviceIcon.hashCode ^
        comparator.hashCode ^
        uniqueCustomId.hashCode ^
        operationDialogType.hashCode ^
        operationalValues.hashCode ^
        deviceType.hashCode;
  }
}

class SceneOperationalValue {
  final String icon;
  final dynamic value;
  final String? description;
  final String? iconValue;
  final double? minValue;
  final double? maxValue;
  final double? stepValue;

  SceneOperationalValue({
    required this.icon,
    required this.value,
    this.description,
    this.iconValue,
    this.minValue,
    this.maxValue,
    this.stepValue,
  });

  SceneOperationalValue copyWith({
    String? icon,
    dynamic value,
    String? description,
    String? iconValue,
    double? minValue,
    double? maxValue,
    double? stepValue,
  }) {
    return SceneOperationalValue(
      icon: icon ?? this.icon,
      value: value ?? this.value,
      description: description ?? this.description,
      iconValue: iconValue ?? this.iconValue,
      minValue: minValue ?? this.minValue,
      maxValue: maxValue ?? this.maxValue,
      stepValue: stepValue ?? this.stepValue,
    );
  }

  Map<String, dynamic> toMap() {
    return {
      'icon': icon,
      'value': value,
      'description': description,
      'iconValue': iconValue,
      'minValue': minValue,
      'maxValue': maxValue,
      'stepValue': stepValue
    };
  }

  factory SceneOperationalValue.fromMap(Map<String, dynamic> map) {
    return SceneOperationalValue(
      icon: map['icon'] ?? '',
      value: map['value'],
      description: map['description'],
      iconValue: map['iconValue'] ?? '',
      minValue: map['minValue'],
      maxValue: map['maxValue'],
      stepValue: map['stepValue'],
    );
  }

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

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

  @override
  String toString() =>
      'StaticFunctionOperationHelper(icon: $icon, value: $value, description: $description, iconValue: $iconValue, minValue: $minValue, maxValue: $maxValue, stepValue: $stepValue)';

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

    return other is SceneOperationalValue &&
        other.icon == icon &&
        other.description == description &&
        other.iconValue == iconValue &&
        other.minValue == minValue &&
        other.maxValue == maxValue &&
        other.stepValue == stepValue &&
        other.value == value;
  }

  @override
  int get hashCode =>
      icon.hashCode ^
      value.hashCode ^
      description.hashCode ^
      iconValue.hashCode ^
      minValue.hashCode ^
      maxValue.hashCode ^
      stepValue.hashCode ^
      description.hashCode;
}
