import 'package:dio/dio.dart';
import '../../core/network/api_client.dart';
import '../../core/storage/storage_service.dart';
import '../../core/constants/app_constants.dart';
import '../../core/errors/app_error.dart';
import '../models/api_response.dart';
import '../models/user_model.dart';

/// 认证服务
class AuthService {
  static final AuthService _instance = AuthService._internal();
  factory AuthService() => _instance;
  AuthService._internal();
  
  final ApiClient _apiClient = ApiClient.instance;
  
  /// 用户注册
  Future<ApiResponse<AuthResponse>> register({
    required String username,
    required String email,
    required String password,
    required String nickname,
    String? phone,
  }) async {
    try {
      final response = await _apiClient.post(
        '/auth/register',
        data: {
          'username': username,
          'email': email,
          'password': password,
          'nickname': nickname,
          if (phone != null) 'phone': phone,
        },
      );
      
      if (response.statusCode == 201) {
        final authResponse = AuthResponse.fromJson(response.data['data']);
        await _saveTokens(authResponse);
        
        return ApiResponse.success(
          message: response.data['message'] ?? '注册成功',
          data: authResponse,
        );
      } else {
        return ApiResponse.failure(
          message: response.data['message'] ?? '注册失败',
          code: response.statusCode,
        );
      }
    } on DioException catch (e) {
      return _handleDioError(e);
    } catch (e) {
      return ApiResponse.failure(
        message: '注册失败：$e',
        error: e.toString(),
      );
    }
  }
  
  /// 用户登录
  Future<ApiResponse<AuthResponse>> login({
    required String account, // 用户名或邮箱
    required String password,
    bool rememberMe = false,
  }) async {
    try {
      final response = await _apiClient.post(
        '/auth/login',
        data: {
          'account': account,
          'password': password,
        },
      );
      
      if (response.statusCode == 200) {
        final authResponse = AuthResponse.fromJson(response.data['data']);
        await _saveTokens(authResponse);
        
        return ApiResponse.success(
          message: response.data['message'] ?? '登录成功',
          data: authResponse,
        );
      } else {
        return ApiResponse.failure(
          message: response.data['message'] ?? '登录失败',
          code: response.statusCode,
        );
      }
    } on DioException catch (e) {
      return _handleDioError(e);
    } catch (e) {
      return ApiResponse.failure(
        message: '登录失败：$e',
        error: e.toString(),
      );
    }
  }
  
  /// 刷新Token
  Future<ApiResponse<AuthResponse>> refreshToken() async {
    try {
      final refreshToken = StorageService.getString(AppConstants.refreshTokenKey);
      if (refreshToken == null) {
        return ApiResponse.failure(
          message: 'Refresh token not found',
          code: 401,
        );
      }
      
      final response = await _apiClient.post(
        '/auth/refresh',
        data: {
          'refresh_token': refreshToken,
        },
      );
      
      if (response.statusCode == 200) {
        final authResponse = AuthResponse.fromJson(response.data['data']);
        await _saveTokens(authResponse);
        
        return ApiResponse.success(
          message: 'Token refreshed successfully',
          data: authResponse,
        );
      } else {
        return ApiResponse.failure(
          message: response.data['message'] ?? 'Token refresh failed',
          code: response.statusCode,
        );
      }
    } on DioException catch (e) {
      return _handleDioError(e);
    } catch (e) {
      return ApiResponse.failure(
        message: 'Token refresh failed: $e',
        error: e.toString(),
      );
    }
  }
  
  /// 用户登出
  Future<ApiResponse<void>> logout() async {
    try {
      final response = await _apiClient.post('/auth/logout');
      
      // 无论服务器响应如何，都清除本地token
      await _clearTokens();
      
      if (response.statusCode == 200) {
        return ApiResponse.success(
          message: response.data['message'] ?? '登出成功',
        );
      } else {
        return ApiResponse.success(
          message: '登出成功',
        );
      }
    } on DioException catch (e) {
      // 即使请求失败，也清除本地token
      await _clearTokens();
      return ApiResponse.success(
        message: '登出成功',
      );
    } catch (e) {
      await _clearTokens();
      return ApiResponse.success(
        message: '登出成功',
      );
    }
  }
  
  /// 获取当前用户信息
  Future<ApiResponse<UserModel>> getCurrentUser() async {
    try {
      final response = await _apiClient.get('/auth/me');
      
      if (response.statusCode == 200) {
        final user = UserModel.fromJson(response.data['data']);
        await StorageService.setObject(AppConstants.userInfoKey, user.toJson());
        
        return ApiResponse.success(
          message: 'User info retrieved successfully',
          data: user,
        );
      } else {
        return ApiResponse.failure(
          message: response.data['message'] ?? 'Failed to get user info',
          code: response.statusCode,
        );
      }
    } on DioException catch (e) {
      return _handleDioError(e);
    } catch (e) {
      return ApiResponse.failure(
        message: 'Failed to get user info: $e',
        error: e.toString(),
      );
    }
  }
  
