import 'dart:async';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:get_it/get_it.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:tugas_akhir_supabase/services/user_presence_service.dart';

class SessionManager {
  static const String _lastActiveTimeKey = 'last_active_time';
  static const String _lastUserInteractionKey = 'last_user_interaction';
  static const String _sessionStateKey = 'session_state';
  static const int _sessionTimeoutMinutes =
      480; // Increased to 8 hours for permissive mode

  static Timer? _sessionCheckTimer;
  static Timer? _presenceUpdateTimer;
  static bool _isCheckingSession = false;
  static bool _isAppInBackground = false;
  static bool _isSessionExpired = false;
  static bool _hasLoggedInUser = false;
  static bool _isAppJustLaunched = true;
  static final StreamController<bool> _sessionExpiredController =
      StreamController<bool>.broadcast();

  // Stream untuk mendengarkan perubahan status session
  static Stream<bool> get sessionExpiredStream =>
      _sessionExpiredController.stream;

  // Getter untuk mendapatkan waktu timeout session dalam menit
  static int getSessionTimeout() {
    return _sessionTimeoutMinutes;
  }

  // Getter untuk status login
  static bool get hasLoggedInUser => _hasLoggedInUser;

  // Metode untuk menghindari blocking pada SharedPreferences
  static Future<SharedPreferences?> _getSafeSharedPreferences() async {
    try {
      return await SharedPreferences.getInstance().timeout(
        const Duration(seconds: 2),
        onTimeout: () {
          debugPrint('Session: SharedPreferences timeout');
          throw TimeoutException('SharedPreferences timeout');
        },
      );
    } catch (e) {
      debugPrint('Session: Error getting SharedPreferences - $e');
      return null;
    }
  }

  // Initialize session management
  static Future<void> initializeSession() async {
    try {
      _isAppJustLaunched = true;
      debugPrint('Session: App just launched flag set to true');

      Future.delayed(Duration(seconds: 10), () {
        _isAppJustLaunched = false;
        debugPrint('Session: App just launched flag set to false after delay');
      });

      final currentUser = Supabase.instance.client.auth.currentUser;
      if (currentUser == null) {
        debugPrint('Session: No authenticated user found');
        _hasLoggedInUser = false;
        return;
      }

      _hasLoggedInUser = true;
      await updateLastUserInteraction();
      _isAppInBackground = false;
      _setSessionExpired(false);

      // Initialize user presence service
      try {
        if (GetIt.instance.isRegistered<UserPresenceService>()) {
          await GetIt.instance<UserPresenceService>().initialize();
          _startPresenceUpdates();
        }
      } catch (e) {
        debugPrint('Session: Error initializing presence service - $e');
      }

      Future.delayed(Duration(seconds: 5), () {
        _startSessionMonitoring();
      });

      debugPrint(
        'Session: Initialized successfully for user: ${currentUser.email}',
      );
    } catch (e) {
      debugPrint('Session: Error initializing - $e');
      _hasLoggedInUser = false;
    }
  }

  // Method baru untuk memperbarui status login
  static void setUserLoggedIn(bool isLoggedIn) {
    _hasLoggedInUser = isLoggedIn;
    debugPrint('Session: User login status set to: $isLoggedIn');

    if (isLoggedIn) {
      _setSessionExpired(false); // Pastikan expired direset!
      _isSessionExpired = false;
      _sessionExpiredController.add(false); // Kirim event expired false
      updateLastUserInteraction();
      _startSessionMonitoring();
      _startPresenceUpdates();
    } else {
      _stopSessionMonitoring();
      _stopPresenceUpdates();
      _setSessionExpired(false); // Reset expired saat logout juga!
      _isSessionExpired = false;
      _sessionExpiredController.add(false);
    }
  }

  // Tambahkan fungsi untuk reset expired state secara manual
  static void resetExpiredState() {
    _isSessionExpired = false;
    _sessionExpiredController.add(false);
  }

  // Start periodic presence updates
  static void _startPresenceUpdates() {
    _stopPresenceUpdates(); // Stop any existing timer

    // Update presence every 30 seconds
    _presenceUpdateTimer = Timer.periodic(Duration(seconds: 30), (timer) {
      if (_hasLoggedInUser && !_isSessionExpired) {
        try {
          if (GetIt.instance.isRegistered<UserPresenceService>()) {
            GetIt.instance<UserPresenceService>().updatePresence();
          }
        } catch (e) {
          debugPrint('Session: Error updating presence - $e');
        }
      }
    });

    debugPrint('Session: Started presence updates');
  }

