import 'package:flutter_test/flutter_test.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:mockito/mockito.dart';
import 'package:mockito/annotations.dart';
import 'package:travel_mate/blocs/trip/trip_bloc.dart';
import 'package:travel_mate/blocs/trip/trip_event.dart';
import 'package:travel_mate/blocs/trip/trip_state.dart';
import 'package:travel_mate/repositories/trip_repository.dart';
import 'package:travel_mate/models/trip.dart';

import 'trip_bloc_test.mocks.dart';

@GenerateMocks([TripRepository])
void main() {
  group('TripBloc', () {
    late MockTripRepository mockTripRepository;
    late TripBloc tripBloc;

    final trip = Trip(
      id: 'trip1',
      title: 'Summer Vacation',
      description: 'Trip to the beach',
      location: 'Miami',
      startDate: DateTime(2023, 6, 1),
      endDate: DateTime(2023, 6, 10),
      createdBy: 'user1',
      createdAt: DateTime(2023, 1, 1),
      updatedAt: DateTime(2023, 1, 2),
      participants: ['user1'],
      status: 'active',
    );

    setUp(() {
      mockTripRepository = MockTripRepository();
      tripBloc = TripBloc(mockTripRepository);
    });

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

    test('initial state is TripInitial', () {
      expect(tripBloc.state, TripInitial());
    });

    // LoadTripsByUserId
    blocTest<TripBloc, TripState>(
      'emits [TripLoading, TripLoaded] when LoadTripsByUserId is added',
      setUp: () {
        when(
          mockTripRepository.getTripsByUserId('user1'),
        ).thenAnswer((_) => Stream.value([trip]));
      },
      build: () => tripBloc,
      act: (bloc) => bloc.add(const LoadTripsByUserId(userId: 'user1')),
      expect: () => [
        TripLoading(),
        TripLoaded([trip]),
      ],
    );

    blocTest<TripBloc, TripState>(
      'emits [TripLoading, TripError] when stream error',
      setUp: () {
        when(
          mockTripRepository.getTripsByUserId('user1'),
        ).thenAnswer((_) => Stream.error('Error loading trips'));
      },
      build: () => tripBloc,
      act: (bloc) => bloc.add(const LoadTripsByUserId(userId: 'user1')),
      expect: () => [
        TripLoading(),
        const TripError('Impossible de charger les voyages'),
      ],
    );

    // TripCreateRequested
    blocTest<TripBloc, TripState>(
      'emits [TripLoading, TripCreated] when TripCreateRequested is added',
      setUp: () {
        when(
          mockTripRepository.createTrip(any),
        ).thenAnswer((_) async => 'trip1');
      },
      build: () => tripBloc,
      act: (bloc) => bloc.add(TripCreateRequested(trip: trip)),
      // Note: TripBloc automatically refreshes list if _currentUserId is set.
      // Here we haven't loaded trips so _currentUserId is null.
      expect: () => [TripLoading(), const TripCreated(tripId: 'trip1')],
    );

    // TripDeleteRequested
    blocTest<TripBloc, TripState>(
      'emits [TripOperationSuccess] when TripDeleteRequested is added',
      setUp: () {
        when(mockTripRepository.deleteTrip('trip1')).thenAnswer((_) async {});
      },
      build: () => tripBloc,
      act: (bloc) => bloc.add(const TripDeleteRequested(tripId: 'trip1')),
      expect: () => [const TripOperationSuccess('Trip deleted successfully')],
    );
  });
}
