package com.prolog.rdc.tms.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.prolog.common.util.ToolKits;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.PrologException;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Order;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.rdc.tms.constant.DataDictionaryConstant;
import com.prolog.rdc.tms.constant.SeriaNnumberConstant;
import com.prolog.rdc.tms.constant.enums.SignInStatusEnum;
import com.prolog.rdc.tms.dao.mapper.*;
import com.prolog.rdc.tms.kuaidi100.ApiInfoConstant;
import com.prolog.rdc.tms.kuaidi100.api.Subscribe;
import com.prolog.rdc.tms.kuaidi100.core.IBaseClient;
import com.prolog.rdc.tms.kuaidi100.dto.*;
import com.prolog.rdc.tms.kuaidi100.util.SignUtils;
import com.prolog.rdc.tms.model.ShipbillRouteDataModel;
import com.prolog.rdc.tms.model.entity.TmsGpsDataModel;
import com.prolog.rdc.tms.model.entity.TmsLoadingBillDetailModel;
import com.prolog.rdc.tms.model.entity.TmsShipbillHeaderModel;
import com.prolog.rdc.tms.model.entity.TmsShipbillPackageModel;
import com.prolog.rdc.tms.model.vo.KD100VO;
import com.prolog.rdc.tms.model.vo.WaitDeliveredDeliveredConfirmVO;
import com.prolog.rdc.tms.rmi.feign.MaindataFeign;
import com.prolog.rdc.tms.service.KD100Service;
import com.prolog.rdc.tms.service.WaitDeliveredService;
import com.prolog.rdc.tms.util.MapUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 快递100接口调用实现层
 *
 * @author :fanzw
 * @version :1.0.0
 * @className :KD100ServiceImpl
 * @creationTime :2022/11/28
 * @description :
 * @modifier :fanzw
 * @modifyTime :2022/11/28
 * @reviseRemarks:
 */
@Slf4j
@Service
public class KD100ServiceImpl implements KD100Service {

    // hbGGDZwW8136
    @Value("${prolog.kuaidi100.key:hbGGDZwW8136}")
    private String kuaiDi100Key;

    @Value("${prolog.kuaidi100.callbackUrl:hbGGDZwW8136}")
    private String callbackUrl;

    @Autowired
    private ShipbillRouteDataMapper shipbillRouteDataMapper;

    @Autowired
    private MaindataFeign maindataTmsResource;

    @Autowired
    private TmsShipbillPackageMapper shipbillPackageMapper;

    @Autowired
    private TmsShipbillHeaderMapper shipbillHeaderMapper;

    @Autowired
    private TmsLoadingBillDetailMapper loadingBillDetailMapper;

    @Autowired
    private WaitDeliveredService waitDeliveredService;

    @Autowired
    private TmsGpsDataMapper tmsGpsDataMapper;

