import '../../../core/network/api_client.dart';
import '../../../core/network/api_endpoints.dart';
import '../../../core/error/exceptions.dart';
import '../../models/capability_model.dart';

class AuthResult {
  final String accessToken;
  final String refreshToken;
  final int expiresIn;
  final UserInfo user;

  AuthResult({
    required this.accessToken,
    required this.refreshToken,
    required this.expiresIn,
    required this.user,
  });

  factory AuthResult.fromJson(Map<String, dynamic> json) {
    return AuthResult(
      accessToken: json['accessToken'] as String,
      refreshToken: json['refreshToken'] as String,
      expiresIn: json['expiresIn'] as int,
      user: UserInfo.fromJson(json['user'] as Map<String, dynamic>),
    );
  }
}

class UserInfo {
  final String accountSequence;
  final String phone;
  final String source;
  final String kycStatus;
  final String? status;
  final String? realName;
  final DateTime? createdAt;
  final DateTime? lastLoginAt;

  UserInfo({
    required this.accountSequence,
    required this.phone,
    required this.source,
    required this.kycStatus,
    this.status,
    this.realName,
    this.createdAt,
    this.lastLoginAt,
  });

  factory UserInfo.fromJson(Map<String, dynamic> json) {
    return UserInfo(
      accountSequence: json['accountSequence'] as String,
      phone: json['phone'] as String,
      source: json['source'] as String,
      kycStatus: json['kycStatus'] as String,
      status: json['status'] as String?,
      realName: json['realName'] as String?,
      createdAt: json['createdAt'] != null
          ? DateTime.parse(json['createdAt'].toString())
          : null,
      lastLoginAt: json['lastLoginAt'] != null
          ? DateTime.parse(json['lastLoginAt'].toString())
          : null,
    );
  }

  bool get isKycVerified => kycStatus == 'VERIFIED';
}

abstract class AuthRemoteDataSource {
  Future<void> sendSmsCode(String phone, String type);
  Future<bool> verifySmsCode(String phone, String code, String type);
  Future<AuthResult> register(String phone, String password, String smsCode);
  Future<AuthResult> loginWithPassword(String phone, String password);
  Future<AuthResult> loginWithSms(String phone, String smsCode);
  Future<String> refreshToken(String refreshToken);
  Future<void> logout(String refreshToken);
  Future<UserInfo> getProfile();
  Future<void> resetPassword(String phone, String smsCode, String newPassword);
  Future<void> changePassword(String oldPassword, String newPassword);
  // 支付密码相关
  Future<bool> getTradePasswordStatus();
  Future<void> setTradePassword(String loginPassword, String tradePassword);
  Future<void> changeTradePassword(String oldTradePassword, String newTradePassword);
  Future<bool> verifyTradePassword(String tradePassword);
  Future<CapabilityMap> getCapabilities();
}

class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
  final ApiClient client;

  AuthRemoteDataSourceImpl({required this.client});

  @override
  Future<void> sendSmsCode(String phone, String type) async {
    try {
      await client.post(
        ApiEndpoints.sendSms,
        data: {'phone': phone, 'type': type},
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<bool> verifySmsCode(String phone, String code, String type) async {
    try {
      final response = await client.post(
        ApiEndpoints.verifySms,
        data: {'phone': phone, 'code': code, 'type': type},
      );
      return response.data['valid'] as bool? ?? false;
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<AuthResult> register(String phone, String password, String smsCode) async {
    try {
      final response = await client.post(
        ApiEndpoints.register,
        data: {'phone': phone, 'password': password, 'smsCode': smsCode},
      );
      return AuthResult.fromJson(response.data as Map<String, dynamic>);
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<AuthResult> loginWithPassword(String phone, String password) async {
    try {
      final response = await client.post(
        ApiEndpoints.login,
        data: {'phone': phone, 'password': password},
      );
      return AuthResult.fromJson(response.data as Map<String, dynamic>);
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<AuthResult> loginWithSms(String phone, String smsCode) async {
    try {
      final response = await client.post(
        ApiEndpoints.loginSms,
        data: {'phone': phone, 'smsCode': smsCode},
      );
      return AuthResult.fromJson(response.data as Map<String, dynamic>);
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<String> refreshToken(String refreshToken) async {
    try {
      final response = await client.post(
        ApiEndpoints.refreshToken,
        data: {'refreshToken': refreshToken},
      );
      return response.data['accessToken'] as String;
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<void> logout(String refreshToken) async {
    try {
      await client.post(
        ApiEndpoints.logout,
        data: {'refreshToken': refreshToken},
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<UserInfo> getProfile() async {
    try {
      final response = await client.get(ApiEndpoints.userProfile);
      return UserInfo.fromJson(response.data as Map<String, dynamic>);
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<void> resetPassword(String phone, String smsCode, String newPassword) async {
    try {
      await client.post(
        ApiEndpoints.resetPassword,
        data: {'phone': phone, 'smsCode': smsCode, 'newPassword': newPassword},
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<void> changePassword(String oldPassword, String newPassword) async {
    try {
      await client.post(
        ApiEndpoints.changePassword,
        data: {'oldPassword': oldPassword, 'newPassword': newPassword},
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<bool> getTradePasswordStatus() async {
    try {
      final response = await client.get(ApiEndpoints.tradePasswordStatus);
      return response.data['hasTradePassword'] as bool? ?? false;
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<void> setTradePassword(String loginPassword, String tradePassword) async {
    try {
      await client.post(
        ApiEndpoints.tradePasswordSet,
        data: {'loginPassword': loginPassword, 'tradePassword': tradePassword},
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<void> changeTradePassword(String oldTradePassword, String newTradePassword) async {
    try {
      await client.post(
        ApiEndpoints.tradePasswordChange,
        data: {'oldTradePassword': oldTradePassword, 'newTradePassword': newTradePassword},
      );
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<bool> verifyTradePassword(String tradePassword) async {
    try {
      final response = await client.post(
        ApiEndpoints.tradePasswordVerify,
        data: {'tradePassword': tradePassword},
      );
      return response.data['valid'] as bool? ?? false;
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  @override
  Future<CapabilityMap> getCapabilities() async {
    try {
      final response = await client.get(ApiEndpoints.userCapabilities);
      final data = response.data;
      if (data is Map<String, dynamic>) {
        return CapabilityMap.fromJson(data);
      }
      return CapabilityMap.defaultAll();
    } catch (e) {
      // fail-open: 获取失败时默认全部开启
      return CapabilityMap.defaultAll();
    }
  }
}
