import 'package:flutter/foundation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../../core/platform/health_gateway.dart'; import '../../../health_sync/presentation/controllers/biometric_controller.dart'; /// Immutable snapshot of the integrations toggles shown on the Settings /// screen. /// /// Native health toggles are gated by the platform actually backing the /// gateway (HealthKit on iOS, Health Connect on Android); the HealthGateway /// connector (cloud partner REST sync) is available everywhere and reports /// manual-entry fallback on Web/Windows/macOS. class IntegrationsState { const IntegrationsState({ this.appleHealthEnabled = false, this.healthConnectEnabled = false, this.healthGatewayEnabled = false, this.isRequestingPermissions = false, this.errorMessage, }); /// Sentinel allowing `copyWith` to explicitly reset a field to `null`. static const Object _keep = Object(); /// Apple HealthKit sync armed (iOS only). final bool appleHealthEnabled; /// Google Health Connect sync armed (Android only). final bool healthConnectEnabled; /// HealthGateway (cloud partner / manual-entry fallback) sync armed. final bool healthGatewayEnabled; /// `true` while a native permission round-trip is in flight. final bool isRequestingPermissions; /// Last permission/persistence failure, surfaced inline. final String? errorMessage; IntegrationsState copyWith({ bool? appleHealthEnabled, bool? healthConnectEnabled, bool? healthGatewayEnabled, bool? isRequestingPermissions, Object? errorMessage = _keep, }) => IntegrationsState( appleHealthEnabled: appleHealthEnabled ?? this.appleHealthEnabled, healthConnectEnabled: healthConnectEnabled ?? this.healthConnectEnabled, healthGatewayEnabled: healthGatewayEnabled ?? this.healthGatewayEnabled, isRequestingPermissions: isRequestingPermissions ?? this.isRequestingPermissions, errorMessage: identical(errorMessage, _keep) ? this.errorMessage : errorMessage as String?, ); } /// Orchestrates the integrations toggles: requests native health /// permissions through the cross-platform [IHealthGateway] before arming a /// toggle, and degrades gracefully on platforms without native support. class IntegrationsController extends Notifier { @override IntegrationsState build() { final gateway = ref.read(healthGatewayProvider); return IntegrationsState( // Toggles start disarmed; enabling requests fresh permissions. appleHealthEnabled: false, healthConnectEnabled: false, healthGatewayEnabled: false, errorMessage: gateway.supportsNativeHealth ? null : _fallbackNotice(gateway), ); } /// Human-readable capability notice for platforms without native health /// SDKs (Web / Windows / macOS fallback driver). static String? _fallbackNotice(IHealthGateway gateway) { if (gateway.supportsNativeHealth) return null; return 'Native health SDKs are unavailable on this platform — ' 'HealthGateway runs in manual-entry mode.'; } /// Arms/disarms the Apple Health toggle. Enabling requests native /// permission; denial reverts the toggle and records a message. Future setAppleHealthEnabled(bool enabled) => _setNative(enabled: enabled, isApple: true); /// Arms/disarms the Health Connect toggle (same permission contract as /// Apple Health; the gateway routes to the right SDK per platform). Future setHealthConnectEnabled(bool enabled) => _setNative(enabled: enabled, isApple: false); /// Arms/disarms the HealthGateway connector (no native permission needed). void setHealthGatewayEnabled(bool enabled) { state = state.copyWith(healthGatewayEnabled: enabled, errorMessage: null); } /// Clears the transient error banner. void clearError() { if (state.errorMessage != null) { state = state.copyWith(errorMessage: null); } } Future _setNative({required bool enabled, required bool isApple}) async { if (!enabled) { state = state.copyWith( appleHealthEnabled: isApple ? false : state.appleHealthEnabled, healthConnectEnabled: isApple ? state.healthConnectEnabled : false, errorMessage: null, ); return; } state = state.copyWith(isRequestingPermissions: true, errorMessage: null); try { final granted = await ref.read(healthGatewayProvider).requestPermissions(); if (granted) { state = state.copyWith( appleHealthEnabled: isApple ? true : state.appleHealthEnabled, healthConnectEnabled: isApple ? state.healthConnectEnabled : true, isRequestingPermissions: false, ); } else { state = state.copyWith( isRequestingPermissions: false, errorMessage: 'Health permissions were denied. Enable them in your device ' 'settings to sync biometrics.', ); } } catch (error, stackTrace) { debugPrintStack( stackTrace: stackTrace, label: 'health permission request failed', ); state = state.copyWith( isRequestingPermissions: false, errorMessage: 'Could not request health permissions: $error', ); } } } /// Exposes the [IntegrationsController] to the widget tree. final integrationsControllerProvider = NotifierProvider( IntegrationsController.new, );