package cn.freemud.demo.service.impl;

import cn.freemud.demo.entities.bo.goods.DeliveryConfigBO;
import cn.freemud.demo.entities.bo.goods.ManagerServiceBO;
import cn.freemud.demo.entities.bo.goods.QueryReceiveAddressByIdBO;
import cn.freemud.demo.entities.bo.goods.ReceiveAddressBO;
import cn.freemud.demo.entities.bo.store.GetStoreInfoBO;
import cn.freemud.demo.entities.bo.store.StoreInfoBO;
import cn.freemud.demo.manager.customer.CustomerManager;
import cn.freemud.demo.manager.store.StoreManager;
import cn.freemud.entities.dto.StoreDeliveryInfoDto;
import cn.freemud.entities.vo.ShoppingCartGoodsResponseVo;
import cn.freemud.enums.CreateOrderType;
import cn.freemud.enums.ScopeConfigType;
import cn.freemud.service.delivery.DeliveryFactory;
import cn.freemud.utils.WebUtil;
import com.freemud.application.sdk.api.log.LogThreadLocal;
import com.freemud.application.sdk.api.storecenter.request.StoreInfoRequest;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.awt.geom.Point2D;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

@Service
public class DeliveryService {

    @Autowired
    private CustomerManager customerManager;

    @Autowired
    private StoreManager storeManager;

    @Autowired
    private DeliveryFactory deliveryFactory;

    // 配送费逻辑是否使用旧的
    @Value("${store.delivery.use.old:true}")
    private boolean storeDeliveryUseOld;

    public Long calculateDeliveryAmount(String receiveId, String partnerId, String storeId, Integer orderType, ManagerServiceBO managerServiceBO) {
        Long deliveryAmount = 0L;
        // 如果订单的收获地址为空，且订单是外卖单，返回运费
        // 主要是为了兼容coco不传收获地址，需要获取固定运费的情况
        if (StringUtils.isBlank(receiveId) && !Objects.equals(orderType, CreateOrderType.TAKE_OUT.getCode())) {
            return deliveryAmount;
        }
        if (storeDeliveryUseOld) {
            deliveryAmount = Long.parseLong(getDeliveryAmount(receiveId, partnerId, storeId, managerServiceBO).toString());
        } else {
            deliveryAmount = getNewDeliveryAmount(receiveId, partnerId, storeId, orderType);
        }
        return deliveryAmount;

    }

