package com.sckw.transport.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sckw.core.common.enums.NumberConstant;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.model.enums.CarWaybillEnum;
import com.sckw.core.model.page.PageResult;
import com.sckw.core.utils.BeanUtils;
import com.sckw.core.utils.CollectionUtils;
import com.sckw.core.utils.FileUtils;
import com.sckw.core.utils.StringUtils;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.HttpResult;
import com.sckw.excel.utils.DateUtil;
import com.sckw.fleet.api.RemoteFleetService;
import com.sckw.mongo.model.SckwWaybillOrder;
import com.sckw.mongo.model.TableTops;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.model.dto.res.SysDictResDto;
import com.sckw.system.api.model.dto.res.UserCacheResDto;
import com.sckw.transport.dao.*;
import com.sckw.transport.model.KwtLogisticsOrder;
import com.sckw.transport.model.KwtWaybillOrderTrack;
import com.sckw.transport.model.dto.WayBillDetailDTO;
import com.sckw.transport.model.dto.WaybillOrderDTO;
import com.sckw.transport.model.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.regex.Pattern;

/**
 * @author jc
 * @description 运单相关服务
 * @date 2023-06-29 15:06:45
 */
@Slf4j
@Service
public class WaybillManagementService {

    @DubboReference(version = "1.0.0", group = "design", check = false)
    RemoteFleetService remoteFleetService;

    @DubboReference(version = "2.0.0", group = "design", check = false)
    RemoteSystemService remoteSystemService;

    @Autowired
    public KwtWaybillOrderMapper kwtWaybillOrderMapper;

    @Autowired
    public KwtLogisticsOrderMapper kwtLogisticsOrderMapper;

    @Autowired
    public KwtWaybillOrderAddressMapper kwtWaybillOrderAddressMapper;

    @Autowired
    public KwtWaybillOrderTicketMapper kwtWaybillOrderTicketMapper;

