import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:social_app/features/auth/data/auth_repository.dart';
import 'package:social_app/features/auth/data/models/auth_response.dart';
import 'package:social_app/features/auth/presentation/bloc/auth_bloc.dart';
import 'package:social_app/features/auth/presentation/bloc/auth_event.dart';
import 'package:social_app/features/auth/presentation/bloc/auth_state.dart';

class MockAuthRepository extends Mock implements AuthRepository {}

void main() {
  late AuthBloc authBloc;
  late MockAuthRepository mockRepository;

  setUp(() {
    mockRepository = MockAuthRepository();
    authBloc = AuthBloc(mockRepository);
  });

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

  group('AuthBloc', () {
    blocTest<AuthBloc, AuthState>(
      'emits [AuthLoading, AuthUnauthenticated] when AuthStarted and no refresh token',
      build: () {
        when(
          () => mockRepository.getRefreshToken(),
        ).thenAnswer((_) async => null);
        return authBloc;
      },
      act: (bloc) => bloc.add(AuthStarted()),
      expect: () => [AuthLoading(), AuthUnauthenticated()],
    );

    blocTest<AuthBloc, AuthState>(
      'emits [AuthLoading, AuthAuthenticated] when AuthStarted with valid refresh token',
      build: () {
        when(
          () => mockRepository.getRefreshToken(),
        ).thenAnswer((_) async => 'valid_refresh');
        when(() => mockRepository.refreshSession('valid_refresh')).thenAnswer(
          (_) async => AuthResponse(
            accessToken: 'new_access',
            refreshToken: 'new_refresh',
            expiresIn: 3600,
            tokenType: 'bearer',
            user: const AuthUser(id: '123', email: 'test@example.com'),
          ),
        );
        return authBloc;
      },
      act: (bloc) => bloc.add(AuthStarted()),
      expect: () => [AuthLoading(), isA<AuthAuthenticated>()],
    );

    blocTest<AuthBloc, AuthState>(
      'emits [AuthLoading, AuthUnauthenticated] when refresh token expired',
      build: () {
        when(
          () => mockRepository.getRefreshToken(),
        ).thenAnswer((_) async => 'expired_refresh');
        when(
          () => mockRepository.refreshSession('expired_refresh'),
        ).thenThrow(Exception('Invalid refresh token'));
        when(() => mockRepository.deleteSession()).thenAnswer((_) async {});
        return authBloc;
      },
      act: (bloc) => bloc.add(AuthStarted()),
      expect: () => [AuthLoading(), AuthUnauthenticated()],
    );

    blocTest<AuthBloc, AuthState>(
      'emits [AuthAuthenticated] when AuthLoggedIn',
      build: () => authBloc,
      act: (bloc) => bloc.add(
        AuthLoggedIn(
          user: const AuthUser(id: '1', email: 'test@example.com'),
        ),
      ),
      expect: () => [isA<AuthAuthenticated>()],
    );

    blocTest<AuthBloc, AuthState>(
      'emits [AuthUnauthenticated] when AuthLoggedOut',
      build: () {
        when(() => mockRepository.deleteSession()).thenAnswer((_) async {});
        return authBloc;
      },
      seed: () => AuthAuthenticated(
        user: const AuthUser(id: '1', email: 'test@example.com'),
      ),
      act: (bloc) => bloc.add(AuthLoggedOut()),
      expect: () => [AuthUnauthenticated()],
    );
  });
}