    /**
     * 车辆当前定位V1.0
     *
     * @param
     * @return
     */
    @Override
    public void pickUpSubscribe(List<KD100VO> vos) throws Exception {
        ToolKits.isParamNull(vos, "启运登记订阅请求参数不为空");
        for (KD100VO vo : vos) {
            if (ToolKits.isEmpty(vo.getCarriersCode())) {
                throw new PrologException(StrUtil.format("运单{}没有快递公司编码", vo.getShipbillNo()));
            }
            if (ToolKits.isEmpty(vo.getExpressNumber())) {
                throw new PrologException(StrUtil.format("运单{}没有快递单号", vo.getShipbillNo()));
            }
            SubscribeParameters subscribeParameters = new SubscribeParameters();
            subscribeParameters.setCallbackurl(callbackUrl);
            subscribeParameters.setPhone(vo.getPhone());
            subscribeParameters.setResultv2("4");

            SubscribeParam subscribeParam = new SubscribeParam();
            subscribeParam.setParameters(subscribeParameters);
            subscribeParam.setCompany(vo.getCarriersCode());
            subscribeParam.setNumber(vo.getExpressNumber());
            subscribeParam.setKey(this.kuaiDi100Key);

            SubscribeReq subscribeReq = new SubscribeReq();
            subscribeReq.setSchema(ApiInfoConstant.SUBSCRIBE_SCHEMA);
            subscribeReq.setParam(JSONObject.toJSONString(subscribeParam));

            IBaseClient subscribe = new Subscribe();
            log.info("订阅发送信息:{}",JSONObject.toJSONString(subscribeReq));
            HttpResult rs = subscribe.execute(subscribeReq);
            log.info("订阅返回信息:{}",JSONObject.toJSONString(rs));
            if (!ApiInfoConstant.STATUS_CODE.equals(Integer.valueOf(rs.getStatus()))) {
                throw new PrologException(StrUtil.format("快递单号{}调用启运登记订阅接口失败,", vo.getExpressNumber()));
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public SubscribeResp shipBillRouteReceive(HttpServletRequest request) {
        String param = request.getParameter("param");
        String sign = request.getParameter("sign");

        log.info("快递100订阅推送回调结果|{}|{}", param, sign);
        //String ourSign = SignUtils.sign(param);
        SubscribeResp subscribeResp = new SubscribeResp();
        subscribeResp.setResult(Boolean.TRUE);
        subscribeResp.setReturnCode("200");
        subscribeResp.setMessage("成功");

        SubscribePushParamResp subscribePushParamResp = JSONObject.parseObject(param, SubscribePushParamResp.class);
        SubscribePushResult lastResult = subscribePushParamResp.getLastResult();
        List<ShipbillRouteDataModel> routeDataModels = Lists.newArrayList();

        for (SubscribePushData pushData : lastResult.getData()) {
            ShipbillRouteDataModel routeDataModel = new ShipbillRouteDataModel();
            RestMessage<String> restMessageDetailId = maindataTmsResource.getCodeNumberByCode(SeriaNnumberConstant.SHIPBILL_ROUTE_DATA_ID, "L");
            if (!restMessageDetailId.isSuccess()) {
                log.info("快递单{}获取运单路由表ID失败", lastResult.getNu());
                subscribeResp.setResult(Boolean.FALSE);
                subscribeResp.setReturnCode("500");
                subscribeResp.setMessage("接收数据失败");
                return subscribeResp;
            }
            String id = restMessageDetailId.getData();
            routeDataModel.setId(id);
            routeDataModel.setState(lastResult.getState());
            routeDataModel.setAreaName(pushData.getAreaName());
            routeDataModel.setCarriersCode(lastResult.getCom());
            routeDataModel.setExpressNumber(lastResult.getNu());
            routeDataModel.setCarriersType(1);
            routeDataModel.setRouteDate(pushData.getTime());
            routeDataModel.setRouteTime(DateUtil.parse(pushData.getTime()));
            routeDataModel.setRouteContext(pushData.getContext());
            routeDataModel.setIscheck(lastResult.getIscheck());
            String areaCenter = pushData.getAreaCenter();
            if (ObjectUtil.isNotEmpty(areaCenter)) {
                String[] areas = areaCenter.split(",");
                routeDataModel.setLongitude(areas[0]);
                routeDataModel.setLatitude(areas[1]);
            }
            routeDataModel.setCreatetime(DateUtil.date());
            Criteria criteriaShipbillRouteData = Criteria.forClass(ShipbillRouteDataModel.class);
            Restriction r1 = Restrictions.eq(ShipbillRouteDataModel::getExpressNumber, lastResult.getNu());
            Restriction r2 = Restrictions.eq(ShipbillRouteDataModel::getRouteDate, routeDataModel.getRouteDate());
            criteriaShipbillRouteData.setRestriction(Restrictions.and(r1,r2));
            List<ShipbillRouteDataModel> existsRouteDataModels = shipbillRouteDataMapper.findByCriteria(criteriaShipbillRouteData);

            if (ObjectUtil.isEmpty(existsRouteDataModels) && ObjectUtil.isNotEmpty(routeDataModel.getLatitude())
                    && ObjectUtil.isNotEmpty(routeDataModel.getLongitude())) {
                routeDataModels.add(routeDataModel);
            }
        }
        if (ToolKits.isNotEmpty(routeDataModels)) {
            //shipbillRouteDataMapper.deleteByCriteria(criteriaShipbillRouteData);
            shipbillRouteDataMapper.saveBatch(routeDataModels);
            saveGps(routeDataModels);
        }

        updateSignStatus(lastResult);
        return subscribeResp;
    }

    public void saveGps(List<ShipbillRouteDataModel> routeDataModels,String...gaoDe) {
        List<TmsGpsDataModel> gpsDataModels = Lists.newArrayList();
        for (ShipbillRouteDataModel routeDataModel:routeDataModels) {
            TmsGpsDataModel tmsGpsDataModel = new TmsGpsDataModel();
            tmsGpsDataModel.setId(ToolKits.getUUID());

            Criteria criteriaShipbill = Criteria.forClass(TmsShipbillHeaderModel.class);
            Restriction r1 = Restrictions.likeAll(TmsShipbillHeaderModel::getExpressNumber, routeDataModel.getExpressNumber());
            criteriaShipbill.setRestriction(Restrictions.and(r1));
            List<TmsShipbillHeaderModel> shipbillHeaderModels = shipbillHeaderMapper.findByCriteria(criteriaShipbill);
            if (ToolKits.isEmpty(shipbillHeaderModels)) {
                log.info("快递单{}的运单不存在",routeDataModel.getExpressNumber());
                continue;
            }

            tmsGpsDataModel.setDeviceCode(shipbillHeaderModels.get(0).getShipbillId());
            tmsGpsDataModel.setDeviceName(shipbillHeaderModels.get(0).getShipbillId());
            tmsGpsDataModel.setVehiclePlateNumber(routeDataModel.getExpressNumber());
            if (ObjectUtil.isEmpty(gaoDe)) {
                Map<String, Double> map = MapUtils.bd_decrypt(Double.valueOf(routeDataModel.getLatitude()).doubleValue(), Double.valueOf(routeDataModel.getLongitude()).doubleValue());
                BigDecimal lon = BigDecimal.valueOf(map.get("lon"));
                BigDecimal lat = BigDecimal.valueOf(map.get("lat"));
                tmsGpsDataModel.setLatitude(lat);
                tmsGpsDataModel.setLongitude(lon);
            } else {
                tmsGpsDataModel.setLatitude(BigDecimal.valueOf(Double.valueOf(routeDataModel.getLatitude())));
                tmsGpsDataModel.setLongitude(BigDecimal.valueOf(Double.valueOf(routeDataModel.getLongitude())));
            }
            tmsGpsDataModel.setGpsDate(routeDataModel.getRouteTime());
            tmsGpsDataModel.setEnterpriseId(shipbillHeaderModels.get(0).getEnterpriseId());
            tmsGpsDataModel.setEnterpriseName(shipbillHeaderModels.get(0).getEnterpriseName());

            tmsGpsDataModel.setCreatetime(DateUtil.date());
            tmsGpsDataModel.setUpdatetime(DateUtil.date());
            gpsDataModels.add(tmsGpsDataModel);
        }
        if (ObjectUtil.isNotEmpty(gpsDataModels)) {
            tmsGpsDataMapper.saveBatch(gpsDataModels);
        }
    }

    /*public static void main(String[] args) {
        Map<String, Double> map = MapUtils.bd_decrypt(Double.valueOf("25.879908824977687"),Double.valueOf("114.90347436332169"));

        BigDecimal lon = BigDecimal.valueOf(map.get("lon"));
        BigDecimal lat = BigDecimal.valueOf(map.get("lat"));

        System.out.println("纬度："+lat+",经度：" +lon);
    }*/

    private void updateSignStatus(SubscribePushResult pushResult) {
        if (ToolKits.isEmpty(pushResult) || !"1".equals(pushResult.getIscheck())) {
            log.info("快递单{}没有被签收,不更新签收状态",pushResult.getNu());
            return;
        }
        Criteria criteriaShipbillPackage = Criteria.forClass(TmsShipbillPackageModel.class);
        Restriction r1 = Restrictions.eq(TmsShipbillPackageModel::getExpressNumber, pushResult.getNu());
        criteriaShipbillPackage.setRestriction(Restrictions.and(r1));
        List<TmsShipbillPackageModel> shipbillPackageModels = shipbillPackageMapper.findByCriteria(criteriaShipbillPackage);
        if (ToolKits.isEmpty(shipbillPackageModels)) {
            log.info("快递单{}的包裹不存在",pushResult.getNu());
            return;
        }
        TmsShipbillPackageModel packageModel = shipbillPackageModels.get(0);
        packageModel.setSignInStatus(SignInStatusEnum.SIGN.getCode());
        packageModel.setUpdatetime(DateUtil.date());
        shipbillPackageMapper.update(packageModel);

        r1 = Restrictions.eq(TmsShipbillPackageModel::getShipbillId, packageModel.getShipbillId());
        criteriaShipbillPackage.setRestriction(Restrictions.and(r1));
        List<TmsShipbillPackageModel> allShipbillPackageModels = shipbillPackageMapper.findByCriteria(criteriaShipbillPackage);

        if (allShipbillPackageModels.stream().allMatch(page->SignInStatusEnum.SIGN.getCode().equals(page.getSignInStatus()))) {
            updateShipBill(packageModel.getShipbillId(),SignInStatusEnum.SIGN.getCode());
        } else if (allShipbillPackageModels.stream().anyMatch(page->SignInStatusEnum.SIGN.getCode().equals(page.getSignInStatus()))) {
            updateShipBill(packageModel.getShipbillId(),SignInStatusEnum.PART.getCode());
        }
    }

    private void updateShipBill(String shipBillId,String signInStatus) {
        TmsShipbillHeaderModel shipbillHeaderModel = shipbillHeaderMapper.findById(shipBillId, TmsShipbillHeaderModel.class);
        if (ToolKits.isEmpty(shipbillHeaderModel)) {
            log.info("运单{}不存在",shipBillId);
            return;
        }
        shipbillHeaderModel.setSignInStatus(signInStatus);
        shipbillHeaderModel.setUpdatetime(DateUtil.date());
        shipbillHeaderMapper.update(shipbillHeaderModel);

        Criteria criteriaLoadingBillDetailModel = Criteria.forClass(TmsLoadingBillDetailModel.class);
        Restriction r1 = Restrictions.eq(TmsLoadingBillDetailModel::getShipbillId, shipBillId);
        criteriaLoadingBillDetailModel.setRestriction(Restrictions.and(r1));
        criteriaLoadingBillDetailModel.setOrder(Order.newInstance().desc(new String[] { "createtime" }));
        List<TmsLoadingBillDetailModel> loadingBillDetailModels = loadingBillDetailMapper.findByCriteria(criteriaLoadingBillDetailModel);
        if (ToolKits.isNotEmpty(loadingBillDetailModels)) {
            TmsLoadingBillDetailModel loadingBillDetailModel = loadingBillDetailModels.get(0);
            loadingBillDetailModel.setSignInStatus(signInStatus);
            loadingBillDetailModel.setUpdatetime(DateUtil.date());
            loadingBillDetailMapper.update(loadingBillDetailModel);
        }

        if (SignInStatusEnum.SIGN.getCode().equals(signInStatus)) {
            WaitDeliveredDeliveredConfirmVO confirmVO = new WaitDeliveredDeliveredConfirmVO();
            List<String> ids = Lists.newArrayList();
            ids.add(shipBillId);
            confirmVO.setShipbillIds(ids);
            confirmVO.setDeliveryTime(DateUtil.date());
            confirmVO.setDeliveryStatus(DataDictionaryConstant.DELIVERY_STATUS_SUCCESS);
            confirmVO.setDeliveryMemo("回调接口自动送达");
            confirmVO.setDeliverySignPerson("回调接口自动签收");

            ThreadUtil.execute(() -> waitDeliveredService.autoDeliveredConfirmData(confirmVO));
        }
    }
}
