import 'package:syncrow_web/pages/device_managment/flush_mounted_presence_sensor/models/flush_mounted_presence_sensor_model.dart';
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
import 'package:syncrow_web/pages/routines/models/flush/flush_operational_value.dart';
import 'package:syncrow_web/utils/constants/assets.dart';

abstract class FlushFunctions
    extends DeviceFunction<FlushMountedPresenceSensorModel> {
  final String type;

  FlushFunctions({
    required super.deviceId,
    required super.deviceName,
    required super.code,
    required super.operationName,
    required super.icon,
    required this.type,
  });

  List<FlushOperationalValue> getOperationalValues();
}

class FlushPresenceDelayFunction extends FlushFunctions {
  FlushPresenceDelayFunction({
    required super.deviceId,
    required super.deviceName,
    required super.type,
  })  :
        super(
          code: FlushMountedPresenceSensorModel.codePresenceState,
          operationName: 'Presence State',
          icon: Assets.presenceStateIcon,
        );

  @override
  List<FlushOperationalValue> getOperationalValues() {
    return [
      FlushOperationalValue(
        icon: Assets.nobodyTime,
        description: 'None',
        value: "none",
      ),
      FlushOperationalValue(
        icon: Assets.presenceStateIcon,
        description: 'Presence',
        value: 'presence',
      ),
    ];
  }
}

class FlushSensiReduceFunction extends FlushFunctions {
  final double min;
  final double max;
  final double step;

  FlushSensiReduceFunction({
    required super.deviceId,
    required super.deviceName,
    required super.type,
  })  : min = 1,
        max = 5,
        step = 1,
        super(
          code: FlushMountedPresenceSensorModel.codeSensiReduce,
          operationName: 'Sensitivity Reduction',
          icon: Assets.motionlessDetectionSensitivityIcon,
        );

  @override
  List<FlushOperationalValue> getOperationalValues() {
    return List.generate(
        (max - min) ~/ step + 1,
        (index) => FlushOperationalValue(
              icon: Assets.currentDistanceIcon,
              description: '${min + (index * step)}',
              value: min + (index * step),
            ));
  }
}

class FlushNoneDelayFunction extends FlushFunctions {
  final double min;
  final double max;
  final String unit;

  FlushNoneDelayFunction({
    required super.deviceId,
    required super.deviceName,
    required super.type,
  })  : min = 10,
        max = 10000,
        unit = '秒',
        super(
          code: FlushMountedPresenceSensorModel.codeNoneDelay,
          operationName: 'None Delay',
          icon: Assets.nobodyTime,
        );

  @override
  List<FlushOperationalValue> getOperationalValues() {
    return [
      FlushOperationalValue(
        icon: icon,
        description: 'Custom $unit',
        value: null,
      )
    ];
  }
}

class FlushIlluminanceFunction extends FlushFunctions {
  final double min;
  final double max;
  final double step;

  FlushIlluminanceFunction({
    required super.deviceId,
    required super.deviceName,
    required super.type,
  })  : min = 0,
        max = 2000,
        step = 0,
        super(
          code: FlushMountedPresenceSensorModel.codeIlluminance,
          operationName: 'Illuminance',
          icon: Assets.IlluminanceIcon,
        );

  @override
  List<FlushOperationalValue> getOperationalValues() {
    List<FlushOperationalValue> values = [];
    for (int lux = min.toInt(); lux <= max; lux += step.toInt()) {
      values.add(FlushOperationalValue(
        icon: Assets.IlluminanceIcon,
        description: "$lux Lux",
        value: lux,
      ));
    }
    return values;
  }
}

class FlushOccurDistReduceFunction extends FlushFunctions {
  final double min;
  final double max;
  final double step;

  FlushOccurDistReduceFunction({
    required super.deviceId,
    required super.deviceName,
    required super.type,
  })  : min = 0,
        max = 100,
        step = 1,
        super(
          code: FlushMountedPresenceSensorModel.codeOccurDistReduce,
          operationName: 'Occurrence Distance Reduction',
          icon: Assets.assetsTempreture,
        );

  @override
  List<FlushOperationalValue> getOperationalValues() {
    return List.generate(
        (max - min) ~/ step + 1,
        (index) => FlushOperationalValue(
              icon: Assets.assetsTempreture,
              description: '${min + (index * step)}',
              value: min + (index * step),
            ));
  }
}

// ==== then functions ====
class FlushSensitivityFunction extends FlushFunctions {
  final double min;
  final double max;
  final double step;

  FlushSensitivityFunction({
    required super.deviceId,
    required super.deviceName,
    required super.type,
  })  : min = 1,
        max = 9,
        step = 1,
        super(
          code: FlushMountedPresenceSensorModel.codeSensitivity,
          operationName: 'Sensitivity',
          icon: Assets.sensitivity,
        );

  @override
  List<FlushOperationalValue> getOperationalValues() {
    return List.generate(
        (max - min) ~/ step + 1,
        (index) => FlushOperationalValue(
              icon: Assets.motionDetectionSensitivityValueIcon,
              description: '${min + (index * step)}',
              value: min + (index * step),
            ));
  }
}

