import 'dart:async';
import 'dart:math' as math;
import 'package:sensors_plus/sensors_plus.dart';

class TiltDetector {
  static final TiltDetector _instance = TiltDetector._internal();
  factory TiltDetector() => _instance;
  TiltDetector._internal();

  StreamSubscription<AccelerometerEvent>? _accelerometerSubscription;
  Function(double)? onTiltChanged;
  
  bool _isListening = false;
  double _currentTilt = 0.0;
  
  // Filtering parameters to smooth out noise
  static const double _alpha = 0.8; // Low-pass filter constant
  double _filteredX = 0.0;
  
  bool get isListening => _isListening;
  double get currentTilt => _currentTilt;

  /// Start listening to accelerometer data
  /// [onTiltChanged] callback receives tilt angle in degrees
  /// Positive values = device tilted right, negative = tilted left
  void startListening({Function(double)? onTiltChanged}) {
    if (_isListening) return;
    
    this.onTiltChanged = onTiltChanged;
    _isListening = true;
    
    _accelerometerSubscription = accelerometerEventStream(
      samplingPeriod: const Duration(milliseconds: 100), // 10 Hz sampling rate
    ).listen(_onAccelerometerEvent);
  }
  
  /// Stop listening to accelerometer data
  void stopListening() {
    if (!_isListening) return;
    
    _accelerometerSubscription?.cancel();
    _accelerometerSubscription = null;
    _isListening = false;
    onTiltChanged = null;
    _currentTilt = 0.0;
    _filteredX = 0.0;
  }
  
  void _onAccelerometerEvent(AccelerometerEvent event) {
    // Apply low-pass filter to smooth out noise
    _filteredX = _alpha * _filteredX + (1 - _alpha) * event.x;
    
    // Calculate tilt angle in degrees
    // The accelerometer X axis represents left-right tilt
    // Clamp to reasonable tilt range (-45 to +45 degrees)
    final tiltRadians = math.atan2(_filteredX, 9.8);
    _currentTilt = (tiltRadians * 180 / math.pi).clamp(-45.0, 45.0);
    
    // Only trigger callback if tilt is significant (> 5 degrees)
    if (_currentTilt.abs() > 5.0) {
      onTiltChanged?.call(_currentTilt);
    }
  }
  
  /// Get normalized tilt strength from -1.0 to 1.0
  /// -1.0 = maximum left tilt, +1.0 = maximum right tilt
  double get normalizedTilt {
    return (_currentTilt / 45.0).clamp(-1.0, 1.0);
  }
  
  /// Check if device is significantly tilted
  bool get isTilted => _currentTilt.abs() > 5.0;
  
  /// Check if device is tilted left
  bool get isTiltedLeft => _currentTilt < -5.0;
  
  /// Check if device is tilted right
  bool get isTiltedRight => _currentTilt > 5.0;
}
