import '../../../../core/errors/result.dart';
import '../../domain/entities/user.dart';
import '../../domain/repositories/auth_repository.dart';
import '../datasources/auth_local_datasource.dart';
import '../datasources/auth_remote_datasource.dart';

class AuthRepositoryImpl implements AuthRepository {
  final AuthRemoteDataSource remoteDataSource;
  final AuthLocalDataSource localDataSource;

  AuthRepositoryImpl({
    required this.remoteDataSource,
    required this.localDataSource,
  });

  @override
  Future<Result<User>> login(String username, String password) async {
    final result = await remoteDataSource.login(username, password);
    return result.fold(
      (error) => Result.failure(error),
      (response) async {
        await localDataSource.saveToken(response.accessToken);
        await localDataSource.saveRefreshToken(response.refreshToken);
        await localDataSource.saveUserId(response.userId);
        return Result.success(response.toDomainUser());
      },
    );
  }

  @override
  Future<Result<User>> register(String username, String password, String name) async {
    final result = await remoteDataSource.register(username, password, name);
    return result.fold(
      (error) => Result.failure(error),
      (response) async {
        await localDataSource.saveToken(response.accessToken);
        await localDataSource.saveRefreshToken(response.refreshToken);
        await localDataSource.saveUserId(response.userId);
        return Result.success(response.toDomainUser());
      },
    );
  }

  @override
  Future<Result<void>> logout() async {
    await remoteDataSource.logout();
    await localDataSource.removeToken();
    await localDataSource.removeUserId();
    return const Result.success(null);
  }

  @override
  Future<Result<User>> getCurrentUser() async {
    final result = await remoteDataSource.getCurrentUser();
    if (result.isFailure) {
      // If remote fails (e.g. offline), try to return a dummy user with stored ID
      // to keep the app in authenticated state if we have a token
      final userId = await localDataSource.getUserId();
      if (userId != null) {
        return Result.success(User(id: userId, name: 'User', email: ''));
      }
    }
    return result;
  }

  @override
  Future<Result<void>> refreshToken() async {
    return await remoteDataSource.refreshToken();
  }

  @override
  bool get isLoggedIn {
    // This is problematic because it's synchronous but SharedPreferences is async.
    // However, in our DI we wait for SharedPreferences.getInstance().
    // We can use a synchronous check if we expose it or just use the fact that
    // AuthBloc calls authChecked which is async.
    return localDataSource.getTokenSync() != null;
  }
}
