package cn.freemud.service.impl;

import cn.freemud.constant.ResponseCodeConstant;
import cn.freemud.entities.dto.*;
import cn.freemud.enums.ScopeConfigType;
import cn.freemud.redis.RedisCache;
import cn.freemud.service.StoreService;
import cn.freemud.service.thirdparty.StoreClient;
import cn.freemud.utils.*;
import com.freemud.application.sdk.api.base.BaseResponse;
import com.freemud.application.sdk.api.log.LogThreadLocal;
import com.freemud.application.sdk.api.storecenter.request.vo.GetOrgTreeListRequest;
import com.freemud.application.sdk.api.storecenter.service.StoreCenterService;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
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.concurrent.TimeUnit;

@Service
public class StoreServiceImpl implements StoreService {
    private final Integer RESPONSE_SUCCESS_CODE = 100;

    private static Gson gson = new Gson();

    @Autowired
    private StoreClient storeClient;
    @Autowired
    private RedisCache redisCache;

    /**
     *  查询商户下的所有门店，按照距离排序缓存1分钟
     * @param nearStoreRequestDto
     * @return
     */
    @Override
    public List<StoreResponseDto> findNearStores(NearStoreRequestDto nearStoreRequestDto) {
        NearStoreRequestDto requestDto = new NearStoreRequestDto();
        BeanUtil.convertBean(nearStoreRequestDto, requestDto);
        requestDto.setPageNo(1);
        requestDto.setPageSize(9999);
        double lat = Double.valueOf(requestDto.getLatitude());
        double lng = Double.valueOf(requestDto.getLongitude());
        String geoHashCode = new GeoHash().encode(lat, lng);
        // 取前6位匹配缓存，精确到0.61公里
        String nearStoreKey = "saas:store:info:" + requestDto.getPartnerId() + ":" + geoHashCode.substring(0, 6);
        List<StoreResponseDto> storeListResponseDtos = redisCache.getValue(nearStoreKey);
        if (CollectionUtils.isNotEmpty(storeListResponseDtos)) {
            return storeListResponseDtos;
        }
        StoreBaseResponseDto<StoreListResponseDto> response = storeClient.findNearStores(requestDto);
        if (!RESPONSE_SUCCESS_CODE.equals(response.getStatusCode())) {
            LogUtil.info("findNearStores_error", gson.toJson(requestDto), gson.toJson(response));
            return Collections.emptyList();
        }
        StoreListResponseDto storeListResponseDto = response.getBizVO();
        if (CollectionUtils.isEmpty(storeListResponseDto.getList())) {
            return Collections.emptyList();
        }
        List<StoreResponseDto> list = storeListResponseDto.getList();

        redisCache.save(nearStoreKey, list, 1L, TimeUnit.MINUTES);
        return storeListResponseDto.getList();
    }



    /**
     * 通过用户地址获取实际配送信息
     *
     * @param storeDeliveryInfoDto 门店配送信息
     * @param userLongitude        用户配送地址经度
     * @param userLatitude         用户配送地址维度
     * @return
     */
    public UserDeliveryInfoDto getUserDeliveryInfo(StoreDeliveryInfoDto storeDeliveryInfoDto, String userLongitude, String userLatitude) {
        UserDeliveryInfoDto userDeliveryInfoDto = UserDeliveryInfoDto.builder()
                .userLongitude(userLongitude)
                .userLatitude(userLatitude)
                .deliveryLimitAmount(storeDeliveryInfoDto.getDeliveryLimitAmount())
                .userEnableTakeaway(checkUserEnableDelivery(storeDeliveryInfoDto, userLongitude, userLatitude))
                .realDeliveryAmount(getUserRealDeliveryAmount(storeDeliveryInfoDto, userLongitude, userLatitude))
                .storeId(storeDeliveryInfoDto.getStoreId())
                .storeName(storeDeliveryInfoDto.getStoreName())
                .storeDeliveryInfoDto(storeDeliveryInfoDto).build();
        return userDeliveryInfoDto;

    }

    /**
     * 判断收货地址是否在配送范围
     *
     * @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 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 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));
    }

    /**
     * 查询门店的组织机构
     * @param partnerId
     * @param storeCode
     * @return
     */
    public List<String> getOrgIds(String partnerId, String storeCode) {
        GetOrgTreeListRequest request = new GetOrgTreeListRequest();
        request.setPartnerId(partnerId);
        request.setStoreCode(storeCode);
        StoreCenterService storeCenterService = SpringBeanUtil.getBean(StoreCenterService.class);
        BaseResponse<List<String>> orgList = storeCenterService.getOrgList(request, LogThreadLocal.getTrackingNo());
        if (orgList != null && ResponseCodeConstant.RESPONSE_SUCCESS_STR.equals(orgList.getCode())) {
            return orgList.getData();
        }
        return null;
    }

    public String[] getOrgIdsArr(String partnerId, String storeCode) {
        List<String> orgIdsList = getOrgIds(partnerId, storeCode);
        if (CollectionUtils.isNotEmpty(orgIdsList)) {
            return orgIdsList.toArray(new String[orgIdsList.size()]);
        }
        return null;
    }
}
