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/friends_list_request.dart';
import 'package:location/data/bean/location_info.dart';
import 'package:location/di/get_it.dart';
import 'package:location/utils/async_util.dart';
import 'package:location/utils/http_handler.dart';
import '../../socket/atmob_location_client.dart';
import '../../utils/atmob_log.dart';
import '../api/request/add_friend_request.dart';
import '../api/request/friends_operation_request.dart';
import '../api/response/electric_query_response.dart';
import '../api/response/friends_list_response.dart';
import '../bean/user_info.dart';

@lazySingleton
class FriendsRepository {
  final String tag = 'FriendsRepository';
  final AtmobApi atmobApi;
  bool refreshFriendsFlag = false;
  final RxList<UserInfo> friendsList = RxList();

  final Rxn<UserInfo> virtualFriendInfo = Rxn<UserInfo>();

  CancelableFuture? refreshVirtualFuture;

  FriendsRepository(this.atmobApi) {
    AtmobLog.d(tag, '$tag....init');

    AtmobLocationClient.addLocationListener((location) {
      updateFriendsLocation(location);
    });
    refreshFriends();
  }

  void updateFriendsLocation(List<LocationInfo> location) {
    if (friendsList.isEmpty || location.isEmpty) {
      return;
    }
    AtmobLog.d('zk', 'updateFriendsLocation');
    final idUserMap = <String, UserInfo>{
      for (final user in friendsList) user.id: user
    };
    for (var datum in location) {
      final user = idUserMap[datum.userId];
      if (user != null) {
        user.lastLocation.value = datum;
      }
    }
  }

  void clearFriends() {
    if (friendsList.isNotEmpty) {
      friendsList.clear();
    }
  }

  Future refreshFriends() async {
    if (refreshFriendsFlag) {
      return;
    }
    refreshFriendsFlag = true;
    return _friendList(0, 300).then((value) {
      friendsList.value = value.friends;
    }).whenComplete(() {
      refreshFriendsFlag = false;
    });
  }

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

  void refreshVirtualFriend() {
    refreshVirtualFuture?.cancel();
    refreshVirtualFuture = AsyncUtil.retry(
        () => _requestVirtualFriend(), Duration(seconds: 3),
        maxRetry: 10);
  }

  Future<UserInfo> _requestVirtualFriend() {
    return atmobApi
        .getFriendVirtual(AppBaseRequest())
        .then(HttpHandler.handle(true))
        .then((value) {
      virtualFriendInfo.value = value;
      return value;
    });
  }

  Future<void> updateFriendBlocked(
      {required String friendId, required bool blocked}) {
    return atmobApi
        .updateFriendBlocked(
            FriendsOperationRequest(friendId: friendId, blocked: blocked))
        .then(HttpHandler.handle(true));
  }

  Future<void> deleteFriend(String friendId) {
    return atmobApi
        .deleteFriend(FriendsOperationRequest(friendId: friendId))
        .then(HttpHandler.handle(true))
        .then((_) {
      refreshFriends();
    });
  }

  Future<void> updateFriendRemark(String friendId, String remark) {
    return atmobApi
        .updateFriendRemark(
            FriendsOperationRequest(friendId: friendId, remark: remark))
        .then(HttpHandler.handle(true));
  }

  Future<void> addFriendRequest(String phone) {
    return atmobApi
        .addFriendRequest(AddFriendRequest(phone))
        .then(HttpHandler.handle(true));
  }

  Future<FriendsListResponse> _friendList(int offset, int limit) {
    return atmobApi
        .friendList(FriendsListRequest(offset: offset, limit: limit))
        .then(HttpHandler.handle(true));
  }

  Future<UserInfo?> getUserInfoFromId(String friendId, {bool? isVirtual}) {
    if (isVirtual == true) {
      return atmobApi
          .getVirtualFromId(FriendsOperationRequest(friendId: friendId))
          .then(HttpHandler.handle(true));
    }
    return atmobApi
        .getUserInfoFromId(FriendsOperationRequest(friendId: friendId))
        .then(HttpHandler.handle(true));
  }

  Future<ElectricQueryResponse> userElectricQuery(String friendId) {
    return atmobApi
        .userElectricQuery(FriendsOperationRequest(friendId: friendId))
        .then(HttpHandler.handle(true));
  }
}
