import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

/// Service to track and manage user online presence
class UserPresenceService {
  static const String _presenceTableName = 'user_presence';
  static const int _presenceTimeout = 60; // seconds

  final _supabase = Supabase.instance.client;
  Timer? _heartbeatTimer;
  String? _userId;
  bool _isInitialized = false;

  final StreamController<int> _onlineUsersController =
      StreamController<int>.broadcast();

  /// Stream of currently online users count
  Stream<int> get onlineUsersStream => _onlineUsersController.stream;

  /// Current count of online users
  int _onlineUsersCount = 0;
  int get onlineUsersCount => _onlineUsersCount;

  /// Initialize the presence service
  Future<void> initialize() async {
    if (_isInitialized) return;

    try {
      final currentUser = _supabase.auth.currentUser;
      if (currentUser == null) {
        debugPrint('UserPresence: No authenticated user');
        return;
      }

      _userId = currentUser.id;

      // Start heartbeat timer
      _startHeartbeat();

      // Initial presence update
      await updatePresence();

      // Get initial online users count
      await _fetchOnlineUsersCount();

      _isInitialized = true;
      debugPrint('UserPresence: Service initialized for user $_userId');
    } catch (e) {
      debugPrint('UserPresence: Error initializing - $e');
    }
  }

  /// Start heartbeat timer to keep presence alive
  void _startHeartbeat() {
    _heartbeatTimer?.cancel();

    // Update presence every 30 seconds
    _heartbeatTimer = Timer.periodic(const Duration(seconds: 30), (timer) {
      updatePresence();
      _fetchOnlineUsersCount();
    });
  }

  /// Update user presence
  Future<void> updatePresence() async {
    if (_userId == null) return;

    try {
      final currentUser = _supabase.auth.currentUser;
      if (currentUser == null) return;

      final now = DateTime.now().toIso8601String();

      // Update the database record
      await _supabase.from(_presenceTableName).upsert({
        'id': _userId!,
        'user_id': _userId!,
        'email': currentUser.email ?? '',
        'last_seen_at': now,
        'is_online': true,
      });

      debugPrint('UserPresence: Updated presence for user $_userId');
    } catch (e) {
      debugPrint('UserPresence: Error updating presence - $e');
    }
  }

  /// Fetch the count of online users
  Future<void> _fetchOnlineUsersCount() async {
    try {
      final now = DateTime.now();
      final cutoffTime = now.subtract(Duration(seconds: _presenceTimeout));

      // First, get all online users
      final response = await _supabase
          .from(_presenceTableName)
          .select()
          .gt('last_seen_at', cutoffTime.toIso8601String())
          .eq('is_online', true);

      // Calculate count from the response
      final List<dynamic> users = response;
      final count = users.length;

      if (_onlineUsersCount != count) {
        _onlineUsersCount = count;
        _onlineUsersController.add(count);
        debugPrint(
          'UserPresence: Online users count updated: $_onlineUsersCount',
        );
      }
    } catch (e) {
      debugPrint('UserPresence: Error fetching online users count - $e');
    }
  }

  /// Get all currently online users
  Future<List<Map<String, dynamic>>> getOnlineUsers() async {
    try {
      final now = DateTime.now();
      final cutoffTime = now.subtract(Duration(seconds: _presenceTimeout));

      final response = await _supabase
          .from(_presenceTableName)
          .select('id, user_id, email, last_seen_at')
          .gt('last_seen_at', cutoffTime.toIso8601String())
          .eq('is_online', true);

      return List<Map<String, dynamic>>.from(response);
    } catch (e) {
      debugPrint('UserPresence: Error getting online users - $e');
      return [];
    }
  }

  /// Clean up resources
  void dispose() {
    _heartbeatTimer?.cancel();
    _onlineUsersController.close();
    _isInitialized = false;

    // Set user as offline in the database
    if (_userId != null) {
      try {
        _supabase
            .from(_presenceTableName)
            .update({'is_online': false})
            .eq('id', _userId!)
            .then((_) {
              debugPrint('UserPresence: User set to offline');
            });
      } catch (e) {
        debugPrint('UserPresence: Error setting user offline - $e');
      }
    }

    debugPrint('UserPresence: Service disposed');
  }
}
