import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routines/models/ceiling_presence_sensor_functions.dart';
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_sensor/ceiling_sensor_helper.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_sensor/cps_dialog_slider_selector.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_sensor/cps_dialog_value_selector.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_sensor/cps_functions_list.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ceiling_sensor/cps_slider_helpers.dart';

class CeilingSensorDialog extends StatefulWidget {
  const CeilingSensorDialog({
    required this.uniqueCustomId,
    required this.functions,
    required this.deviceSelectedFunctions,
    required this.device,
    required this.dialogType,
    super.key,
  });

  final String? uniqueCustomId;
  final List<DeviceFunction> functions;
  final List<DeviceFunctionData> deviceSelectedFunctions;
  final AllDevicesModel? device;
  final String dialogType;

  @override
  State<CeilingSensorDialog> createState() => _CeilingSensorDialogState();
}

class _CeilingSensorDialogState extends State<CeilingSensorDialog> {
  late final List<CpsFunctions> _cpsFunctions;
  late final String _dialogHeaderText;

  @override
  void initState() {
    super.initState();

    _cpsFunctions =
        widget.functions.whereType<CpsFunctions>().where((function) {
      if (widget.dialogType == 'THEN') {
        return function.type == 'THEN' || function.type == 'BOTH';
      }
      return function.type == 'IF' || function.type == 'BOTH';
    }).toList();

    final isIfDialog = widget.dialogType == 'IF';
    _dialogHeaderText = isIfDialog ? 'Conditions' : 'Functions';
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      contentPadding: EdgeInsets.zero,
      content: BlocBuilder<FunctionBloc, FunctionBlocState>(
        builder: (context, state) {
          final selectedFunction = state.selectedFunction;

          return Container(
            width: selectedFunction != null ? 600 : 360,
            height: 450,
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(20),
            ),
            padding: const EdgeInsets.only(top: 20),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                DialogHeader('Presence Sensor $_dialogHeaderText'),
                Expanded(child: _buildMainContent(context, state)),
                DialogFooter(
                  onCancel: () => Navigator.pop(context),
                  onConfirm: state.addedFunctions.isNotEmpty
                      ? () {
                          final selectedFunctionData =
                              state.addedFunctions.firstWhere(
                            (f) => f.functionCode == state.selectedFunction,
                            orElse: () => DeviceFunctionData(
                              entityId: '',
                              functionCode: state.selectedFunction ?? '',
                              operationName: '',
                              value: null,
                            ),
                          );
                          final functions = _updateValuesForAddedFunctions(
                            state.addedFunctions,
                          );
                          context.read<RoutineBloc>().add(
                                AddFunctionToRoutine(
                                  [selectedFunctionData],
                                  '${widget.uniqueCustomId}',
                                ),
                              );

                          Navigator.pop(context, {
                            'deviceId': widget.functions.first.deviceId,
                          });
                        }
                      : null,
                  isConfirmEnabled: selectedFunction != null,
                ),
              ],
            ),
          );
        },
      ),
    );
  }

  Widget _buildMainContent(BuildContext context, FunctionBlocState state) {
    final selectedFunction = state.selectedFunction;
    final selectedOperationName = state.selectedOperationName;
    final selectedFunctionData = state.addedFunctions.firstWhere(
      (f) => f.functionCode == selectedFunction,
      orElse: () => DeviceFunctionData(
        entityId: '',
        functionCode: selectedFunction ?? '',
        operationName: '',
        value: null,
      ),
    );
    final selectedCpsFunctions = _cpsFunctions.firstWhere(
      (f) => f.code == selectedFunction,
      orElse: () => CpsMovementFunctions(
        deviceId: '',
        deviceName: '',
        type: '',
      ),
    );
    final operations = selectedCpsFunctions.getOperationalValues();
    final isSensitivityFunction = selectedFunction == 'sensitivity';
    final isToggleFunction = isSensitivityFunction
        ? widget.dialogType == 'THEN'
        : CeilingSensorHelper.toggleCodes.contains(selectedFunction);

    return Row(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        CpsFunctionsList(
          cpsFunctions: _cpsFunctions,
          device: widget.device,
          selectedFunctionData: selectedFunctionData,
          dialogType: widget.dialogType,
        ),
        if (state.selectedFunction != null)
          Expanded(
            child: isToggleFunction
                ? CpsDialogValueSelector(
                    operations: operations,
                    selectedFunction: selectedFunction ?? '',
                    selectedFunctionData: selectedFunctionData,
                    cpsFunctions: _cpsFunctions,
                    operationName: selectedOperationName ?? '',
                    device: widget.device,
                  )
                : CpsDialogSliderSelector(
                    step: selectedCpsFunctions.step!,
                    operations: operations,
                    selectedFunction: selectedFunction ?? '',
                    selectedFunctionData: selectedFunctionData,
                    cpsFunctions: _cpsFunctions,
                    operationName: selectedOperationName ?? '',
                    device: widget.device,
                    dialogType: widget.dialogType,
                  ),
          ),
      ],
    );
  }

  static const _mappableSteppedFunctions = <String>{
    'static_max_dis',
    'presence_reference',
    'moving_reference',
    'perceptual_boundary',
    'moving_boundary',
    'moving_rigger_time',
    'moving_static_time',
    'none_body_time',
    'moving_max_dis',
    'moving_range',
    'presence_range',
  };

  List<DeviceFunctionData> _updateValuesForAddedFunctions(
    List<DeviceFunctionData> addedFunctions,
  ) {
    return addedFunctions.map((function) {
      final shouldMapValue = _mappableSteppedFunctions.contains(
        function.functionCode,
      );
      if (shouldMapValue) {
        final mappedValue = _mapSteppedValue(
          value: function.value,
          inputStep: CpsSliderHelpers.dividendOfRange(function.functionCode),
          inputRange: CpsSliderHelpers.sliderRange(function.functionCode),
          outputRange: CpsSliderHelpers.mappedRange(function.functionCode),
        );
        return DeviceFunctionData(
          value: mappedValue,
          entityId: function.entityId,
          functionCode: function.functionCode,
          operationName: function.operationName,
          condition: function.condition,
          actionExecutor: function.actionExecutor,
          valueDescription: function.valueDescription,
        );
      }
      return function;
    }).toList();
  }

  int _mapSteppedValue({
    required (double min, double max) inputRange,
    required double inputStep,
    required (double min, double max, double dividend) outputRange,
    required double value,
  }) {
    final (inputMin, inputMax) = inputRange;
    final (outputMin, outputMax, outputStep) = outputRange;

    final clampedValue = value.clamp(inputMin, inputMax);

    final stepsFromMin = ((clampedValue - inputMin) / inputStep).round();

    final mappedValue = outputMin + (stepsFromMin * outputStep);

    return mappedValue.clamp(outputMin, outputMax).round();
  }
}
