import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';
import 'package:injectable/injectable.dart';
import 'package:superport/core/errors/exceptions.dart';
import 'package:superport/core/errors/failures.dart';
import 'package:superport/data/datasources/remote/api_client.dart';
import 'package:superport/data/models/auth/login_request.dart';
import 'package:superport/data/models/auth/login_response.dart';
import 'package:superport/data/models/auth/logout_request.dart';
import 'package:superport/data/models/auth/refresh_token_request.dart';
import 'package:superport/data/models/auth/token_response.dart';
import 'package:superport/data/models/auth/auth_user.dart';
import 'package:superport/data/models/auth/change_password_request.dart';
import 'package:superport/data/models/auth/message_response.dart';
import 'package:superport/core/utils/debug_logger.dart';

abstract class AuthRemoteDataSource {
  Future<Either<Failure, LoginResponse>> login(LoginRequest request);
  Future<Either<Failure, void>> logout(LogoutRequest request);
  Future<Either<Failure, TokenResponse>> refreshToken(RefreshTokenRequest request);
  Future<Either<Failure, AuthUser>> getCurrentAdmin();
  Future<Either<Failure, MessageResponse>> changePassword(ChangePasswordRequest request);
}

@LazySingleton(as: AuthRemoteDataSource)
class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
  final ApiClient _apiClient;

  AuthRemoteDataSourceImpl(this._apiClient);

  @override
  Future<Either<Failure, LoginResponse>> login(LoginRequest request) async {
    try {
      DebugLogger.logLogin('요청 시작', data: request.toJson());
      
      final response = await _apiClient.post(
        '/auth/login',
        data: request.toJson(),
      );

      DebugLogger.logApiResponse(
        url: '/auth/login',
        statusCode: response.statusCode,
        data: response.data,
      );

      if (response.statusCode == 200 && response.data != null) {
        final responseData = response.data;
        
        // API 응답 형식 확인 및 처리
        // 형식 1: { success: bool, data: {...} }
        if (responseData is Map && responseData['success'] == true && responseData['data'] != null) {
          DebugLogger.logLogin('응답 형식 1 감지', data: {'format': 'wrapped'});
          
          // 응답 데이터 구조 검증 (snake_case 키 확인)
          final dataFields = responseData['data'] as Map<String, dynamic>;
          DebugLogger.validateResponseStructure(
            dataFields,
            ['access_token', 'refresh_token', 'admin'],  // API returns 'admin' instead of 'user'
            responseName: 'LoginResponse.data',
          );
          
          final loginResponse = DebugLogger.parseJsonWithLogging(
            responseData['data'],
            LoginResponse.fromJson,
            objectName: 'LoginResponse',
          );
          
          if (loginResponse != null) {
            DebugLogger.logLogin('로그인 성공', data: {
              'userId': loginResponse.user.id,
              'userEmail': loginResponse.user.email,
              'userRole': loginResponse.user.role,
            });
            return Right(loginResponse);
          } else {
            return Left(ServerFailure(message: 'LoginResponse 파싱 실패'));
          }
        } 
        // 형식 2: 직접 LoginResponse 형태
        else if (responseData is Map && 
                 (responseData.containsKey('accessToken') || 
                  responseData.containsKey('access_token'))) {
          DebugLogger.logLogin('응답 형식 2 감지', data: {'format': 'direct'});
          
          // 응답 데이터 구조 검증 (snake_case 키 확인)
          DebugLogger.validateResponseStructure(
            responseData as Map<String, dynamic>,
            ['access_token', 'refresh_token', 'admin'],  // API returns 'admin' instead of 'user'
            responseName: 'LoginResponse',
          );
          
          final loginResponse = DebugLogger.parseJsonWithLogging(
            responseData,
            LoginResponse.fromJson,
            objectName: 'LoginResponse',
          );
          
          if (loginResponse != null) {
            DebugLogger.logLogin('로그인 성공', data: {
              'userId': loginResponse.user.id,
              'userEmail': loginResponse.user.email,
              'userRole': loginResponse.user.role,
            });
            return Right(loginResponse);
          } else {
            return Left(ServerFailure(message: 'LoginResponse 파싱 실패'));
          }
        }
        // 그 외의 경우
        else {
          DebugLogger.logError(
            '알 수 없는 응답 형식',
            additionalData: {
              'responseKeys': responseData.keys.toList(),
              'responseType': responseData.runtimeType.toString(),
            },
          );
          return Left(ServerFailure(
            message: '잘못된 응답 형식입니다.',
          ));
        }
      } else {
        DebugLogger.logError(
          '비정상적인 응답',
          additionalData: {
            'statusCode': response.statusCode,
            'hasData': response.data != null,
          },
        );
        return Left(ServerFailure(
          message: response.statusMessage ?? '로그인 실패',
        ));
      }
    } on DioException catch (e) {
      DebugLogger.logError(
        'DioException 발생',
        error: e,
        additionalData: {
          'type': e.type.toString(),
          'message': e.message,
          'error': e.error?.toString(),
          'statusCode': e.response?.statusCode,
        },
      );
      
      // ErrorInterceptor에서 변환된 예외 처리
      if (e.error is NetworkException) {
        return Left(NetworkFailure(message: (e.error as NetworkException).message));
      } else if (e.error is UnauthorizedException) {
        return Left(AuthenticationFailure(message: (e.error as UnauthorizedException).message));
      } else if (e.error is ServerException) {
        return Left(ServerFailure(message: (e.error as ServerException).message));
      }
      
      // 기본 DioException 처리
      if (e.response?.statusCode == 401) {
        return Left(AuthenticationFailure(
          message: '자격 증명이 올바르지 않습니다. 이메일과 비밀번호를 확인해주세요.',
        ));
      }
      
      // 네트워크 관련 에러 처리
      if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.sendTimeout ||
          e.type == DioExceptionType.receiveTimeout) {
        return Left(ServerFailure(message: '네트워크 연결 시간이 초과되었습니다. 로그인 중 오류가 발생했습니다.'));
      }
      
      return Left(ServerFailure(message: e.message ?? '로그인 중 오류가 발생했습니다.'));
    } catch (e, stackTrace) {
      DebugLogger.logError(
        '예상치 못한 예외 발생',
        error: e,
        stackTrace: stackTrace,
      );
      return Left(ServerFailure(message: '로그인 중 오류가 발생했습니다.'));
    }
  }

  @override
  Future<Either<Failure, void>> logout(LogoutRequest request) async {
    try {
      final response = await _apiClient.post(
        '/auth/logout',
        data: request.toJson(),
      );

      if (response.statusCode == 200) {
        // API 응답이 { success: bool, data: {...} } 형태인지 확인
        if (response.data is Map && response.data['success'] == true) {
          return const Right(null);
        } else if (response.data == null) {
          // 응답 본문이 없는 경우도 성공으로 처리
          return const Right(null);
        } else {
          return Left(ServerFailure(
            message: '로그아웃 실패',
          ));
        }
      } else {
        return Left(ServerFailure(
          message: response.statusMessage ?? '로그아웃 실패',
        ));
      }
    } catch (e) {
      if (e is ApiException) {
        return Left(ServerFailure(message: e.message));
      }
      return Left(ServerFailure(message: '로그아웃 중 오류가 발생했습니다.'));
    }
  }

  @override
  Future<Either<Failure, TokenResponse>> refreshToken(RefreshTokenRequest request) async {
    try {
      final response = await _apiClient.post(
        '/auth/refresh',
        data: request.toJson(),
      );

      if (response.statusCode == 200 && response.data != null) {
        // API 응답이 { success: bool, data: {...} } 형태인 경우
        final responseData = response.data;
        if (responseData is Map && responseData['success'] == true && responseData['data'] != null) {
          final tokenResponse = TokenResponse.fromJson(responseData['data']);
          return Right(tokenResponse);
        } else {
          return Left(ServerFailure(
            message: '잘못된 응답 형식입니다.',
          ));
        }
      } else {
        return Left(ServerFailure(
          message: response.statusMessage ?? '토큰 갱신 실패',
        ));
      }
    } catch (e) {
      if (e is ApiException) {
        if (e.statusCode == 401) {
          return Left(AuthenticationFailure(
            message: '인증이 만료되었습니다. 다시 로그인해주세요.',
          ));
        }
        return Left(ServerFailure(message: e.message));
      }
      return Left(ServerFailure(message: '토큰 갱신 중 오류가 발생했습니다.'));
    }
  }

  @override
  Future<Either<Failure, AuthUser>> getCurrentAdmin() async {
    try {
      DebugLogger.logApiRequest(url: '/auth/me', method: 'GET');
      
      final response = await _apiClient.get('/auth/me');

      DebugLogger.logApiResponse(
        url: '/auth/me',
        statusCode: response.statusCode,
        data: response.data,
      );

      if (response.statusCode == 200 && response.data != null) {
        final responseData = response.data as Map<String, dynamic>;
        
        // 응답 데이터 구조 검증
        DebugLogger.validateResponseStructure(
          responseData,
          ['id', 'name', 'email'],
          responseName: 'CurrentAdmin',
        );
        
        final authUser = DebugLogger.parseJsonWithLogging(
          responseData,
          AuthUser.fromJson,
          objectName: 'AuthUser',
        );
        
        if (authUser != null) {
          DebugLogger.log(
            'getCurrentAdmin 성공',
            tag: 'API_SUCCESS',
            data: {
              'url': '/auth/me',
              'adminId': authUser.id,
              'adminEmail': authUser.email,
              'adminName': authUser.name,
            },
          );
          return Right(authUser);
        } else {
          return Left(ServerFailure(message: 'AuthUser 파싱 실패'));
        }
      } else {
        return Left(ServerFailure(
          message: response.statusMessage ?? '관리자 정보 조회 실패',
        ));
      }
    } on DioException catch (e) {
      DebugLogger.logError(
        'getCurrentAdmin DioException',
        error: e,
        additionalData: {
          'type': e.type.toString(),
          'statusCode': e.response?.statusCode,
        },
      );
      
      if (e.response?.statusCode == 401) {
        return Left(AuthenticationFailure(
          message: '인증이 필요합니다. 다시 로그인해주세요.',
        ));
      }
      
      return Left(ServerFailure(message: '관리자 정보 조회 중 오류가 발생했습니다.'));
    } catch (e, stackTrace) {
      DebugLogger.logError(
        'getCurrentAdmin 예상치 못한 예외',
        error: e,
        stackTrace: stackTrace,
      );
      return Left(ServerFailure(message: '관리자 정보 조회 중 오류가 발생했습니다.'));
    }
  }

  @override
  Future<Either<Failure, MessageResponse>> changePassword(ChangePasswordRequest request) async {
    try {
      DebugLogger.logApiRequest(url: '/auth/change-password', method: 'POST');
      
      final response = await _apiClient.post(
        '/auth/change-password',
        data: request.toJson(),
      );

      DebugLogger.logApiResponse(
        url: '/auth/change-password',
        statusCode: response.statusCode,
        data: response.data,
      );

      if (response.statusCode == 200 && response.data != null) {
        final responseData = response.data as Map<String, dynamic>;
        
        // 응답 데이터 구조 검증
        DebugLogger.validateResponseStructure(
          responseData,
          ['message'],
          responseName: 'ChangePasswordResponse',
        );
        
        final messageResponse = DebugLogger.parseJsonWithLogging(
          responseData,
          MessageResponse.fromJson,
          objectName: 'MessageResponse',
        );
        
        if (messageResponse != null) {
          DebugLogger.log(
            'changePassword 성공',
            tag: 'API_SUCCESS',
            data: {
              'url': '/auth/change-password',
              'message': messageResponse.message,
            },
          );
          return Right(messageResponse);
        } else {
          return Left(ServerFailure(message: 'MessageResponse 파싱 실패'));
        }
      } else {
        return Left(ServerFailure(
          message: response.statusMessage ?? '비밀번호 변경 실패',
        ));
      }
    } on DioException catch (e) {
      DebugLogger.logError(
        'changePassword DioException',
        error: e,
        additionalData: {
          'type': e.type.toString(),
          'statusCode': e.response?.statusCode,
        },
      );
      
      if (e.response?.statusCode == 401) {
        return Left(AuthenticationFailure(
          message: '기존 비밀번호가 올바르지 않습니다.',
        ));
      } else if (e.response?.statusCode == 400) {
        return Left(ValidationFailure(
          message: '비밀번호 형식이 올바르지 않습니다.',
        ));
      }
      
      return Left(ServerFailure(message: '비밀번호 변경 중 오류가 발생했습니다.'));
    } catch (e, stackTrace) {
      DebugLogger.logError(
        'changePassword 예상치 못한 예외',
        error: e,
        stackTrace: stackTrace,
      );
      return Left(ServerFailure(message: '비밀번호 변경 중 오류가 발생했습니다.'));
    }
  }
}