import 'package:bloc_test/bloc_test.dart';
import 'package:comwell_key_app/domain/repositories/booking_details_repository.dart';
import 'package:comwell_key_app/key/bloc/key_bloc.dart';
import 'package:comwell_key_app/key/repository/key_repository.dart';
import 'package:comwell_key_app/utils/seos_repository.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:fake_async/fake_async.dart';
import 'package:seos_mobile_keys_plugin/app_usage_api.dart';

class MockKeyRepository extends Mock implements KeyRepository {}

class MockBookingDetailsRepository extends Mock implements BookingDetailsRepository {}

class MockMobileKeysKey extends Mock implements MobileKeysKey {}

class MockSeosRepository extends Mock implements SeosRepository {}

void main() {
  late KeyBloc keyBloc;
  late MockKeyRepository mockKeyRepository;
  late MockBookingDetailsRepository mockBookingDetailsRepository;
  late MockMobileKeysKey mockMobileKeysKey;
  late MockSeosRepository mockSeosRepository;

  setUp(() {
    mockKeyRepository = MockKeyRepository();
    mockBookingDetailsRepository = MockBookingDetailsRepository();
    mockMobileKeysKey = MockMobileKeysKey();
    mockSeosRepository = MockSeosRepository();
    keyBloc = KeyBloc(
      seosRepository: mockSeosRepository,
      keyRepository: mockKeyRepository,
      bookingDetailsRepository: mockBookingDetailsRepository,
    );
  });

  tearDown(() {
    keyBloc.close();
  });

  group('KeyBloc', () {
    blocTest<KeyBloc, KeyState>(
      'emits [KeyState.searchForKeys, KeyState.validKeys, KeyState.scanning, KeyState.openClosestReaderSuccess] when SearchForKeys and StartScanning are added',
      build: () {
        when(() => mockKeyRepository.checkDeviceInfo()).thenAnswer((_) async => {});
        when(() => mockSeosRepository.refreshKeys()).thenAnswer((_) async => [mockMobileKeysKey]);
        return keyBloc;
      },
      act: (bloc) {
        fakeAsync((async) {
          bloc.add(SearchForKeys());
          async.elapse(const Duration(seconds: 5));
        });
      },
      expect: () => [
        KeyState.searchForKeys(),
        KeyState.validKeys([mockMobileKeysKey]),
        KeyState.scanning(),
       // KeyState.openClosestReaderSuccess(), Not able to test this
      ],
    );

    blocTest<KeyBloc, KeyState>(
      'emits [KeyState.searchForKeys, KeyState.searchForKeysError] when SearchForKeys fails',
      build: () {
        when(() => mockSeosRepository.refreshKeys()).thenThrow(Exception('Failed to list keys'));
        return keyBloc;
      },
      act: (bloc) => bloc.add(SearchForKeys()),
      expect: () => [
        KeyState.searchForKeys(),
        KeyState.searchForKeysError('Exception: Failed to list keys'),
      ],
    );

    blocTest<KeyBloc, KeyState>(
      'emits [KeyState.scanningError] when StartScanning fails',
      build: () {
        when(() => mockKeyRepository.checkDeviceInfo()).thenThrow(Exception('Device info error'));
        return keyBloc;
      },
      act: (bloc) => bloc.add(const StartScanning()),
      expect: () => [
        KeyState.scanningError('Exception: Device info error'),
      ],
    );
  });
}