    private Integer getDeliveryAmount(String receiveId, String partnerId, String storeId, ManagerServiceBO managerServiceBO) {
        String trackingNo = LogThreadLocal.getTrackingNo();
        Integer amount = 0;
        if (StringUtils.isBlank(receiveId)) {
            return amount;
        }
        QueryReceiveAddressByIdBO queryReceive = new QueryReceiveAddressByIdBO();
        queryReceive.setAddressId(receiveId);
        queryReceive.setPartnerId(partnerId);
        //查询会员后货地址经纬度
        ReceiveAddressBO receiveAddressBO = customerManager.queryReceiveAddressById(queryReceive, managerServiceBO.getCustomerService());
        StoreInfoRequest request = new StoreInfoRequest();
        request.setPartnerId(partnerId);
        request.setStoreCode(storeId);
        //查询门店信息，获取门店经纬度
        GetStoreInfoBO getStoreInfoBO = new GetStoreInfoBO();
        getStoreInfoBO.setPartnerId(partnerId);
        getStoreInfoBO.setStoreId(storeId);
        StoreInfoBO storeResponse = storeManager.getStoreInfo(getStoreInfoBO, managerServiceBO.getStoreService());

        //查询门店外卖配送配置
        DeliveryConfigBO deliveryConfigBO = storeManager.findDeliveryConfigByPartnerIdAndStoreId(partnerId, storeId, managerServiceBO.getStoreService());

        StoreDeliveryInfoDto storeDeliveryInfoDto = new StoreDeliveryInfoDto();
        storeDeliveryInfoDto.setPartnerId(partnerId);
        storeDeliveryInfoDto.setStoreId(storeId);
        storeDeliveryInfoDto.setStoreName(storeResponse.getStoreName());
        storeDeliveryInfoDto.setDeliveryLimitAmount(deliveryConfigBO == null ? 0 : deliveryConfigBO.getDeliveryLimitAmount());
        storeDeliveryInfoDto.setDeliveryAmount(deliveryConfigBO == null ? 0 : deliveryConfigBO.getDeliveryAmount());
        storeDeliveryInfoDto.setDefaultDeliveryRange(deliveryConfigBO == null ? 0L : deliveryConfigBO.getDefaultDeliveryRange());
        storeDeliveryInfoDto.setAddRangeAmount(deliveryConfigBO == null ? 0L : deliveryConfigBO.getAddRangeAmount());
        storeDeliveryInfoDto.setAddRangeCount(deliveryConfigBO == null ? 0L : deliveryConfigBO.getAddRangeCount());
        storeDeliveryInfoDto.setPoint2DList(getDeliveryPoint2DList(storeResponse.getDistributionScope()));
        storeDeliveryInfoDto.setDeliveryHoursDay(storeResponse.getDeliveryHoursDay());
        storeDeliveryInfoDto.setLongitude(storeResponse.getLongitude());
        storeDeliveryInfoDto.setLatitude(storeResponse.getLatitude());
        storeDeliveryInfoDto.setScopeConfig(storeResponse.getScopeConfig());
        if (StringUtils.isNotEmpty(storeResponse.getDeliveryRadius())) {
            storeDeliveryInfoDto.setDeliveryRadius(Integer.valueOf(storeResponse.getDeliveryRadius()));
        } else {
            storeDeliveryInfoDto.setDeliveryRadius(0);
        }
        storeDeliveryInfoDto.setEnableTakeaway(true);
        String userLongitude = receiveAddressBO.getLongitude();
        String userLatitude = receiveAddressBO.getLatitude();
        amount = getUserRealDeliveryAmount(storeDeliveryInfoDto, userLongitude, userLatitude).intValue();
        return amount;
    }


    private Long getNewDeliveryAmount(String receiveId, String partnerId, String storeId, Integer orderType) {
        //String trackingNo = LogThreadLocal.getTrackingNo();
        Long amount = 0L;
        // 如果订单的收获地址为空，且订单是外卖单，返回运费
        // 主要是为了兼容coco不传收获地址，需要获取固定运费的情况
        if (StringUtils.isBlank(receiveId) && !Objects.equals(orderType, CreateOrderType.TAKE_OUT.getCode())) {
            return amount;
        }

        cn.freemud.service.delivery.DeliveryService deliveryService = deliveryFactory.getCalculateDeliveryAmount(orderType,receiveId);
        amount = deliveryService.calculateDeliveryAmount(receiveId,partnerId,storeId);

        return amount;
    }

    /**
     * 获取配送范围内集合
     */
    private List<Point2D.Double> getDeliveryPoint2DList(String distributionScope) {
        if (StringUtils.isBlank(distributionScope)) {
            return Collections.emptyList();
        }
        /**
         * 如果点不为整数，返回空
         */
        String[] points = distributionScope.split(",");
        if (points.length % 2 != 0) {
            return Collections.emptyList();
        }
        List<String> pointList = Arrays.asList(points);
        List<Point2D.Double> point2DList = Lists.newArrayList();
        for (int i = 0; i < pointList.size(); i++) {
            Double pointX = Double.parseDouble(pointList.get(i));
            Double pointY = Double.parseDouble(pointList.get(++i));
            point2DList.add(new Point2D.Double(pointX, pointY));
        }
        return point2DList;
    }

