import 'dart:async';
import 'dart:convert';
import 'package:geolocator/geolocator.dart';
import 'package:votianlt_app/services/developer.dart' as developer;
import 'websocket_service.dart';

/// Service for tracking and sending GPS location.
/// Sends position every 30 seconds when online.
/// Does not buffer location data when offline.
class LocationService {
  static final LocationService _instance = LocationService._internal();

  factory LocationService() => _instance;

  LocationService._internal();

  Timer? _locationTimer;
  bool _isTracking = false;
  Position? _lastPosition;

  static const String _topic = '/server/location';
  static const int _sendIntervalSeconds = 30;

  /// Check if location services are enabled and permission is granted
  Future<bool> _checkPermissions() async {
    // Check if location services are enabled
    bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) {
      developer.log(
        'Location services are disabled',
        name: 'LocationService',
      );
      return false;
    }

    // Check location permission
    LocationPermission permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        developer.log(
          'Location permission denied',
          name: 'LocationService',
        );
        return false;
      }
    }

    if (permission == LocationPermission.deniedForever) {
      developer.log(
        'Location permission permanently denied',
        name: 'LocationService',
      );
      return false;
    }

    return true;
  }

  /// Start location tracking and periodic sending
  Future<void> startTracking() async {
    if (_isTracking) {
      developer.log(
        'Location tracking already active',
        name: 'LocationService',
      );
      return;
    }

    final hasPermission = await _checkPermissions();
    if (!hasPermission) {
      developer.log(
        'Cannot start location tracking - permission not granted',
        name: 'LocationService',
      );
      return;
    }

    _isTracking = true;
    developer.log(
      'Starting location tracking (sending every $_sendIntervalSeconds seconds)',
      name: 'LocationService',
    );

    // Get initial position
    await _updateAndSendPosition();

    // Start periodic timer
    _locationTimer = Timer.periodic(
      const Duration(seconds: _sendIntervalSeconds),
      (_) => _updateAndSendPosition(),
    );
  }

  /// Stop location tracking
  void stopTracking() {
    if (!_isTracking) return;

    developer.log(
      'Stopping location tracking',
      name: 'LocationService',
    );

    _locationTimer?.cancel();
    _locationTimer = null;
    _isTracking = false;
  }

  /// Get current position and send to server if online
  Future<void> _updateAndSendPosition() async {
    try {
      final position = await Geolocator.getCurrentPosition(
        locationSettings: const LocationSettings(
          accuracy: LocationAccuracy.best,
        ),
      );

      _lastPosition = position;

      developer.log(
        'Position updated: ${position.latitude}, ${position.longitude}',
        name: 'LocationService',
      );

      await _sendPosition(position);
    } catch (e, st) {
      developer.log(
        'Error getting position: $e',
        name: 'LocationService',
      );
      developer.log('Stack: $st', name: 'LocationService');
    }
  }

  /// Send position to server if online
  /// Does NOT buffer when offline - location data is time-sensitive
  Future<void> _sendPosition(Position position) async {
    final wsService = WebSocketService();

    // Only send if connected and authenticated
    if (!wsService.isConnected || !wsService.isAuthenticated) {
      developer.log(
        'Not sending position - not connected/authenticated',
        name: 'LocationService',
      );
      return;
    }

    final payload = {
      'latitude': position.latitude,
      'longitude': position.longitude,
      'accuracy': position.accuracy,
      'altitude': position.altitude,
      'speed': position.speed,
      'heading': position.heading,
      'timestamp': position.timestamp.toIso8601String(),
    };

    try {
      const topic = _topic;
      final jsonPayload = jsonEncode(payload);

      // Use direct WebSocket send to avoid buffering
      wsService.sendMessage(topic, jsonPayload);

      developer.log(
        'Position sent to server: ${position.latitude}, ${position.longitude}',
        name: 'LocationService',
      );
    } catch (e, st) {
      developer.log(
        'Error sending position: $e',
        name: 'LocationService',
      );
      developer.log('Stack: $st', name: 'LocationService');
    }
  }

  /// Get the last known position
  Position? get lastPosition => _lastPosition;

  /// Check if tracking is active
  bool get isTracking => _isTracking;
}
