import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_automation_model.dart'; import 'package:syncrow_web/pages/routiens/models/create_scene_and_autoamtion/create_scene_model.dart'; import 'package:syncrow_web/pages/routiens/models/device_functions.dart'; import 'package:syncrow_web/pages/routiens/models/routine_model.dart'; import 'package:syncrow_web/services/routines_api.dart'; part 'routine_event.dart'; part 'routine_state.dart'; const spaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6'; class RoutineBloc extends Bloc { // bool isAutomation = false; // bool isTabToRun = false; RoutineBloc() : super(const RoutineState()) { on(_onAddToIfContainer); on(_onAddToThenContainer); on(_onLoadScenes); on(_onLoadAutomation); on(_onAddFunctionsToRoutine); on(_onSearchRoutines); on(_onAddSelectedIcon); on(_onCreateScene); on(_onRemoveDragCard); on(_changeOperatorOperator); on(_onEffectiveTimeEvent); on(_onCreateAutomation); // on(_onRemoveFunction); // on(_onClearFunctions); } void _onAddToIfContainer(AddToIfContainer event, Emitter emit) { final updatedIfItems = List>.from(state.ifItems) ..add(event.item); if (event.isTabToRun) { emit(state.copyWith( ifItems: updatedIfItems, isTabToRun: true, isAutomation: false)); } else { emit(state.copyWith( ifItems: updatedIfItems, isTabToRun: false, isAutomation: true)); } } void _onAddToThenContainer( AddToThenContainer event, Emitter emit) { final currentItems = List>.from(state.thenItems); // Find the index of the item in teh current itemsList int index = currentItems.indexWhere( (map) => map['uniqueCustomId'] == event.item['uniqueCustomId']); // Replace the map if the index is valid if (index != -1) { currentItems[index] = event.item; } else { currentItems.add(event.item); } emit(state.copyWith(thenItems: currentItems)); } void _onAddFunctionsToRoutine( AddFunctionToRoutine event, Emitter emit) { try { if (event.functions.isEmpty) return; final currentSelectedFunctions = Map>.from(state.selectedFunctions); if (currentSelectedFunctions.containsKey(event.uniqueCustomId)) { currentSelectedFunctions[event.uniqueCustomId] = List.from(currentSelectedFunctions[event.uniqueCustomId]!) ..addAll(event.functions); } else { currentSelectedFunctions[event.uniqueCustomId] = List.from(event.functions); } emit(state.copyWith(selectedFunctions: currentSelectedFunctions)); } catch (e) { debugPrint('Error adding functions: $e'); } } Future _onLoadScenes( LoadScenes event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); try { final scenes = await SceneApi.getScenesByUnitId(event.unitId); emit(state.copyWith( scenes: scenes, isLoading: false, )); } catch (e) { emit(state.copyWith( isLoading: false, loadScenesErrorMessage: 'Failed to load scenes', errorMessage: '', loadAutomationErrorMessage: '', )); } } Future _onLoadAutomation( LoadAutomation event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); try { final automations = await SceneApi.getAutomationByUnitId(event.unitId); emit(state.copyWith( automations: automations, isLoading: false, )); } catch (e) { emit(state.copyWith( isLoading: false, loadAutomationErrorMessage: 'Failed to load automations', errorMessage: '', loadScenesErrorMessage: '', )); } } FutureOr _onSearchRoutines( SearchRoutines event, Emitter emit) async { emit(state.copyWith(isLoading: true, errorMessage: null)); await Future.delayed(const Duration(seconds: 1)); emit(state.copyWith(searchText: event.query)); } FutureOr _onAddSelectedIcon( AddSelectedIcon event, Emitter emit) { emit(state.copyWith(selectedIcon: event.icon)); } bool _isFirstActionDelay(List> actions) { if (actions.isEmpty) return false; return actions.first['deviceId'] == 'delay'; } Future _onCreateScene( CreateSceneEvent event, Emitter emit) async { try { // Check if first action is delay if (_isFirstActionDelay(state.thenItems)) { emit(state.copyWith( errorMessage: 'Cannot have delay as the first action', isLoading: false, )); return; } emit(state.copyWith(isLoading: true)); final actions = state.thenItems .map((item) { final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; if (functions.isEmpty) return null; final function = functions.first; if (item['deviceId'] == 'delay') { return CreateSceneAction( entityId: function.entityId, actionExecutor: 'delay', executorProperty: CreateSceneExecutorProperty( functionCode: '', functionValue: '', delaySeconds: function.value, ), ); } return CreateSceneAction( entityId: function.entityId, actionExecutor: 'device_issue', executorProperty: CreateSceneExecutorProperty( functionCode: function.functionCode.toString(), functionValue: function.value, delaySeconds: 0, ), ); }) .whereType() .toList(); final createSceneModel = CreateSceneModel( spaceUuid: spaceId, iconId: state.selectedIcon ?? '', showInDevice: true, sceneName: state.routineName ?? '', decisionExpr: 'and', actions: actions, ); final result = await SceneApi.createScene(createSceneModel); if (result['success']) { emit(const RoutineState()); } else { emit(state.copyWith( isLoading: false, errorMessage: result['message'], )); } } catch (e) { emit(state.copyWith( isLoading: false, errorMessage: e.toString(), )); } } Future _onCreateAutomation( CreateAutomationEvent event, Emitter emit) async { try { if (state.routineName == null || state.routineName!.isEmpty) { emit(state.copyWith( errorMessage: 'Automation name is required', )); return; } emit(state.copyWith(isLoading: true)); final conditions = state.ifItems .map((item) { final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; if (functions.isEmpty) return null; final function = functions.first; return CreateCondition( code: state.ifItems.indexOf(item) + 1, entityId: function.entityId, entityType: 'device_report', expr: ConditionExpr( statusCode: function.functionCode, comparator: function.condition ?? '==', statusValue: function.value, ), ); }) .whereType() .toList(); if (conditions.isEmpty) { emit(state.copyWith( isLoading: false, errorMessage: 'At least one condition is required', )); return; } final createAutomationModel = CreateAutomationModel( unitUuid: spaceId, automationName: state.routineName!, decisionExpr: state.selectedAutomationOperator, effectiveTime: state.effectiveTime ?? EffectiveTime( start: '00:00', end: '23:59', loops: '1111111', ), conditions: conditions, actions: state.thenItems .map((item) { final functions = state.selectedFunctions[item['uniqueCustomId']] ?? []; if (functions.isEmpty) return null; final function = functions.first; if (function.functionCode == 'automation') { return CreateSceneAction( entityId: function.entityId, actionExecutor: function.value, executorProperty: null, ); } if (item['deviceId'] == 'delay') { return CreateSceneAction( entityId: function.entityId, actionExecutor: 'delay', executorProperty: CreateSceneExecutorProperty( functionCode: '', functionValue: '', delaySeconds: function.value, ), ); } return CreateSceneAction( entityId: function.entityId, actionExecutor: 'device_issue', executorProperty: CreateSceneExecutorProperty( functionCode: function.functionCode, functionValue: function.value, delaySeconds: 0, ), ); }) .whereType() .toList(), ); final result = await SceneApi.createAutomation(createAutomationModel); if (result['success']) { emit(const RoutineState()); } else { emit(state.copyWith( isLoading: false, errorMessage: result['message'], )); } } catch (e) { emit(state.copyWith( isLoading: false, errorMessage: e.toString(), )); } } FutureOr _onRemoveDragCard( RemoveDragCard event, Emitter emit) { if (event.isFromThen) { final thenItems = List>.from(state.thenItems); thenItems.removeAt(event.index); emit(state.copyWith(thenItems: thenItems)); } else { final ifItems = List>.from(state.ifItems); ifItems.removeAt(event.index); emit(state.copyWith(ifItems: ifItems)); } } FutureOr _changeOperatorOperator( ChangeAutomationOperator event, Emitter emit) { emit(state.copyWith( selectedAutomationOperator: event.operator, )); } FutureOr _onEffectiveTimeEvent( EffectiveTimePeriodEvent event, Emitter emit) { emit(state.copyWith(effectiveTime: event.effectiveTime)); } }