import 'dart:async';

import 'package:get/get.dart';
import 'package:injectable/injectable.dart';
import 'package:location/base/app_base_request.dart';
import 'package:location/data/api/atmob_api.dart';
import 'package:location/data/api/request/login_request.dart';
import 'package:location/data/api/request/send_code_request.dart';
import 'package:location/data/bean/location_info.dart';
import 'package:location/data/bean/member_status_info.dart';
import 'package:location/data/bean/user_info.dart';
import 'package:location/data/consts/constants.dart';
import 'package:location/data/consts/error_code.dart';
import 'package:location/data/repositories/friends_repository.dart';
import 'package:location/data/repositories/message_repository.dart';
import 'package:location/data/repositories/phone_event_repository.dart';
import 'package:location/data/repositories/urgent_contact_repository.dart';
import 'package:location/di/get_it.dart';
import 'package:location/module/main/today_track_helper.dart';
import 'package:location/push_notification/ios_push_notification_service.dart';
import 'package:location/resource/string.gen.dart';
import 'package:location/socket/atmob_location_client.dart';
import 'package:location/utils/async_util.dart';
import 'package:location/utils/atmob_log.dart';
import 'package:location/utils/http_handler.dart';
import 'package:location/utils/mmkv_util.dart';

import '../../sdk/map/map_helper.dart';
import '../api/request/notification_report_request.dart';
import '../api/request/one_click_login_request.dart';
import '../api/request/user_avatar_update_request.dart';
import '../api/response/login_response.dart';
import '../api/response/member_status_response.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';
  static final String keyAccountLoginUserId = 'key_account_login_user_id';

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

  int? _lastRequestCodeTime;
  int _errorCodeTimes = 0;

  Timer? refreshMemberHandler;
  CancelableFuture? memberStatusFuture;

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

  late final FriendsRepository friendsRepository;
  late final MessageRepository messageRepository;
  late final UrgentContactRepository urgentContactRepository;
  late final PhoneEventRepository phoneEventRepository;

  final Rx<UserInfo> mineUserInfo = Rx<UserInfo>(UserInfo(
      id: Constants.mineLocationId,
      phoneNumber: StringName.locationMine,
      isMine: true));

  AccountRepository(this.atmobApi) {
    AtmobLog.d(tag, '$tag....init');
    friendsRepository = FriendsRepository.getInstance();
    messageRepository = MessageRepository.getInstance();
    urgentContactRepository = UrgentContactRepository.getInstance();
    phoneEventRepository = PhoneEventRepository.getInstance();

    isLogin.bindStream(
      loginPhoneNum.map((value) {
        return value?.isNotEmpty == true;
      }),
    );
    loginPhoneNum.value = KVUtil.getString(keyAccountLoginPhoneNum, null);

    refreshMemberStatus();
    MapHelper.addLocationListener((location) {
      mineUserInfo.value.lastLocation.value =
          LocationInfo.fromMapLocation(location);
    });
  }

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

  Future<void> loginSendCode(String phoneNum) {
    final currentTime = DateTime.now().millisecondsSinceEpoch;

    // 检查是否在 60 秒内重复请求
    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) {
      return Future.error(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 onLoginSuccess(String phoneNum, String authToken) {
    AccountRepository.token = authToken;
    loginPhoneNum.value = phoneNum;

    KVUtil.putString(keyAccountLoginPhoneNum, phoneNum);
    KVUtil.putString(keyAccountLoginToken, authToken);

    AtmobLocationClient.connectWebSocket();

    refreshMemberStatus();
    friendsRepository.refreshFriends();
    messageRepository.refreshFriendWaitingCount();
    messageRepository.refreshUnreadMessage();
    urgentContactRepository.requestUrgentContactList();
    //上传推送token
    onRequestNotificationReport();
    //上报事件
    phoneEventRepository.startReportPhoneEvent();

    TodayTrackHelper.getInstance().clear();
  }

  void logout() {
    token = null;

    refreshMemberHandler?.cancel();

    AtmobLocationClient.disConnectWebSocket();

    KVUtil.putString(keyAccountLoginPhoneNum, null);
    KVUtil.putString(keyAccountLoginToken, null);
    KVUtil.putString(keyAccountLoginUserId, null);
    KVUtil.putString(Constants.keyLastSelectFriendId, null);
    loginPhoneNum.value = null;
    memberStatusInfo.value = null;

    friendsRepository.clearFriends();
    messageRepository.clearMessage();
    urgentContactRepository.clearContactList();

    phoneEventRepository.stopReportPhoneEvent();
  }

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

  Future<MemberStatusResponse> getMemberStatus() {
    return atmobApi
        .getMemberStatus(AppBaseRequest())
        .then(HttpHandler.handle(false))
        .then((response) {
      refreshMemberHandler?.cancel();
      updateAvatar(response.avatar);
      KVUtil.putString(keyAccountLoginUserId, response.deviceId);
      if (!response.permanent && !response.expired) {
        refreshMemberHandler = Timer(
            Duration(
                milliseconds: response.endTimestamp - response.serverTimestamp),
            () => refreshMemberStatus());
      }
      return response;
    }).then((response) {
      MemberStatusInfo memberStatusInfo = MemberStatusInfo(
          level: response.level,
          endTimestamp: response.endTimestamp,
          expired: response.expired,
          permanent: response.permanent,
          trialed: response.trialed,
          avatar: response.avatar,
          trialEndTimestamp: response.trialEndTimestamp);
      this.memberStatusInfo.value = memberStatusInfo;
      return response;
    });
  }

  void updateAvatar(String? avatar) {
    mineUserInfo.value.avatar = avatar;
    mineUserInfo.refresh();
  }

  Future<bool> userAvatarUpdate(String avatar) {
    if (avatar == mineUserInfo.value.avatar) {
      return Future.value(true);
    }
    return atmobApi
        .userAvatarUpdate(UserAvatarUpdateRequest(avatar))
        .then(HttpHandler.handle(true))
        .then((_) {
      updateAvatar(avatar);
      AtmobLog.d(tag, "userAvatarUpdate success: $avatar");
      return true;
    });
  }

  Future<void> oneClickLogin(
      {required String token, required String accessToken}) {
    return atmobApi
        .oneClickLogin(OneClickLoginRequest(token, accessToken))
        .then(HttpHandler.handle(false))
        .then((response) {
      onLoginSuccess(response.phone ?? '', response.authToken);
    });
  }

  bool memberIsExpired() {
    return memberStatusInfo.value == null ||
        memberStatusInfo.value?.expired == true;
  }

  Future<void> userClear() {
    return atmobApi.userClear(AppBaseRequest()).then(HttpHandler.handle(true));
  }

  ///请求推送的数据
  Future<void> onRequestNotificationReport() async {
    // 初始化推送服务
    var tokenStr = await IosPushNotificationService.getDeviceToken();
    print("tokenStrsfsdf---${tokenStr}");
    return atmobApi
        .notificationReport(
            NotificationReportRequest(deviceToken: tokenStr as String))
        .then(HttpHandler.handle(false))
        .then((response) {})
        .catchError((_) {});
  }
}

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;
}