  // Stop presence updates
  static void _stopPresenceUpdates() {
    _presenceUpdateTimer?.cancel();
    _presenceUpdateTimer = null;
  }

  // Check if session is valid with extremely permissive logic
  static Future<bool> isSessionValid() async {
    debugPrint('Session: Checking session validity (PERMISSIVE MODE)...');

    // Check if user is actually logged in
    final currentUser = Supabase.instance.client.auth.currentUser;
    final currentSession = Supabase.instance.client.auth.currentSession;

    if (currentUser == null || currentSession == null) {
      debugPrint('Session: No user or session found, returning false');
      return false;
    }

    // Always return true for permissive mode if user is logged in
    debugPrint('Session: PERMISSIVE MODE - User logged in, returning true');
    return true;
  }

  // BARU: Update timestamp interaksi pengguna terakhir
  static Future<void> updateLastUserInteraction() async {
    try {
      final currentUser = Supabase.instance.client.auth.currentUser;
      if (currentUser == null) {
        debugPrint(
          'Session: Cannot update interaction - user not authenticated',
        );
        return;
      }

      SharedPreferences? prefs = await _getSafeSharedPreferences();
      if (prefs == null) return;

      final now = DateTime.now().millisecondsSinceEpoch;

      try {
        await prefs
            .setInt(_lastUserInteractionKey, now)
            .timeout(
              const Duration(seconds: 2),
              onTimeout: () {
                debugPrint(
                  'Session: Timeout setting last user interaction time',
                );
                return false;
              },
            );

        await updateLastActiveTime();

        // Update presence when user interacts
        try {
          if (GetIt.instance.isRegistered<UserPresenceService>()) {
            GetIt.instance<UserPresenceService>().updatePresence();
          }
        } catch (e) {
          debugPrint('Session: Error updating presence on interaction - $e');
        }

        debugPrint(
          'Session: User interaction recorded at ${DateTime.fromMillisecondsSinceEpoch(now)}',
        );
      } catch (e) {
        debugPrint(
          'Session: Error writing user interaction to SharedPreferences - $e',
        );
      }
    } catch (e) {
      debugPrint('Session: Error updating user interaction - $e');
    }
  }

  // Update last active time with better error handling
  static Future<void> updateLastActiveTime() async {
    try {
      final currentUser = Supabase.instance.client.auth.currentUser;
      if (currentUser == null) {
        debugPrint('Session: Cannot update activity - user not authenticated');
        return;
      }

      SharedPreferences? prefs = await _getSafeSharedPreferences();
      if (prefs == null) return;

      final now = DateTime.now().millisecondsSinceEpoch;

      try {
        await prefs
            .setInt(_lastActiveTimeKey, now)
            .timeout(
              const Duration(seconds: 2),
              onTimeout: () {
                debugPrint('Session: Timeout setting last active time');
                return false;
              },
            );

        await prefs
            .setString(_sessionStateKey, 'active')
            .timeout(
              const Duration(seconds: 2),
              onTimeout: () {
                debugPrint('Session: Timeout setting session state');
                return false;
              },
            );

        debugPrint(
          'Session: Activity updated at ${DateTime.fromMillisecondsSinceEpoch(now)}',
        );
      } catch (e) {
        debugPrint('Session: Error writing to SharedPreferences - $e');
      }
    } catch (e) {
      debugPrint('Session: Error updating activity - $e');
    }
  }

  // Called when app goes to background
  static Future<void> onAppBackground() async {
    debugPrint('Session: App entering background');
    _isAppInBackground = true;
    await updateLastActiveTime();
    _startSessionMonitoring();
  }

  // Called when app comes to foreground
  static Future<void> onAppForeground() async {
    debugPrint('Session: App entering foreground');
    if (!_isAppInBackground) return;

    _isAppInBackground = false;

    try {
      final currentUser = Supabase.instance.client.auth.currentUser;
      if (currentUser == null) {
        debugPrint(
          'Session: No authenticated user when returning to foreground',
        );
        _stopSessionMonitoring();
        return;
      }

      debugPrint(
        'Session: Checking session validity after returning to foreground',
      );

      // Use permissive mode - don't check timeout
      final isValid = await isSessionValid();
      if (!isValid) {
        debugPrint('Session: Session invalid after background');
        await clearSession();
        Future.delayed(const Duration(milliseconds: 500), () {
          _setSessionExpired(true);
        });
      } else {
        debugPrint('Session: Still valid after background');
        await updateLastActiveTime();
        _startSessionMonitoring();
      }
    } catch (e) {
      debugPrint('Session: Error during foreground transition - $e');
    }
  }