  /// 更新用户信息
  Future<ApiResponse<UserModel>> updateProfile({
    String? nickname,
    String? avatar,
    String? phone,
    DateTime? birthday,
    String? gender,
    String? bio,
    String? learningLevel,
    String? targetLanguage,
    String? nativeLanguage,
    int? dailyGoal,
  }) async {
    try {
      final data = <String, dynamic>{};
      if (nickname != null) data['nickname'] = nickname;
      if (avatar != null) data['avatar'] = avatar;
      if (phone != null) data['phone'] = phone;
      if (birthday != null) data['birthday'] = birthday.toIso8601String();
      if (gender != null) data['gender'] = gender;
      if (bio != null) data['bio'] = bio;
      if (learningLevel != null) data['learning_level'] = learningLevel;
      if (targetLanguage != null) data['target_language'] = targetLanguage;
      if (nativeLanguage != null) data['native_language'] = nativeLanguage;
      if (dailyGoal != null) data['daily_goal'] = dailyGoal;
      
      final response = await _apiClient.put('/auth/profile', data: data);
      
      if (response.statusCode == 200) {
        final user = UserModel.fromJson(response.data['data']);
        await StorageService.setObject(AppConstants.userInfoKey, user.toJson());
        
        return ApiResponse.success(
          message: response.data['message'] ?? '个人信息更新成功',
          data: user,
        );
      } else {
        return ApiResponse.failure(
          message: response.data['message'] ?? '个人信息更新失败',
          code: response.statusCode,
        );
      }
    } on DioException catch (e) {
      return _handleDioError(e);
    } catch (e) {
      return ApiResponse.failure(
        message: '个人信息更新失败：$e',
        error: e.toString(),
      );
    }
  }
  
  /// 修改密码
  Future<ApiResponse<void>> changePassword({
    required String currentPassword,
    required String newPassword,
    required String confirmPassword,
  }) async {
    try {
      final response = await _apiClient.put(
        '/auth/change-password',
        data: {
          'current_password': currentPassword,
          'new_password': newPassword,
          'confirm_password': confirmPassword,
        },
      );
      
      if (response.statusCode == 200) {
        return ApiResponse.success(
          message: response.data['message'] ?? '密码修改成功',
        );
      } else {
        return ApiResponse.failure(
          message: response.data['message'] ?? '密码修改失败',
          code: response.statusCode,
        );
      }
    } on DioException catch (e) {
      return _handleDioError(e);
    } catch (e) {
      return ApiResponse.failure(
        message: '密码修改失败：$e',
        error: e.toString(),
      );
    }
  }
  
  /// 检查是否已登录
  bool isLoggedIn() {
    final token = StorageService.getString(AppConstants.accessTokenKey);
    return token != null && token.isNotEmpty;
  }
  
  /// 获取本地存储的用户信息
  UserModel? getCachedUser() {
    final userJson = StorageService.getObject(AppConstants.userInfoKey);
    if (userJson != null) {
      try {
        return UserModel.fromJson(userJson);
      } catch (e) {
        print('Error parsing cached user: $e');
        return null;
      }
    }
    return null;
  }
  
  /// 保存tokens
  Future<void> _saveTokens(AuthResponse authResponse) async {
    await StorageService.setString(
      AppConstants.accessTokenKey,
      authResponse.accessToken,
    );
    await StorageService.setString(
      AppConstants.refreshTokenKey,
      authResponse.refreshToken,
    );
    
    if (authResponse.user != null) {
      await StorageService.setObject(
        AppConstants.userInfoKey,
        authResponse.user!,
      );
    }
  }
  
  /// 清除tokens
  Future<void> _clearTokens() async {
    await StorageService.remove(AppConstants.accessTokenKey);
    await StorageService.remove(AppConstants.refreshTokenKey);
    await StorageService.remove(AppConstants.userInfoKey);
  }
  
  /// 处理Dio错误
  ApiResponse<T> _handleDioError<T>(DioException e) {
    switch (e.type) {
      case DioExceptionType.connectionTimeout:
      case DioExceptionType.sendTimeout:
      case DioExceptionType.receiveTimeout:
        return ApiResponse.failure(
          message: '请求超时，请检查网络连接',
          error: 'TIMEOUT',
        );
      case DioExceptionType.badResponse:
        final statusCode = e.response?.statusCode;
        final message = e.response?.data?['message'] ?? '请求失败';
        return ApiResponse.failure(
          message: message,
          code: statusCode,
          error: 'BAD_RESPONSE',
        );
      case DioExceptionType.cancel:
        return ApiResponse.failure(
          message: '请求已取消',
          error: 'CANCELLED',
        );
      case DioExceptionType.connectionError:
        return ApiResponse.failure(
          message: '网络连接失败，请检查网络设置',
          error: 'CONNECTION_ERROR',
        );
      default:
        return ApiResponse.failure(
          message: '未知错误：${e.message}',
          error: 'UNKNOWN',
        );
    }
  }
}