import 'package:bloc_test/bloc_test.dart';
import 'package:comwell_key_app/authentication/authentication_repository.dart';
import 'package:comwell_key_app/domain/models/app_error.dart';
import 'package:comwell_key_app/domain/models/user.dart';
import 'package:comwell_key_app/domain/repositories/profile_repository.dart';
import 'package:comwell_key_app/domain/models/address.dart';
import 'package:comwell_key_app/presentation/app/bloc/profile_cubit.dart';
import 'package:comwell_key_app/presentation/screens/profile_settings/bloc/profile_settings_cubit.dart';
import 'package:comwell_key_app/presentation/screens/profile_settings/bloc/profile_settings_state.dart';
import 'package:comwell_key_app/domain/repositories/profile_settings_repository.dart';
import 'package:comwell_key_app/tracking/comwell_tracking.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';

class MockProfileSettingsRepository extends Mock implements ProfileSettingsRepository {}

class MockAuthenticationRepository extends Mock implements AuthenticationRepository {}

class MockProfileRepository extends Mock implements ProfileRepository {}

class MockTracking extends Mock implements ComwellTracking {}

class MockProfileCubit extends Mock implements ProfileCubit {}

final user = User(
  userId: '1',
  email: 'john.doe@example.com',
  emailVerified: true,
  locale: 'en',
  wasRecentlyCreated: false,
  firstName: 'John',
  lastName: 'Doe',
  phoneNumber: '1234567890',
  gender: 'Male',
  address: const Address(
    street: '123 Main St',
    city: 'Anytown',
    zipCode: '12345',
    country: 'USA',
  ),
  birthDate: DateTime(1990, 1, 1),
  shopperReference: '1234567890',
  points: 100,
  isClubMember: false,
);

void main() {
  late ProfileSettingsCubit profileSettingsCubit;
  late MockProfileSettingsRepository mockProfileSettingsRepository;
  late MockAuthenticationRepository mockAuthenticationRepository;
  late MockProfileRepository mockProfileRepository;
  late MockTracking mockTracking;
  late MockProfileCubit mockProfileCubit;
  setUp(() {
    mockProfileSettingsRepository = MockProfileSettingsRepository();

    mockAuthenticationRepository = MockAuthenticationRepository();
    mockProfileRepository = MockProfileRepository();
    when(() => mockProfileRepository.fetchProfileSettings()).thenAnswer((_) async => user);
    mockTracking = MockTracking();
    mockProfileCubit = MockProfileCubit();
    profileSettingsCubit = ProfileSettingsCubit(
      mockProfileRepository,
      mockAuthenticationRepository,
      mockProfileCubit,
      mockProfileSettingsRepository,
      mockTracking,
    );
  });
  tearDown(() {
    profileSettingsCubit.close();
  });

  group('ProfileSettingsCubit', () {
    blocTest<ProfileSettingsCubit, ProfileSettingsState>(
      'emits [ProfileSettingsLoading, ProfileSettingsLoaded] when fetchProfileSettings is successful',
      build: () {
        when(() => mockProfileRepository.fetchProfileSettings()).thenAnswer((_) async => user);
        return profileSettingsCubit;
      },
      act: (cubit) => cubit.init(),
      expect: () => [
        ProfileSettingsState(),
      ],
    );

    blocTest<ProfileSettingsCubit, ProfileSettingsState>(
      'emits [ProfileSettingsLoading, ProfileSettingsError] when fetchProfileSettings fails',
      build: () {
        when(
          () => mockProfileRepository.fetchProfileSettings(),
        ).thenThrow(Exception('Failed to fetch profile settings'));
        return profileSettingsCubit;
      },
      act: (cubit) => cubit.init(),
      expect: () => [
        const ProfileSettingsState(
          error: AppError.none,
          isLoading: true,
        ),
        ProfileSettingsState(
          error: AppError.unknown('Failed to fetch profile settings'),
          isLoading: true,
        ),
        ProfileSettingsState(
          error: AppError.unknown('Failed to fetch profile settings'),
          isLoading: false,
        ),
      ],
    );

    blocTest<ProfileSettingsCubit, ProfileSettingsState>(
      'emits [ProfileSettingsDeleted] when deleteProfile is successful',
      build: () {
        when(() => mockProfileSettingsRepository.deleteProfile()).thenAnswer((_) async => {});
        when(() => mockAuthenticationRepository.logOut()).thenAnswer((_) async => {});
        return profileSettingsCubit;
      },
      act: (cubit) => cubit.deleteProfile(),
      expect: () => [
        const ProfileSettingsState(isDeleted: true),
      ],
    );

    blocTest<ProfileSettingsCubit, ProfileSettingsState>(
      'emits [ProfileSettingsError] when deleteProfile fails',
      build: () {
        when(
          () => mockProfileSettingsRepository.deleteProfile(),
        ).thenThrow(Exception('Failed to delete profile'));
        return profileSettingsCubit;
      },
      act: (cubit) => cubit.deleteProfile(),
      expect: () => [
        const ProfileSettingsState(),
      ],
    );
  });
}