    @Autowired
    public KwtWaybillOrderTrackMapper kwtWaybillOrderTrackMapper;

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 运单详情
     *
     * @param id
     * @return
     */
    public HttpResult waybillData(Long id) {
        WaybillDataVO waybillDataVO = new WaybillDataVO();
        Criteria criteria = new Criteria();
        criteria.and("wOrderId").is(id);
        criteria.and("entId").is(LoginUserHolder.getEntId());
        criteria.and("delFlag").is(NumberConstant.ZERO);
        Query queryFormat = new Query(criteria);
        SckwWaybillOrder info = mongoTemplate.findOne(queryFormat, SckwWaybillOrder.class);
        WayBillDetailDTO wayBillDetailDTO = new WayBillDetailDTO();
        WaybillTicketVO waybillTicketVO = new WaybillTicketVO();
        WaybillCarVO waybillCarVO = new WaybillCarVO();
        if(!ObjectUtils.isEmpty(info)) {
            // 基础信息
            wayBillDetailDTO.setTruckId(info.getTruckId());
            wayBillDetailDTO.setTruckNo(info.getTruckNo());
            wayBillDetailDTO.setDriverId(info.getDriverId());
            wayBillDetailDTO.setDriverName(info.getDriverName());
            wayBillDetailDTO.setDriverPhone(info.getDriverPhone());
            wayBillDetailDTO.setDriverId(info.getDriverId());
            wayBillDetailDTO.setWOrderId(info.getWOrderId());
            wayBillDetailDTO.setWOrderNo(info.getWOrderNo());
            wayBillDetailDTO.setLOrderId(info.getLOrderId());
            wayBillDetailDTO.setLOrderNo(info.getLOrderNo());
            wayBillDetailDTO.setEntrustAmount(String.valueOf(info.getEntrustAmount()));
            wayBillDetailDTO.setType(String.valueOf(info.getType()));
            wayBillDetailDTO.setStartTime(DateUtil.getDateTime(info.getStartTime()));
            wayBillDetailDTO.setEndTime(DateUtil.getDateTime(info.getEndTime()));
            wayBillDetailDTO.setCreateBy(info.getCreateByName());
            wayBillDetailDTO.setGoodsName(info.getGoodsName());
            wayBillDetailDTO.setLoadDetailAddress(info.getLoadCityName().concat(info.getLoadDetailAddress()));
            wayBillDetailDTO.setUnloadDetailAddress(info.getUnloadCityName().concat(info.getUnloadDetailAddress()));
            // 计价方式
            KwtLogisticsOrder kwtLogisticsOrder = kwtLogisticsOrderMapper.selectById(info.getLOrderId());
            if(!ObjectUtils.isEmpty(kwtLogisticsOrder)) {
                SysDictResDto billingMode = remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.CHARGING_TYPE.getType(), kwtLogisticsOrder.getBillingMode());
                if(!ObjectUtils.isEmpty(billingMode)) {
                    wayBillDetailDTO.setPriceType(billingMode.getLabel());
                }
            }
            wayBillDetailDTO.setCheckFirmName(info.getCheckFirmName());
            // 车辆信息
            SysDictResDto truckTypeString = remoteSystemService.queryDictByTypeAndValue(DictTypeEnum.TRUCK_TYPE.getType(), info.getTruckType());
            if(!ObjectUtils.isEmpty(truckTypeString)) {
                waybillCarVO.setType(truckTypeString.getLabel());
            }
            waybillCarVO.setTruckId(String.valueOf(info.getTruckId()));
            waybillCarVO.setTruckNo(info.getTruckNo());
            waybillCarVO.setType(info.getTruckType());
            waybillCarVO.setDriverName(info.getDriverName());
            waybillCarVO.setDriverPhone(info.getDriverPhone());
            waybillCarVO.setDriverId(String.valueOf(info.getTruckId()));
            waybillCarVO.setTrailerNo(info.getTruckTrailerNo());
            // 票据
            waybillTicketVO.setLoadTime(DateUtil.getDateTime(info.getLoadTime()));
            waybillTicketVO.setLoadWeight(String.valueOf(info.getLoadAmount()));
            waybillTicketVO.setLoadUrl(String.valueOf(info.getLoadUrls()));
            waybillTicketVO.setUnloadTime(DateUtil.getDateTime(info.getUnloadTime()));
            waybillTicketVO.setUnloadWeight(String.valueOf(info.getUnloadAmount()));
            waybillTicketVO.setUnloadUrl(String.valueOf(info.getUnloadUrls()));
        }
        List<Integer> statuses = initWaybillIndexStatus();
        // 初始化各状态
        List<WaybillStatusVO> statusVOS = new ArrayList<>();
        statuses.forEach(e -> {
            WaybillStatusVO waybillStatusVO = new WaybillStatusVO();
            waybillStatusVO.setStatus(false);
            waybillStatusVO.setCode(e);
            waybillStatusVO.setDestination(CarWaybillEnum.getName(e));
            statusVOS.add(waybillStatusVO);
        });
        List<KwtWaybillOrderTrack> kwtWaybillOrderTracks = kwtWaybillOrderTrackMapper.selectList(new LambdaQueryWrapper<KwtWaybillOrderTrack>()
                .eq(KwtWaybillOrderTrack::getWOrderId, id));
        List<WaybillTrackVO> waybillTrackVOS = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(kwtWaybillOrderTracks)) {
            List<Long> userIds = new ArrayList<>();
            kwtWaybillOrderTracks.forEach(e -> userIds.add(e.getCreateBy()));
            List<UserCacheResDto> users = remoteSystemService.queryUserCacheByIds(userIds);
            Map<Long, String> usersMap = new HashMap<>();
            users.forEach(e -> usersMap.put(e.getId(), e.getName()));
            for (KwtWaybillOrderTrack kwtWaybillOrderTrack: kwtWaybillOrderTracks) {
                for (WaybillStatusVO statusVO:statusVOS) {
                    if(statusVO.getCode().equals(kwtWaybillOrderTrack.getStatus())) {
                        statusVO.setStatus(true);
                        statusVO.setId(kwtWaybillOrderTrack.getId());
                        statusVO.setCreateTime(DateUtil.getDateTime(kwtWaybillOrderTrack.getCreateTime()));
                        statusVO.setOperateTime(kwtWaybillOrderTrack.getOperateTime() == null
                                ? null : DateUtil.getDateTime(kwtWaybillOrderTrack.getOperateTime()));
                        statusVO.setCreateByName(usersMap.get(kwtWaybillOrderTrack.getCreateBy()) == null
                                ? null : usersMap.get(kwtWaybillOrderTrack.getCreateBy()));
                        break;
                    }
                }
                WaybillTrackVO waybillTrackVO = new WaybillTrackVO();
                waybillTrackVO.setId(String.valueOf(kwtWaybillOrderTrack.getId()))
                        .setRemark(kwtWaybillOrderTrack.getRemark())
                        .setStatus(String.valueOf(kwtWaybillOrderTrack.getStatus()))
                        .setCreateBy(usersMap.get(kwtWaybillOrderTrack.getCreateBy()) == null
                                ? null : usersMap.get(kwtWaybillOrderTrack.getCreateBy()))
                        .setCreateTime(DateUtil.getDateTime(kwtWaybillOrderTrack.getCreateTime()));
                waybillTrackVOS.add(waybillTrackVO);
            }
        }

        waybillDataVO.setAgreement(waybillTicketVO);
        waybillDataVO.setCar(waybillCarVO);
        waybillDataVO.setTransport(wayBillDetailDTO);
        waybillDataVO.setProcess(statusVOS);
        waybillDataVO.setLogs(waybillTrackVOS);
        return HttpResult.ok(waybillDataVO);
    }

    /**
     * 运单看板列表
     * @param query
     * @return
     * @throws Exception
     */
    public HttpResult waybillIndex(WaybillOrderDTO query) throws Exception {
        // mongo查询列数据，不足的数据单独关联表查询
        // 状态查询 status [2-8]
        List<Integer> statuses = initWaybillIndexStatus();
        // 初始化各状态
        List<WaybillStatusVO> statusVOS = new ArrayList<>();
        statuses.forEach(e -> {
            WaybillStatusVO waybillStatusVO = new WaybillStatusVO();
            waybillStatusVO.setStatus(false);
            waybillStatusVO.setCode(e);
            waybillStatusVO.setDestination(CarWaybillEnum.getName(e));
            statusVOS.add(waybillStatusVO);
        });

        Criteria criteria = buildWaybillIndexQuery(query, statuses);
        Query queryFormat = new Query(criteria);
        long total = mongoTemplate.count(queryFormat, SckwWaybillOrder.class);
        queryFormat.with(PageRequest.of(query.getPage() - 1, query.getPageSize(),
                Sort.by(Sort.Order.desc("createTime"))));
        // 执行查询
        List<SckwWaybillOrder> list = mongoTemplate.find(queryFormat, SckwWaybillOrder.class);
        List<WaybillBoardListVO> orders = new ArrayList<>();
        for (SckwWaybillOrder sckwWaybillOrder:list) {
            WaybillBoardListVO waybillBoardListVO = new WaybillBoardListVO();
            waybillBoardListVO.setWOrderId(String.valueOf(sckwWaybillOrder.getWOrderId()));
            waybillBoardListVO.setWOrderNo(String.valueOf(sckwWaybillOrder.getWOrderNo()));
            waybillBoardListVO.setGoodsName(String.valueOf(sckwWaybillOrder.getGoodsName()));
            waybillBoardListVO.setLoadDetailAddress(String.valueOf(sckwWaybillOrder.getLoadDetailAddress()));
            waybillBoardListVO.setUnloadDetailAddress(String.valueOf(sckwWaybillOrder.getUnloadDetailAddress()));
            waybillBoardListVO.setStartTime(DateUtil.getDateTime(sckwWaybillOrder.getStartTime()));
            waybillBoardListVO.setEndTime(DateUtil.getDateTime(sckwWaybillOrder.getEndTime()));
            waybillBoardListVO.setFirmName(String.valueOf(sckwWaybillOrder.getFirmName()));
            waybillBoardListVO.setCreateByName(String.valueOf(sckwWaybillOrder.getCreateByName()));
            waybillBoardListVO.setCreateTime(DateUtil.getDateTime(sckwWaybillOrder.getCreateTime()));
            waybillBoardListVO.setDriverName(String.valueOf(sckwWaybillOrder.getDriverName()));
            waybillBoardListVO.setDriverPhone(String.valueOf(sckwWaybillOrder.getDriverPhone()));
            waybillBoardListVO.setTruckNo(String.valueOf(sckwWaybillOrder.getTruckNo()));
            waybillBoardListVO.setLoadGrossAmount(sckwWaybillOrder.getLoadGrossAmount() != null ? String.valueOf(sckwWaybillOrder.getLoadGrossAmount()) : null);
            waybillBoardListVO.setUnloadGrossAmount(sckwWaybillOrder.getUnloadGrossAmount() != null ? String.valueOf(sckwWaybillOrder.getUnloadGrossAmount()) : null);
            waybillBoardListVO.setLoadUrls(sckwWaybillOrder.getLoadUrls() != null ? FileUtils.getOSSAddressPrefix() + sckwWaybillOrder.getLoadUrls() : null);
            waybillBoardListVO.setUnloadUrls(sckwWaybillOrder.getUnloadUrls() != null ? FileUtils.getOSSAddressPrefix() + sckwWaybillOrder.getUnloadUrls() : null);
            List<WaybillStatusVO> statusVOS2 = new ArrayList<>();
            statusVOS.forEach(e -> {
                WaybillStatusVO temp = new WaybillStatusVO();
                BeanUtils.copyProperties(e, temp);
                statusVOS2.add(temp);
            });
            waybillBoardListVO.setTracks(statusVOS2);
            // 运单进度
            List<KwtWaybillOrderTrack> kwtWaybillOrderTracks = kwtWaybillOrderTrackMapper.selectList(new LambdaQueryWrapper<KwtWaybillOrderTrack>()
                    .eq(KwtWaybillOrderTrack::getWOrderId, sckwWaybillOrder.getWOrderId()));
            if (CollectionUtils.isNotEmpty(kwtWaybillOrderTracks)) {
                List<Long> userIds = new ArrayList<>();
                kwtWaybillOrderTracks.forEach(e -> userIds.add(e.getCreateBy()));
                List<UserCacheResDto> users = remoteSystemService.queryUserCacheByIds(userIds);
                Map<Long, String> usersMap = new HashMap<>();
                users.forEach(e -> usersMap.put(e.getId(), e.getName()));
                waybillBoardListVO.getTracks().forEach(e -> {
                    kwtWaybillOrderTracks.forEach(e2 -> {
                        if(e.getCode().equals(e2.getStatus())) {
                            e.setStatus(true);
                            e.setId(e2.getId());
                            e.setCreateTime(DateUtil.getDateTime(e2.getCreateTime()));
                            e.setCreateByName(usersMap.get(e2.getCreateBy()) == null ? null : usersMap.get(e2.getCreateBy()));
                        }
                    });
                });
            }
            orders.add(waybillBoardListVO);
        }

        PageResult build = PageResult.build(query.getPage(), query.getPageSize(), total, orders);
        return HttpResult.ok(build);
    }

    /**
     *
     * @return
     */
    public  List<Integer> initWaybillIndexStatus() {
        List<Integer> statuses = new ArrayList<>();
        statuses.add(CarWaybillEnum.PENDING_ORDER.getCode());
        statuses.add(CarWaybillEnum.PENDING_VEHICLE.getCode());
        statuses.add(CarWaybillEnum.EXIT_COMPLETED.getCode());
        statuses.add(CarWaybillEnum.WAIT_LOADING.getCode());
        statuses.add(CarWaybillEnum.COMPLETION_LOADING.getCode());
        statuses.add(CarWaybillEnum.WAIT_UNLOADING.getCode());
        statuses.add(CarWaybillEnum.COMPLETION_UNLOADING.getCode());
        statuses.add(CarWaybillEnum.APPROVAL_PASS.getCode());
        return statuses;
    }

    /**
     * 运单看板 查询条件构造
     * @param query
     * @param statuses
     * @return
     */
    public Criteria buildWaybillIndexQuery(WaybillOrderDTO query,List<Integer> statuses) {
        Criteria criteria = new Criteria();
        criteria.and("entId").is(LoginUserHolder.getEntId());
        criteria.and("delFlag").is(NumberConstant.ZERO);

        List<Long> wOrderIds = StringUtils.splitStrToList(query.getIds(), ",", Long.class);
        if (CollectionUtils.isNotEmpty(wOrderIds)) {
            Criteria.where("wOrderId").in(wOrderIds);
        }

        if (StringUtils.isNotBlank(query.getStatus()) && !query.getStatus().equals("all")) {
            criteria.and("status").is(Integer.valueOf(query.getStatus()));
        } else {
            criteria.and("status").in(statuses);
        }
        // 装载时间
        if (Objects.nonNull(query.getStartLoadTime()) && Objects.nonNull(query.getEndLoadTime())) {
            criteria.and("loadTime").gte(query.getStartLoadTime()).lte(DateUtil.offsetDay(query.getEndLoadTime(), 1));
        } else if (Objects.nonNull(query.getStartLoadTime())) {
            criteria.and("loadTime").gte(query.getStartLoadTime());
        } else if (Objects.nonNull(query.getEndLoadTime())) {
            criteria.and("loadTime").lte(DateUtil.offsetDay(query.getEndLoadTime(), 1));
        }
        // 派车时间
        if (Objects.nonNull(query.getStartSendCarTime()) && Objects.nonNull(query.getEndSendCarTime())) {
            criteria.and("sendCarTime").gte(query.getStartSendCarTime()).lte(DateUtil.offsetDay(query.getEndSendCarTime(), 1));
        } else if (Objects.nonNull(query.getStartSendCarTime())) {
            criteria.and("sendCarTime").gte(query.getStartSendCarTime());
        } else if (Objects.nonNull(query.getEndSendCarTime())) {
            criteria.and("sendCarTime").lte(DateUtil.offsetDay(query.getEndSendCarTime(), 1));
        }
        // 卸货时间
        if (Objects.nonNull(query.getStartUnloadTime()) && Objects.nonNull(query.getEndUnloadTime())) {
            criteria.and("unloadTime").gte(query.getStartUnloadTime()).lte(DateUtil.offsetDay(query.getEndUnloadTime(), 1));
        } else if (Objects.nonNull(query.getStartUnloadTime())) {
            criteria.and("unloadTime").gte(query.getStartUnloadTime());
        } else if (Objects.nonNull(query.getEndUnloadTime())) {
            criteria.and("unloadTime").lte(DateUtil.offsetDay(query.getEndUnloadTime(), 1));
        }
        // 装货地址
        String loadCode = query.getLoadCityCode();
        if (StringUtils.isNotBlank(loadCode)) {
            switch (query.getLoadCityCodeLevel()) {
                case 1 -> criteria.and("loadCityCode")
                        .regex(Pattern.compile("^" + loadCode.substring(0, 2) + ".*$", Pattern.CASE_INSENSITIVE));
                case 2 -> criteria.and("loadCityCode")
                        .regex(Pattern.compile("^" + loadCode.substring(0, 4) + ".*$", Pattern.CASE_INSENSITIVE));
                case 3 -> criteria.and("loadCityCode").is(loadCode);
            }
        }
        // 卸货地址
        String unloadCode = query.getUnloadCityCode();
        if (StringUtils.isNotBlank(unloadCode)) {
            switch (query.getUnloadCityCodeLevel()) {
                case 1 -> criteria.and("unloadCityCode")
                        .regex(Pattern.compile("^" + unloadCode.substring(0, 2) + ".*$", Pattern.CASE_INSENSITIVE));
                case 2 -> criteria.and("unloadCityCode")
                        .regex(Pattern.compile("^" + unloadCode.substring(0, 4) + ".*$", Pattern.CASE_INSENSITIVE));
                case 3 -> criteria.and("unloadCityCode").is(unloadCode);
            }
        }
        // 多条件模糊查询
        List<Criteria> orCriteria = new ArrayList<>();
        if (StringUtils.isNotBlank(query.getKeywords())) {
            Pattern pattern = Pattern.compile("^.*" + query.getKeywords() + ".*$", Pattern.CASE_INSENSITIVE);
            orCriteria.add(Criteria.where("wOrderNo").regex(pattern));
            orCriteria.add(Criteria.where("truckNo").regex(pattern));
            orCriteria.add(Criteria.where("driverName").regex(pattern));
            orCriteria.add(Criteria.where("firmName").regex(pattern));
            criteria.orOperator(orCriteria);
        }
        return criteria;
    }

    /**
     *  运单看板TOP
     * @param query
     * @return
     */
    public HttpResult waybillIndexStatistics(WaybillOrderDTO query){
        List<Integer> statuses = initWaybillIndexStatus();
        Criteria criteria = buildWaybillIndexQuery(query, statuses);
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.group("status").count().as("total"),
                Aggregation.project("total").and("value").previousOperation()
        );
        AggregationResults<TableTops> outputTypeCount = mongoTemplate.aggregate(aggregation, SckwWaybillOrder.class, TableTops.class);
        List<TableTops> results = outputTypeCount.getMappedResults();

        Map<String, TableTops> listMap = new HashMap<>();
        TableTops topTotal = new TableTops();
        topTotal.setName("全部");
        topTotal.setValue("all");
        topTotal.setTotal(0);
        listMap.put("all", topTotal);
        statuses.forEach(e -> {
            TableTops top = new TableTops();
            top.setValue(String.valueOf(e));
            top.setTotal(0);
            top.setName(CarWaybillEnum.getName(e));
            listMap.put(String.valueOf(e), top);
        });
        if(CollectionUtils.isNotEmpty(results)) {
            for(TableTops result: results) {
                listMap.get(result.getValue()).setTotal(result.getTotal());
            }
        }
        listMap.get("all").setTotal(listMap.values().parallelStream().mapToInt(e -> e.getTotal()).sum());
        return HttpResult.ok(listMap.values());
    }
}
