import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import '../../core/errors/failures.dart';
import '../../domain/repositories/auth_repository.dart';
import '../datasources/remote/auth_remote_datasource.dart';
import '../models/auth/auth_user.dart';
import '../models/auth/login_request.dart';
import '../models/auth/login_response.dart';
import '../models/auth/logout_request.dart';
import '../models/auth/refresh_token_request.dart';
import '../models/auth/token_response.dart';

/// 인증 Repository 구현체
/// JWT 토큰 기반 인증 시스템을 관리하며 SharedPreferences를 사용해 토큰을 저장
@Injectable(as: AuthRepository)
class AuthRepositoryImpl implements AuthRepository {
  final AuthRemoteDataSource remoteDataSource;
  final SharedPreferences sharedPreferences;
  final FlutterSecureStorage secureStorage;
  
  // SharedPreferences 키 상수
  static const String _keyAccessToken = 'access_token';
  static const String _keyRefreshToken = 'refresh_token';
  static const String _keyUserData = 'user_data';

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

  @override
  Future<Either<Failure, LoginResponse>> login(LoginRequest loginRequest) async {
    try {
      final result = await remoteDataSource.login(loginRequest);
      
      return result.fold(
        (failure) => Left(failure),
        (loginResponse) async {
          // 로그인 성공 시 토큰과 사용자 정보를 로컬에 저장 (보안 저장소)
          await _saveTokens(loginResponse.accessToken, loginResponse.refreshToken);
          await _saveUserData(loginResponse.user);
          
          return Right(loginResponse);
        },
      );
    } catch (e) {
      return Left(ServerFailure(
        message: '로그인 처리 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, void>> logout() async {
    try {
      // 로컬에 저장된 리프레시 토큰으로 로그아웃 요청 생성
      final refreshToken = await _getRefreshToken();
      if (refreshToken == null) {
        // 토큰이 없으면 로컬 데이터만 삭제하고 성공 처리
        await _clearLocalData();
        return const Right(null);
      }
      
      final logoutRequest = LogoutRequest(refreshToken: refreshToken);
      final result = await remoteDataSource.logout(logoutRequest);
      
      return result.fold(
        (failure) async {
          // 서버 로그아웃 실패해도 로컬 데이터는 삭제
          await _clearLocalData();
          return Left(failure);
        },
        (_) async {
          // 성공 시 로컬 데이터 삭제
          await _clearLocalData();
          return const Right(null);
        },
      );
    } catch (e) {
      // 오류 발생해도 로컬 데이터는 삭제
      await _clearLocalData();
      return Left(ServerFailure(
        message: '로그아웃 처리 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, TokenResponse>> refreshToken(RefreshTokenRequest refreshRequest) async {
    try {
      final result = await remoteDataSource.refreshToken(refreshRequest);
      
      return result.fold(
        (failure) => Left(failure),
        (tokenResponse) async {
          // 새 토큰 저장 (보안 저장소)
          await _saveTokens(tokenResponse.accessToken, tokenResponse.refreshToken);
          return Right(tokenResponse);
        },
      );
    } catch (e) {
      return Left(ServerFailure(
        message: '토큰 갱신 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, AuthUser>> getCurrentUser() async {
    try {
      final userData = sharedPreferences.getString(_keyUserData);
      if (userData == null) {
        return const Left(AuthenticationFailure(
          message: '저장된 사용자 정보가 없습니다.',
        ));
      }
      
      // JSON 문자열을 AuthUser 객체로 변환
      final user = AuthUser.fromJson(
        Map<String, dynamic>.from(
          // JSON 디코딩 처리 필요 시 여기에 추가
          {} // TODO: JSON 디코딩 로직 추가
        )
      );
      
      return Right(user);
    } catch (e) {
      return Left(ServerFailure(
        message: '사용자 정보 조회 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, bool>> isAuthenticated() async {
    try {
      final accessToken = await _getAccessToken();
      final refreshToken = await _getRefreshToken();
      
      // 액세스 토큰과 리프레시 토큰이 모두 있으면 인증된 것으로 간주
      final isAuth = accessToken != null && refreshToken != null;
      return Right(isAuth);
    } catch (e) {
      return Left(ServerFailure(
        message: '인증 상태 확인 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, void>> changePassword(String currentPassword, String newPassword) async {
    // TODO: 비밀번호 변경 API가 구현되면 추가
    return const Left(ServerFailure(
      message: '비밀번호 변경 기능은 아직 구현되지 않았습니다.',
    ));
  }

  @override
  Future<Either<Failure, void>> requestPasswordReset(String email) async {
    // TODO: 비밀번호 재설정 API가 구현되면 추가
    return const Left(ServerFailure(
      message: '비밀번호 재설정 기능은 아직 구현되지 않았습니다.',
    ));
  }

  @override
  Future<Either<Failure, bool>> validateSession() async {
    try {
      final accessToken = await _getAccessToken();
      if (accessToken == null) {
        return const Right(false);
      }
      
      // TODO: 서버에서 세션 유효성 검증 API가 있으면 호출
      // 현재는 토큰 존재 여부만 확인
      return const Right(true);
    } catch (e) {
      return Left(ServerFailure(
        message: '세션 유효성 검증 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, String?>> getStoredRefreshToken() async {
    try {
      final token = await _getRefreshToken();
      return Right(token);
    } catch (e) {
      return Left(ServerFailure(
        message: '리프레시 토큰 조회 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, String?>> getStoredAccessToken() async {
    try {
      final token = await _getAccessToken();
      return Right(token);
    } catch (e) {
      return Left(ServerFailure(
        message: '액세스 토큰 조회 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  @override
  Future<Either<Failure, void>> clearLocalSession() async {
    try {
      await _clearLocalData();
      return const Right(null);
    } catch (e) {
      return Left(ServerFailure(
        message: '로컬 세션 정리 중 오류가 발생했습니다: ${e.toString()}',
      ));
    }
  }

  // Private 헬퍼 메서드들
  
  /// 액세스 토큰과 리프레시 토큰을 로컬에 저장 (보안 저장소 사용)
  Future<void> _saveTokens(String accessToken, String refreshToken) async {
    await secureStorage.write(key: _keyAccessToken, value: accessToken);
    await secureStorage.write(key: _keyRefreshToken, value: refreshToken);
  }
  
  /// 사용자 데이터를 로컬에 저장
  Future<void> _saveUserData(AuthUser user) async {
    // TODO: JSON 인코딩 로직 구현
    await sharedPreferences.setString(_keyUserData, user.toJson().toString());
  }
  
  /// 액세스 토큰 조회 (보안 저장소)
  Future<String?> _getAccessToken() async {
    return await secureStorage.read(key: _keyAccessToken);
  }
  
  /// 리프레시 토큰 조회 (보안 저장소)
  Future<String?> _getRefreshToken() async {
    return await secureStorage.read(key: _keyRefreshToken);
  }
  
  /// 로컬 데이터 전체 삭제 (토큰은 보안 저장소에서 삭제)
  Future<void> _clearLocalData() async {
    // 토큰 삭제
    await secureStorage.delete(key: _keyAccessToken);
    await secureStorage.delete(key: _keyRefreshToken);
    // 사용자 데이터는 SharedPreferences에 저장되어 있으므로 제거
    await sharedPreferences.remove(_keyUserData);
  }
}
