import 'package:dartz/dartz.dart';

import '../../../../core/errors/exceptions.dart';
import '../../../../core/errors/failures.dart';
import '../../../../core/storage/secure_storage.dart';
import '../../domain/entities/user_entity.dart';
import '../../domain/repositories/auth_repository.dart';
import '../datasources/auth_remote_datasource.dart';
import '../models/login_request_model.dart';

/// Implementation of AuthRepository
///
/// Coordinates between remote data source and local storage
/// Handles error conversion from exceptions to failures
class AuthRepositoryImpl implements AuthRepository {
  final AuthRemoteDataSource remoteDataSource;
  final SecureStorage secureStorage;

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

  @override
  Future<Either<Failure, UserEntity>> login(LoginRequestModel request) async {
    try {
      // Call remote data source to login
      final userModel = await remoteDataSource.login(request);

      // Save tokens to secure storage
      await secureStorage.saveAccessToken(userModel.accessToken);
      await secureStorage.saveUserId(userModel.userId);
      await secureStorage.saveUsername(userModel.username);
      // Save email (username is the email from login)
      await secureStorage.saveEmail(request.username);

      if (userModel.refreshToken != null) {
        await secureStorage.saveRefreshToken(userModel.refreshToken!);
      }

      // Return user entity
      return Right(userModel.toEntity());
    } on ServerException catch (e) {
      return Left(AuthenticationFailure(e.message));
    } on NetworkException catch (e) {
      return Left(NetworkFailure(e.message));
    } catch (e) {
      return Left(UnknownFailure('Login failed: ${e.toString()}'));
    }
  }

  @override
  Future<Either<Failure, void>> logout() async {
    try {
      // Just clear access token from secure storage
      // No API call needed
      await secureStorage.clearTokens();

      return const Right(null);
    } catch (e) {
      return Left(UnknownFailure('Logout failed: ${e.toString()}'));
    }
  }

  @override
  Future<Either<Failure, UserEntity>> refreshToken(String refreshToken) async {
    try {
      // Call remote data source to refresh token
      final userModel = await remoteDataSource.refreshToken(refreshToken);

      // Update tokens in secure storage
      await secureStorage.saveAccessToken(userModel.accessToken);
      if (userModel.refreshToken != null) {
        await secureStorage.saveRefreshToken(userModel.refreshToken!);
      }

      return Right(userModel.toEntity());
    } on ServerException catch (e) {
      return Left(AuthenticationFailure(e.message));
    } on NetworkException catch (e) {
      return Left(NetworkFailure(e.message));
    } catch (e) {
      return Left(UnknownFailure('Token refresh failed: ${e.toString()}'));
    }
  }

  @override
  Future<bool> isAuthenticated() async {
    try {
      return await secureStorage.isAuthenticated();
    } catch (e) {
      return false;
    }
  }

  @override
  Future<Either<Failure, UserEntity>> getCurrentUser() async {
    try {
      final userId = await secureStorage.getUserId();
      final username = await secureStorage.getUsername();
      final accessToken = await secureStorage.getAccessToken();
      final refreshToken = await secureStorage.getRefreshToken();

      if (userId == null || username == null || accessToken == null) {
        return const Left(AuthenticationFailure('No user data found'));
      }

      final user = UserEntity(
        userId: userId,
        username: username,
        accessToken: accessToken,
        refreshToken: refreshToken,
      );

      return Right(user);
    } catch (e) {
      return Left(CacheFailure('Failed to get user data: ${e.toString()}'));
    }
  }

  @override
  Future<Either<Failure, void>> clearAuthData() async {
    try {
      await secureStorage.clearAll();
      return const Right(null);
    } catch (e) {
      return Left(CacheFailure('Failed to clear auth data: ${e.toString()}'));
    }
  }
}
