import 'dart:async';
import 'package:bloc/bloc.dart';
import 'editor_session_event.dart';
import 'editor_session_state.dart';
import '../../services/file_service.dart';
import '../../models/api_error.dart';

class EditorSessionBloc extends Bloc<EditorSessionEvent, EditorSessionState> {
  final FileService _fileService;
  Timer? _expiryTimer;

  EditorSessionBloc(this._fileService) : super(EditorSessionInitial()) {
    on<EditorSessionStarted>(_onEditorSessionStarted);
    on<EditorSessionConnected>(_onEditorSessionConnected);
    on<EditorSessionDisconnected>(_onEditorSessionDisconnected);
    on<EditorSessionEnded>(_onEditorSessionEnded);
  }

  String _getErrorMessage(dynamic error) {
    if (error is ApiError) {
      switch (error.code) {
        case 'UNAUTHENTICATED':
          return 'Session expired. Please log in again.';
        case 'PERMISSION_DENIED':
          return 'You do not have permission to edit this file.';
        case 'NOT_FOUND':
          return 'The file was not found.';
        case 'CONFLICT':
          return 'The file has been modified. Please refresh and try again.';
        case 'INVALID_ARGUMENT':
          return 'Invalid request.';
        case 'INTERNAL':
        default:
          return 'An error occurred while opening the editor.';
      }
    }
    return error.toString();
  }

  void _onEditorSessionStarted(
    EditorSessionStarted event,
    Emitter<EditorSessionState> emit,
  ) async {
    emit(EditorSessionStarting());
    try {
      final session = await _fileService.requestEditorSession(
        event.orgId,
        event.fileId,
      );
      if (session.expiresAt.isBefore(DateTime.now())) {
        emit(EditorSessionExpired());
        return;
      }
      if (!session.readOnly) {
        emit(
          EditorSessionActive(editUrl: session.editUrl, token: session.token),
        );
      } else {
        emit(
          EditorSessionReadOnly(viewUrl: session.editUrl, token: session.token),
        );
      }
      _expiryTimer = Timer(
        session.expiresAt.difference(DateTime.now()),
        () => add(EditorSessionEnded()), // Or emit expired
      );
    } catch (e) {
      emit(EditorSessionFailed(message: _getErrorMessage(e)));
    }
  }

  void _onEditorSessionConnected(
    EditorSessionConnected event,
    Emitter<EditorSessionState> emit,
  ) {
    // Handle connection if needed
  }

  void _onEditorSessionDisconnected(
    EditorSessionDisconnected event,
    Emitter<EditorSessionState> emit,
  ) {
    // Handle disconnection if needed
  }

  void _onEditorSessionEnded(
    EditorSessionEnded event,
    Emitter<EditorSessionState> emit,
  ) {
    _expiryTimer?.cancel();
    emit(EditorSessionInitial());
  }
}
