import 'dart:async';

import 'package:get/get.dart';
import 'package:injectable/injectable.dart';
import 'package:keyboard/data/api/atmob_api.dart';
import 'package:keyboard/data/api/request/user_info_setting_request.dart';
import 'package:keyboard/data/bean/member_info.dart';

import '../../base/app_base_request.dart';
import '../../di/get_it.dart';
import '../../utils/async_util.dart';
import '../../utils/atmob_log.dart';
import '../../utils/http_handler.dart';
import '../../utils/mmkv_util.dart';
import '../api/request/complaint_submit_request.dart';
import '../api/request/login_request.dart';
import '../api/request/send_code_request.dart';
import '../api/response/login_response.dart';
import '../api/response/user_info_response.dart';
import '../consts/error_code.dart';

@lazySingleton
class AccountRepository {
  final AtmobApi atmobApi;
  final String tag = "AccountRepository";
  static final String keyAccountLoginPhoneNum = 'key_account_login_phone_num';
  static final String keyAccountLoginToken = 'key_account_login_token';

  final Rxn<UserInfoResponse> _userInfo = Rxn<UserInfoResponse>();

  Rxn<UserInfoResponse> get userInfo => _userInfo;

  RxnString loginPhoneNum = RxnString();
  RxBool isLogin = RxBool(false);
  Rxn<MemberInfo> memberStatusInfo = Rxn<MemberInfo>();
  RxBool isMember = RxBool(false);

  int? _lastRequestCodeTime;
  int _errorCodeTimes = 0;

  Timer? refreshUserInfoHandler;
  CancelableFuture? userInfoFuture;

  static String? token = KVUtil.getString(keyAccountLoginToken, null);

  AccountRepository(this.atmobApi) {
    AtmobLog.d(tag, '$tag....init');
    isLogin.bindStream(
      loginPhoneNum.map((value) {
        return value?.isNotEmpty == true;
      }),
    );

    loginPhoneNum.value = KVUtil.getString(keyAccountLoginPhoneNum, null);
    refreshUserInfo();
  }

  // 检查是否在 60 秒内重复请求
  Future<void> loginSendCode(String phoneNum) {
    final currentTime = DateTime.now().millisecondsSinceEpoch;
    if (currentTime - (_lastRequestCodeTime ?? 0) < 60 * 1000) {
      throw RequestCodeTooOftenException();
    }
    return atmobApi
        .loginSendCode(SendCodeRequest(phoneNum))
        .then(HttpHandler.handle(true))
        .then((value) {
          _lastRequestCodeTime = currentTime;
          _errorCodeTimes = 0;
        });
  }

  Future<LoginResponse> loginUserLogin(
    String phoneNum,
    String verificationCode,
  ) {
    if (_errorCodeTimes >= 5) {
      throw LoginTooOftenException();
    }
    return atmobApi
        .loginUserLogin(LoginRequest(phoneNum, verificationCode))
        .then(HttpHandler.handle(true))
        .then((response) {
          _errorCodeTimes = 0;
          onLoginSuccess(phoneNum, response.authToken);
          return response;
        })
        .catchError((error) {
          if (error is ServerErrorException &&
              error.code == ErrorCode.verificationCodeError) {
            _errorCodeTimes++;
          }
          throw error;
        });
  }

  void refreshUserInfo() {
    userInfoFuture?.cancel();
    userInfoFuture = AsyncUtil.retryWithExponentialBackoff(
      () => getUserInfo(),
      10,
      predicate: (error) {
        if (error is ServerErrorException) {
          return error.code != ErrorCode.noLoginError;
        }
        return true;
      },
    );
    userInfoFuture
        ?.then((userInfo) {
          AtmobLog.d(tag, "refreshUserInfo success: ${memberStatusInfo.value}");
        })
        .catchError((error) {
          AtmobLog.e(tag, "refreshUserInfo error: $error");
        });
  }

  Future<UserInfoResponse> getUserInfo() {
    return atmobApi
        .getUserInfo(AppBaseRequest())
        .then(HttpHandler.handle(true))
        .then((response) {
          _userInfo.value = response;
          memberStatusInfo.value = response.memberInfo;
          isMember.value = response.memberInfo?.isMember == true;
          return response;
        });
  }

  Future<void> setUserInfo({
    String? name,
    String? birthday,
    int? gender,
    String? imageUrl,
    List<String>? hobbies,
    List<String>? characters,
  }) {
    return atmobApi
        .setUserInfo(
          UserInfoSettingRequest(
            name: name,
            birthday: birthday,
            gender: gender,
            imageUrl: imageUrl,
            hobbies: hobbies,
            characters: characters,
          ),
        )
        .then(HttpHandler.handle(true));
  }

  void onLoginSuccess(String phoneNum, String authToken) {
    AccountRepository.token = authToken;
    loginPhoneNum.value = phoneNum;
    refreshUserInfo();
    KVUtil.putString(keyAccountLoginPhoneNum, phoneNum);
    KVUtil.putString(keyAccountLoginToken, authToken);
  }

  void logout() {
    token = null;

    KVUtil.putString(keyAccountLoginPhoneNum, null);
    KVUtil.putString(keyAccountLoginToken, null);
    memberStatusInfo.value = null;
    isMember.value = false;
    loginPhoneNum.value = null;
  }

  // 意见反馈
  Future<void> complaintSubmit(String? phone, String content) {
    return atmobApi
        .complaintSubmit(ComplaintSubmitRequest(phone, content))
        .then(HttpHandler.handle(true));
  }

  static AccountRepository getInstance() {
    return getIt.get<AccountRepository>();
  }
}

class RequestCodeTooOftenException implements Exception {
  final String message;

  /// 可选的构造函数，支持自定义错误信息
  RequestCodeTooOftenException([this.message = '请求验证码过于频繁']);

  @override
  String toString() => message;
}

class LoginTooOftenException implements Exception {
  final String message;

  /// 可选的构造函数，支持自定义错误信息
  LoginTooOftenException([this.message = '登录过于频繁']);

  @override
  String toString() => message;
}