    /**
     * 计算用户收货地址实际配送费
     *
     * @param storeDeliveryInfoDto 门店配送信息
     * @param userLongitude        用户地址经度
     * @param userLatitude         用户地址维度
     * @return
     */
    public Long getUserRealDeliveryAmount(StoreDeliveryInfoDto storeDeliveryInfoDto, String userLongitude, String userLatitude) {
        if (!checkUserEnableDelivery(storeDeliveryInfoDto, userLongitude, userLatitude)) {
            return 0L;
        }
        // TODO 用户收货地址距离门店距离 单位米 如果门店没有设置阶层配送费，配送费默认=基础配送费
        if (storeDeliveryInfoDto.getAddRangeCount() == null || storeDeliveryInfoDto.getAddRangeCount() <= 0) {
            return storeDeliveryInfoDto.getDeliveryAmount();
        }
        if (storeDeliveryInfoDto.getAddRangeAmount() == null || storeDeliveryInfoDto.getAddRangeAmount() <= 0) {
            return storeDeliveryInfoDto.getDeliveryAmount();
        }
        double distance = getDistance(storeDeliveryInfoDto.getLongitude(), storeDeliveryInfoDto.getLatitude(),
                userLongitude, userLatitude);
        Long defaultDeliveryRange = storeDeliveryInfoDto.getDefaultDeliveryRange();
        Long deliveryAmount = storeDeliveryInfoDto.getDeliveryAmount();
        Long addRangeCount = storeDeliveryInfoDto.getAddRangeCount();
        Long addRangeAmount = storeDeliveryInfoDto.getAddRangeAmount();
        if (new BigDecimal(distance).compareTo(new BigDecimal(defaultDeliveryRange)) <= 0) {
            return deliveryAmount;
        } else {
            //计算实际配送费
            BigDecimal extraAmount = (new BigDecimal(distance).subtract(new BigDecimal(defaultDeliveryRange)))
                    .divide(new BigDecimal(addRangeCount), 0, BigDecimal.ROUND_UP)
                    .multiply(new BigDecimal(addRangeAmount));
            BigDecimal realAmount = new BigDecimal(deliveryAmount).add(extraAmount);
            return realAmount.longValue();
        }
    }

    /**
     * 判断收货地址是否在配送范围
     *
     * @param storeDeliveryInfoDto 门店配送信息
     * @param userLongitude        用户经度
     * @param userLatitude         用户维度
     * @return
     */
    public boolean checkUserEnableDelivery(StoreDeliveryInfoDto storeDeliveryInfoDto, String userLongitude, String userLatitude) {
        if (!storeDeliveryInfoDto.getEnableTakeaway()) {
            return false;
        }
        //兼容老版本 为空设置默认按自定义配送
        if (storeDeliveryInfoDto.getScopeConfig() == null) {
            storeDeliveryInfoDto.setScopeConfig(ScopeConfigType.DEFINITION.getCode());
        }
        if (ScopeConfigType.getByCode(storeDeliveryInfoDto.getScopeConfig()) == null) {
            return false;
        }
        ScopeConfigType scopeConfigType = ScopeConfigType.getByCode(storeDeliveryInfoDto.getScopeConfig());
        if (ScopeConfigType.RADIUS.equals(scopeConfigType)) {
            if (storeDeliveryInfoDto.getDeliveryRadius() == null || storeDeliveryInfoDto.getDeliveryRadius() <= 0) {
                return false;
            }
            //用户收货地址距离门店距离 单位米
            double distance = getDistance(storeDeliveryInfoDto.getLongitude(), storeDeliveryInfoDto.getLatitude(),
                    userLongitude, userLatitude);
            if (distance > storeDeliveryInfoDto.getDeliveryRadius().doubleValue()) {
                return false;
            }
            return true;
        }
        List<Point2D.Double> points = storeDeliveryInfoDto.getPoint2DList();
        if (CollectionUtils.isEmpty(points)) {
            return false;
        }
        Point2D.Double point2D = new Point2D.Double(Double.parseDouble(userLongitude), Double.parseDouble(userLatitude));
        return WebUtil.IsPtInPoly(point2D, points);
    }

    /**
     * 获取两个点的距离 单位米
     *
     * @param shopLng
     * @param shopLat
     * @param addressLng
     * @param addressLat
     * @return
     */
    public double getDistance(String shopLng, String shopLat, String addressLng, String addressLat) {
        if (StringUtils.isBlank(shopLng) || StringUtils.isBlank(shopLat) || StringUtils.isBlank(addressLng) || StringUtils.isBlank(addressLat)) {
            return 100000;
        }
        return WebUtil.calDistance(Double.valueOf(shopLng), Double.valueOf(shopLat), Double.valueOf(addressLng), Double.valueOf(addressLat));
    }

}
