import 'dart:collection';
import 'dart:math';

import 'package:driverapp/config/config.dart';
import 'package:driverapp/config/shared_pref_kay.dart';
import 'package:driverapp/core/model/StatusModel.dart';
import 'package:driverapp/core/model/order_delivey/request_initiate_order_delivery.dart';
import 'package:driverapp/core/model/order_delivey/request_validate_delivery.dart';
import 'package:driverapp/core/model/orders/pending_orders_res_model.dart';
import 'package:driverapp/core/model/update_driver_location/request_update_driver_location.dart';
import 'package:driverapp/core/service/base_service.dart';
import 'package:driverapp/uitl/app_shared_preferences.dart';
import 'package:driverapp/uitl/utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:latlong/latlong.dart';
import 'package:location/location.dart';
import 'package:shared_preferences/shared_preferences.dart';


class DeliveryTrackingServices extends BaseService {
  var _distanceFilter = 20; // [Meters] (Call update API if distance covered from last location is greater then 'value' )


  Future<ResponseModel>  initiateOrderDelivery(PendingOrdersRes order) async {
    hasError = false;

    var testNumber = "";
    ResponseModel result;
    // var orderRequest = RequestInitiateOrderDelivery(orderNo: order.ePharmacyOrderNo, mobileNumber: testNumber == "" ? order.mobileNumber : testNumber);
    var fullUrl = BASE_URL + INITIATE_DELIVERY + "/${order.ePharmacyOrderNo}/${user.iD}";
    await baseAppClient.simpleGet(fullUrl,
        onSuccess: (dynamic response, int statusCode) {
          result =  ResponseModel(isSuccessful: true,message: null, data: response);
          startLocationUpdate(order.ePharmacyOrderNo);

        }, onFailure: (String error, int statusCode) {
          result =  ResponseModel(isSuccessful: false,message: error,data: null);
        });

    return result;
  }

  Future<ResponseModel> validateDelivery(PendingOrdersRes order, String pinCode) async{
    hasError = false;
    var request = RequestValidateDelivery(orderNo: order.ePharmacyOrderNo, pinCode: pinCode);

    ResponseModel result;
    await baseAppClient.post(VERIFY_DELIVERY,
        onSuccess: (dynamic response, int statusCode) {
          result =  ResponseModel(isSuccessful: true,message: null, data: response);
        }, onFailure: (String error, int statusCode) {
          result =  ResponseModel(isSuccessful: false,message: error,data: null);
        }, body: request.toJson());

    return result;
  }

  _updateDriverLocation(int orderID, LocationData location) async {
    if(location != null){
      debugPrint("Updating driver location");
      var jsonBody = await RequestUpdateDriverLocation(orderID: orderID, location: location).toJson();
      await baseAppClient.post(UPDATE_DRIVER_LOCATION,
          onSuccess: (dynamic response, int statusCode) {

          }, onFailure: (String errorMessage, int statusCode) {
            if(statusCode == 200){
              // Server responded but check failed (stop updating location)
              // stopLocationUpdate(orderID);
              // Show error message that you received in response
            }
          }, body: jsonBody);
    }
  }



  Map _currentRunnings = Map<String,Future>();
  Future<Object> startLocationUpdate(int orderID, {int frequencyInSeconds = 3}) async {
    if (_currentRunnings[orderID.toString()] == null){
      _currentRunnings[orderID.toString()] = Future.doWhile(() async{

        await Future.delayed(Duration(seconds: frequencyInSeconds));
        var valid = _currentRunnings.containsKey(orderID.toString());
        if(valid){
          Utils.possibleToGetLocation((value) async{
            if(value){
              var location = await Utils.getLocation();
              if (_haveEnoughLocationUpdate(location))
                await _updateDriverLocation(orderID, location);
            }
          });
        }
        return valid;
      });
    }

    SharedPreferences.getInstance().then((pref){
      pref.setStringList(ACTIVE_DELIVERIES, _currentRunnings.keys.toList());
    });
  }

  bool isActiveDeliveringOrder(int ePharmacyOrderNo){
    return _currentRunnings.containsKey(ePharmacyOrderNo.toString());
  }

  List<String> getActiveDeliveringOrders(){
    return _currentRunnings.keys.toList(growable: false);
  }

  setActiveDeliveringOrders(List<String> orders){
    orders.forEach((element) {
      if(!_currentRunnings.containsKey(element)){
        _currentRunnings[element] = null;
      }
    });
  }

  clearActiveDeliveringOrders(){
    _currentRunnings.clear();
    SharedPreferences.getInstance().then((pref){
      pref.setStringList(ACTIVE_DELIVERIES, _currentRunnings.keys.toList());
    });
  }


  stopLocationUpdate(int orderID){
    _currentRunnings.remove(orderID.toString());
    SharedPreferences.getInstance().then((pref){
      pref.setStringList(ACTIVE_DELIVERIES, _currentRunnings.keys.toList());
    });
  }

  LocationData _lastLocation;
  bool _haveEnoughLocationUpdate(LocationData location){
    _lastLocation = _lastLocation ?? location;
    var distanceCovered = Utils.distanceBetween(_lastLocation, location, LengthUnit.Meter);
    // debugPrint("distance: $distanceCovered");
    return (distanceCovered > _distanceFilter);
  }

}