  // Set session expired state and notify listeners
  static void _setSessionExpired(bool value) {
    // Jangan trigger expired jika user memang belum login
    if (!_hasLoggedInUser) {
      debugPrint('Session: Not logged in, skip setting expired state');
      return;
    }
    if (_isSessionExpired != value) {
      _isSessionExpired = value;
      debugPrint('Session: Setting expired state to $value');
      _sessionExpiredController.add(value);

      // If session is expired, force clear session
      if (value) {
        debugPrint('Session: Session expired, clearing session data');
        clearSession();
      }
    }
  }

  // Get session status for UI components
  static bool get isExpired => _isSessionExpired;

  // Check if user is properly authenticated
  static bool get isAuthenticated {
    if (_isSessionExpired) {
      debugPrint('Session: Session is marked as expired, not authenticated');
      return false;
    }

    if (!_hasLoggedInUser) {
      return false;
    }

    final currentUser = Supabase.instance.client.auth.currentUser;
    final currentSession = Supabase.instance.client.auth.currentSession;

    final isValid =
        currentUser != null && currentSession != null && !_isSessionExpired;

    // Only update state if there's a significant change, and be more conservative
    if (!isValid && _hasLoggedInUser) {
      // Double check before changing state to avoid race conditions
      final doubleCheckUser = Supabase.instance.client.auth.currentUser;
      final doubleCheckSession = Supabase.instance.client.auth.currentSession;

      if (doubleCheckUser == null || doubleCheckSession == null) {
        debugPrint(
          'Session: User authentication state changed, updating flags',
        );
        _hasLoggedInUser = false;
        _setSessionExpired(true);
      } else {
        debugPrint('Session: User still exists, keeping authentication state');
      }
    }

    return isValid;
  }

  // Clear session data with proper cleanup
  static Future<void> clearSession() async {
    try {
      _stopSessionMonitoring();
      _setSessionExpired(true);
      _hasLoggedInUser = false;
      _isSessionExpired = false;
      _sessionExpiredController.add(false);

      final prefs = await SharedPreferences.getInstance();
      await prefs.remove(_lastActiveTimeKey);
      await prefs.remove(_lastUserInteractionKey);
      await prefs.remove(_sessionStateKey);

      await Supabase.instance.client.auth.signOut();

      debugPrint('Session: Cleared and signed out successfully');
    } catch (e) {
      debugPrint('Session: Error during cleanup - $e');
      _setSessionExpired(true);
      _hasLoggedInUser = false;
      _isSessionExpired = false;
      _sessionExpiredController.add(false);
    }
  }

  // Refresh session - extend if still valid
  static Future<bool> refreshSession() async {
    try {
      final isValid = await isSessionValid();
      if (isValid) {
        await updateLastUserInteraction();
        return true;
      }
      return false;
    } catch (e) {
      debugPrint('Session: Error refreshing - $e');
      return false;
    }
  }

  // Fungsi baru untuk memberi tahu aplikasi tentang aktivitas penting yang harus memperbarui sesi
  static Future<void> notifyImportantActivity(String activityType) async {
    try {
      debugPrint('Session: Important activity detected: $activityType');
      await updateLastUserInteraction();

      Timer(Duration(seconds: 2), () {
        debugPrint('Session: Follow-up check after important activity');
        isSessionValid();
      });
    } catch (e) {
      debugPrint('Session: Error handling important activity - $e');
    }
  }

  // Start session monitoring (DISABLED for permissive mode)
  static void _startSessionMonitoring() {
    _stopSessionMonitoring();

    debugPrint('Session: Session monitoring DISABLED for permissive mode');

    // No timer setup - completely disabled
    debugPrint('Session: No periodic checks will run');
  }

  // Stop session monitoring
  static void _stopSessionMonitoring() {
    _sessionCheckTimer?.cancel();
    _sessionCheckTimer = null;
    _stopPresenceUpdates();
    debugPrint('Session: Monitoring stopped');
  }

  // Dispose resources
  static void dispose() {
    _sessionCheckTimer?.cancel();
    _presenceUpdateTimer?.cancel();
    _sessionExpiredController.close();

    try {
      if (GetIt.instance.isRegistered<UserPresenceService>()) {
        GetIt.instance<UserPresenceService>().dispose();
      }
    } catch (e) {
      debugPrint('Session: Error disposing presence service - $e');
    }
  }
}