class FlushNearDetectionFunction extends FlushFunctions {
  final double min;
  final double max;
  final double step;
  final String unit;

  FlushNearDetectionFunction({
    required super.deviceId,
    required super.deviceName,
    required super.type,
  })  : min = 0,
        max = 9.5,
        step = 1,
        unit = 'm',
        super(
          code: FlushMountedPresenceSensorModel.codeNearDetection,
          operationName: 'Nearest Detect Dist',
          icon: Assets.currentDistanceIcon,
        );

  @override
  List<FlushOperationalValue> getOperationalValues() {
    final values = <FlushOperationalValue>[];
    for (var value = min.toDouble(); value <= max; value += step) {
      values.add(FlushOperationalValue(
        icon: Assets.nobodyTime,
        description: '$value $unit',
        value: value * 10,
      ));
    }
    return values;
  }
}

class FlushMaxDetectDistFunction extends FlushFunctions {
  final double min;
  final double max;
  final double step;
  final String unit;

  FlushMaxDetectDistFunction({
    required super.deviceId,
    required super.deviceName,
    required super.type,
  })  : min = 75,
        max = 600,
        step = 75,
        unit = 'cm',
        super(
          code: FlushMountedPresenceSensorModel.codeFarDetection,
          operationName: 'Max Detect Dist',
          icon: Assets.currentDistanceIcon,
        );

  @override
  List<FlushOperationalValue> getOperationalValues() {
    final values = <FlushOperationalValue>[];
    for (var value = min; value <= max; value += step.toInt()) {
      values.add(FlushOperationalValue(
        icon: Assets.nobodyTime,
        description: '$value $unit',
        value: value,
      ));
    }
    return values;
  }
}

class FlushTargetConfirmTimeFunction extends FlushFunctions {
  final double min;
  final double max;
  final double step;
  final String unit;

  FlushTargetConfirmTimeFunction({
    required super.deviceId,
    required super.deviceName,
    required super.type,
  })  : min = 75,
        max = 600,
        step = 75,
        unit = 'cm',
        super(
          code: FlushMountedPresenceSensorModel.codePresenceDelay,
          operationName: 'Target Confirm Time',
          icon: Assets.targetConfirmTimeIcon,
        );

  @override
  List<FlushOperationalValue> getOperationalValues() {
    final values = <FlushOperationalValue>[];
    for (var value = min.toDouble(); value <= max; value += step) {
      values.add(FlushOperationalValue(
        icon: Assets.nobodyTime,
        description: '$value $unit',
        value: value,
      ));
    }
    return values;
  }
}

class FlushDisappeDelayFunction extends FlushFunctions {
  final double min;
  final double max;
  final double step;
  final String unit;

  FlushDisappeDelayFunction({
    required super.deviceId,
    required super.deviceName,
    required super.type,
  })  : min = 75,
        max = 600,
        step = 75,
        unit = 'cm',
        super(
          code: FlushMountedPresenceSensorModel.codeNoneDelay,
          operationName: 'Disappe Delay',
          icon: Assets.DisappeDelayIcon,
        );

  @override
  List<FlushOperationalValue> getOperationalValues() {
    final values = <FlushOperationalValue>[];
    for (var value = min.toDouble(); value <= max; value += step) {
      values.add(FlushOperationalValue(
        icon: Assets.nobodyTime,
        description: '$value $unit',
        value: value,
      ));
    }
    return values;
  }
}

class FlushIndentLevelFunction extends FlushFunctions {
  final double min;
  final double max;
  final double step;
  final String unit;

  FlushIndentLevelFunction({
    required super.deviceId,
    required super.deviceName,
    required super.type,
  })  : min = 75,
        max = 600,
        step = 75,
        unit = 'cm',
        super(
          code: FlushMountedPresenceSensorModel.codeOccurDistReduce,
          operationName: 'Indent Level',
          icon: Assets.indentLevelIcon,
        );

  @override
  List<FlushOperationalValue> getOperationalValues() {
    final values = <FlushOperationalValue>[];
    for (var value = min.toDouble(); value <= max; value += step) {
      values.add(FlushOperationalValue(
        icon: Assets.nobodyTime,
        description: '$value $unit',
        value: value,
      ));
    }
    return values;
  }
}

class FlushTriggerLevelFunction extends FlushFunctions {
  final double min;
  final double max;
  final double step;
  final String unit;

  FlushTriggerLevelFunction({
    required super.deviceId,
    required super.deviceName,
    required super.type,
  })  : min = 75,
        max = 600,
        step = 75,
        unit = 'cm',
        super(
          code: FlushMountedPresenceSensorModel.codeSensiReduce,
          operationName: 'Trigger Level',
          icon: Assets.triggerLevelIcon,
        );

  @override
  List<FlushOperationalValue> getOperationalValues() {
    final values = <FlushOperationalValue>[];
    for (var value = min.toDouble(); value <= max; value += step) {
      values.add(FlushOperationalValue(
        icon: Assets.nobodyTime,
        description: '$value $unit',
        value: value,
      ));
    }
    return values;
  }
}
