import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'session_event.dart';
import 'session_state.dart';

class SessionBloc extends Bloc<SessionEvent, SessionState> {
  Timer? _expiryTimer;
  static const String _tokenKey = 'auth_token';
  static const String _expiryKey = 'auth_expiry';

  SessionBloc() : super(SessionInitial()) {
    on<SessionStarted>(_onSessionStarted);
    on<SessionExpired>(_onSessionExpired);
    on<SessionRefreshed>(_onSessionRefreshed);
    on<SessionEnded>(_onSessionEnded);
    on<SessionRestored>(_onSessionRestored);
  }

  void _onSessionStarted(
    SessionStarted event,
    Emitter<SessionState> emit,
  ) async {
    final expiresAt = DateTime.now().add(
      const Duration(minutes: 15),
    ); // Match Go

    // Save token to persistent storage
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_tokenKey, event.token);
    await prefs.setString(_expiryKey, expiresAt.toIso8601String());

    emit(SessionActive(token: event.token, expiresAt: expiresAt));
    _startExpiryTimer(expiresAt);
  }

  void _onSessionExpired(SessionExpired event, Emitter<SessionState> emit) {
    _expiryTimer?.cancel();
    _clearStoredSession();
    emit(SessionExpiredState());
  }

  void _onSessionRefreshed(
    SessionRefreshed event,
    Emitter<SessionState> emit,
  ) async {
    final expiresAt = DateTime.now().add(const Duration(minutes: 15));

    // Update stored token
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_tokenKey, event.newToken);
    await prefs.setString(_expiryKey, expiresAt.toIso8601String());

    emit(SessionActive(token: event.newToken, expiresAt: expiresAt));
    _startExpiryTimer(expiresAt);
  }

  void _onSessionEnded(SessionEnded event, Emitter<SessionState> emit) {
    _expiryTimer?.cancel();
    _clearStoredSession();
    emit(SessionInitial());
  }

  void _onSessionRestored(SessionRestored event, Emitter<SessionState> emit) {
    final expiresAt = event.expiresAt;
    final now = DateTime.now();

    // Check if token is still valid
    if (expiresAt.isAfter(now)) {
      emit(SessionActive(token: event.token, expiresAt: expiresAt));
      _startExpiryTimer(expiresAt);
    } else {
      // Token expired, clear it
      _clearStoredSession();
      emit(SessionInitial());
    }
  }

  Future<void> _clearStoredSession() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove(_tokenKey);
    await prefs.remove(_expiryKey);
  }

  static Future<void> restoreSession(SessionBloc bloc) async {
    final prefs = await SharedPreferences.getInstance();
    final token = prefs.getString(_tokenKey);
    final expiryStr = prefs.getString(_expiryKey);

    if (token != null && expiryStr != null) {
      try {
        final expiresAt = DateTime.parse(expiryStr);
        bloc.add(SessionRestored(token: token, expiresAt: expiresAt));
      } catch (e) {
        // Invalid stored data, clear it
        await prefs.remove(_tokenKey);
        await prefs.remove(_expiryKey);
      }
    }
  }

  void _startExpiryTimer(DateTime expiresAt) {
    _expiryTimer?.cancel();
    final duration = expiresAt.difference(DateTime.now());
    _expiryTimer = Timer(duration, () {
      add(SessionExpired());
    });
  }

  @override
  Future<void> close() {
    _expiryTimer?.cancel();
    return super.close();
  }
}
