package com.sckw.transport.service.operateService;

import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.constant.NumberConstant;
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.StringUtils;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.HttpResult;
import com.sckw.excel.utils.DateUtil;
import com.sckw.mongo.model.SckwWaybillOrder;
import com.sckw.mongo.model.TableTops;
import com.sckw.system.api.RemoteUserService;
import com.sckw.transport.model.param.ManagementWaybillOrderQuery;
import com.sckw.transport.model.vo.ManagementCarWaybillVo;
import com.sckw.transport.model.vo.execlVo.ManagementWaybillOrderExcelVO;
import com.sckw.transport.service.KwtCommonService;
import com.sckw.transport.service.KwtWaybillManagementService;
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 java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;

/**
 * @author JC
 * @version 1.0
 * @desc TODO
 * @date 2023/09/12 09:20:21
 **/
@Slf4j
@Service
public class KwtManagementWaybillOrderService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private KwtCommonService commonService;

    @Autowired
    private KwtWaybillManagementService waybillManagementService;

    /**
     * 构造运单关联查询条件
     *
     * @param query 查询参数
     * @param query 权限过滤 相关联的企业
     * @return
     */
    public Criteria newBuildWaybillOrdersQuery(ManagementWaybillOrderQuery query,List<Long> authEntIdList) {
        // 模糊匹配
        // 根据条件查询所有并排序，且分页
        // 设置模糊查询匹配规则  忽略大小写
        // 创建条件对象
        Criteria criteria = new Criteria();
        criteria.and("entId").in(authEntIdList);
        criteria.and("delFlag").is(NumberConstant.ZERO);
        // 运单状态
        if (StringUtils.isNotBlank(query.getStatus()) && (!"all".equals(query.getStatus()))) {
            criteria.and("status").is(Integer.valueOf(query.getStatus()));
        }

        // 派车时间
        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.getStartStartTime()) && Objects.nonNull(query.getEndStartTime())) {
            criteria.and("startTime").gte(query.getStartStartTime()).lte(DateUtil.offsetDay(query.getEndStartTime(), 1));
        } else if (Objects.nonNull(query.getStartStartTime())) {
            criteria.and("startTime").gte(query.getStartStartTime());
        } else if (Objects.nonNull(query.getEndStartTime())) {
            criteria.and("startTime").lte(DateUtil.offsetDay(query.getEndStartTime(), 1));
        }
        // 计划结束时间
        if (Objects.nonNull(query.getStartEndTime()) && Objects.nonNull(query.getEndEndTime())) {
            criteria.and("endTime").gte(query.getStartEndTime()).lte(DateUtil.offsetDay(query.getEndEndTime(), 1));
        } else if (Objects.nonNull(query.getStartEndTime())) {
            criteria.and("endTime").gte(query.getStartEndTime());
        } else if (Objects.nonNull(query.getEndEndTime())) {
            criteria.and("endTime").lte(DateUtil.offsetDay(query.getEndEndTime(), 1));
        }

        // 装载时间
        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.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));
        }

        // 多条件模糊查询
        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;
    }

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
    RemoteUserService remoteUserService;

    /**
     * 运单列表
     *
     * @param query
     * @return
     */
    public HttpResult selectWaybillOrder(ManagementWaybillOrderQuery query) {
        List<ManagementCarWaybillVo> returnList = new ArrayList<>();

        //客户经理权限过滤
        List<Long> authEntIdList = LoginUserHolder.getAuthEntIdList();
        if (CollectionUtils.isEmpty(authEntIdList)) {
            List<Long> ids = remoteUserService.findEnterpriseIdsByUserIdIsMain(LoginUserHolder.getUserId());
            if (CollectionUtils.isEmpty(ids)){
                PageResult build = PageResult.build(query.getPage(), query.getPageSize(), 0L, returnList);
                return HttpResult.ok(build);
            }
            authEntIdList.addAll(ids);
        }

        Criteria criteria = newBuildWaybillOrdersQuery(query,authEntIdList);

        Query queryFormat = new Query(criteria);
        // in查询
        List<Long> wOrderIds = StringUtils.splitStrToList(query.getIds(), ",", Long.class);
        if (CollectionUtils.isNotEmpty(wOrderIds)) {
            queryFormat.addCriteria(Criteria.where("wOrderId").in(wOrderIds));
        }
        // 总记录数
        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);

        if (CollectionUtils.isNotEmpty(list)) {
            for (SckwWaybillOrder waybillOrder : list) {
                ManagementCarWaybillVo vo = new ManagementCarWaybillVo();
                vo.setLOrderNo(waybillOrder.getLOrderNo() == null ?
                        null : waybillOrder.getLOrderNo());
                vo.setWOrderNo(waybillOrder.getWOrderNo() == null ?
                        null : waybillOrder.getWOrderNo());
                vo.setWOrderId(waybillOrder.getWOrderId() == null ?
                        String.valueOf(waybillOrder.get_id()) : String.valueOf(waybillOrder.getWOrderId()));
                vo.setTruckNo(waybillOrder.getTruckNo());
                vo.setDriverName(waybillOrder.getDriverName() == null ?
                        null : String.valueOf(waybillOrder.getDriverName()));
                vo.setType(String.valueOf(waybillOrder.getType()));
                String typeString = "";
                if (waybillOrder.getType().equals(NumberConstant.ONE)) {
                    typeString = "趟次";
                }
                if (waybillOrder.getType().equals(NumberConstant.TWO)) {
                    typeString = "循环";
                }
                vo.setTypeLabel(typeString);
                vo.setStatus(waybillOrder.getStatus() == null ?
                        null : String.valueOf(waybillOrder.getStatus()));
                vo.setStatusLabel(CarWaybillEnum.getName(waybillOrder.getStatus()));
                // 托量单位
                vo.setUnit(waybillOrder.getUnit() == null ? null : waybillOrder.getUnit());
                if (waybillOrder.getUnit() != null) {
                    Map<String, String> unitType = commonService.getDictData(DictTypeEnum.UNIT_TYPE.getType());
                    String sysDict = unitType.get(waybillOrder.getUnit());
                    vo.setUnitLabel(sysDict);
                }
                vo.setSendCarTime(waybillOrder.getCreateTime() == null ?
                        null : DateUtil.getDateTime(waybillOrder.getCreateTime()));
                vo.setStartTime(waybillOrder.getStartTime() == null ?
                        null : waybillOrder.getStartTime());
                vo.setEndTime(waybillOrder.getEndTime() == null ?
                        null : waybillOrder.getEndTime());
                vo.setEntrustAmount(String.valueOf(waybillOrder.getEntrustAmount()));
                vo.setLoadName(waybillOrder.getLoadName() == null ?
                        null : waybillOrder.getLoadName());
                vo.setLoadAddress((waybillOrder.getLoadCityName() == null ? "" : waybillOrder.getLoadCityName())
                        .concat(waybillOrder.getLoadDetailAddress() == null ? "" : waybillOrder.getLoadDetailAddress()));
                vo.setUnloadName(waybillOrder.getUnloadName() == null ?
                        null : waybillOrder.getUnloadName());
                vo.setUnloadAddress((waybillOrder.getUnloadCityName() == null ? "" : waybillOrder.getUnloadCityName())
                        .concat(waybillOrder.getUnloadDetailAddress() == null ? "" : waybillOrder.getUnloadDetailAddress()));
                vo.setLoadAmount(waybillOrder.getLoadAmount() == null ?
                        null : String.valueOf(waybillOrder.getLoadAmount()));
                vo.setUnloadAmount(waybillOrder.getUnloadAmount() == null ?
                        null : String.valueOf(waybillOrder.getUnloadAmount()));
                vo.setLoadDateTime(waybillOrder.getLoadTime() == null ?
                        null : DateUtil.getDateTime(waybillOrder.getLoadTime()));
                vo.setUnloadDateTime(waybillOrder.getUnloadTime() == null ?
                        null : DateUtil.getDateTime(waybillOrder.getUnloadTime()));
                vo.setCreateTime(waybillOrder.getCreateTime() == null ?
                        null : DateUtil.getDateTime(waybillOrder.getCreateTime()));
                vo.setUpdateTime(waybillOrder.getUpdateTime() == null ?
                        null : DateUtil.getDateTime(waybillOrder.getUpdateTime()));
                // 货损量
                BigDecimal deficitAmount = waybillOrder.getDeficitAmount() == null ?
                        BigDecimal.valueOf(0) : waybillOrder.getDeficitAmount();
                vo.setDeficitAmount(String.valueOf(deficitAmount));
                // 计算扣亏量
                BigDecimal loadAmount = waybillOrder.getLoadAmount() == null ? NumberConstant.ZERO_TWO : waybillOrder.getLoadAmount();
                BigDecimal unloadAmount = waybillOrder.getUnloadAmount() == null ? NumberConstant.ZERO_TWO : waybillOrder.getUnloadAmount();
                BigDecimal deficitRealAmount = commonService.deficitLossAmount(
                        waybillOrder.getLoadAmount(),
                        loadAmount.subtract(unloadAmount),
                        waybillOrder.getLoss(),
                        waybillOrder.getLossUnit()
                );
                vo.setDeficitRealAmount(deficitRealAmount.setScale(2, RoundingMode.HALF_UP).toString());

                vo.setGoodsPriceUnit(waybillOrder.getGoodsPriceUnit() == null ?
                        null : String.valueOf(waybillOrder.getGoodsPriceUnit()));
                returnList.add(vo);
            }
        }
        PageResult build = PageResult.build(query.getPage(), query.getPageSize(), total, returnList);
        return HttpResult.ok(build);
    }

    /**
     * 运单分类统计
     *
     * @param query
     * @return
     */
    public HttpResult statisticsWaybillOrder(ManagementWaybillOrderQuery query) {
        //需要查询的状态
        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());
        statuses.add(CarWaybillEnum.REJECT_ORDER.getCode());


        //客户经理权限过滤
        List<Long> authEntIdList = LoginUserHolder.getAuthEntIdList();
        if (CollectionUtils.isEmpty(authEntIdList)) {
            List<Long> ids = remoteUserService.findEnterpriseIdsByUserIdIsMain(LoginUserHolder.getUserId());
            if (CollectionUtils.isEmpty(ids)){
                //填充默认值
               return getDefaultWaybillOrder(statuses);
            }
            authEntIdList.addAll(ids);
        }

        Criteria criteria = newBuildWaybillOrdersQuery(query,authEntIdList);
        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<>(Global.NUMERICAL_SIXTEEN);
        TableTops topTotal = new TableTops();
        topTotal.setName("全部");
        topTotal.setValue("all");
        topTotal.setTotal(NumberConstant.ZERO);
        listMap.put("all", topTotal);
        for (Integer status : statuses) {
            TableTops top = new TableTops();
            top.setName(CarWaybillEnum.getName(status));
            top.setValue(status.toString());
            top.setTotal(NumberConstant.ZERO);
            listMap.put(status.toString(), top);
        }
        Integer allTotal = 0;
        for (TableTops result : results) {
            if(listMap.containsKey(result.getValue())) {
                listMap.get(result.getValue()).setTotal(result.getTotal());
            }
            allTotal += result.getTotal();
        }
        topTotal.setTotal(allTotal);
        return HttpResult.ok(listMap.values().stream().toList());
    }

    private HttpResult getDefaultWaybillOrder(List<Integer> statuses) {
        List<TableTops> results = new ArrayList<>();
        // 填充默认值
        Map<String,TableTops> listMap = new HashMap<>(Global.NUMERICAL_SIXTEEN);
        TableTops topTotal = new TableTops();
        topTotal.setName("全部");
        topTotal.setValue("all");
        topTotal.setTotal(NumberConstant.ZERO);
        listMap.put("all", topTotal);
        for (Integer status : statuses) {
            TableTops top = new TableTops();
            top.setName(CarWaybillEnum.getName(status));
            top.setValue(status.toString());
            top.setTotal(NumberConstant.ZERO);
            listMap.put(status.toString(), top);
        }
        Integer allTotal = 0;
        for (TableTops result : results) {
            if(listMap.containsKey(result.getValue())) {
                listMap.get(result.getValue()).setTotal(result.getTotal());
            }
            allTotal += result.getTotal();
        }
        topTotal.setTotal(allTotal);
        return HttpResult.ok(listMap.values().stream().toList());
    }

    /**
     * 导出运单列表
     *
     * @param query
     * @return
     */
    public List<ManagementWaybillOrderExcelVO> exportWaybillOrder(ManagementWaybillOrderQuery query) {
        List<ManagementWaybillOrderExcelVO> list = new ArrayList<>();

        //客户经理权限过滤
        List<Long> authEntIdList = LoginUserHolder.getAuthEntIdList();
        if (CollectionUtils.isEmpty(authEntIdList)) {
            List<Long> ids = remoteUserService.findEnterpriseIdsByUserIdIsMain(LoginUserHolder.getUserId());
            if (CollectionUtils.isEmpty(ids)){
                return list;
            }
            authEntIdList.addAll(ids);
        }

        Criteria criteria = newBuildWaybillOrdersQuery(query,authEntIdList);
        Query queryFormat = new Query(criteria);
        // in查询
        List<Long> wOrderIds = StringUtils.splitStrToList(query.getIds(), ",", Long.class);
        if (CollectionUtils.isNotEmpty(wOrderIds)) {
            queryFormat.addCriteria(Criteria.where("wOrderId").in(wOrderIds));
        }
        List<SckwWaybillOrder> wOrders = mongoTemplate.find(queryFormat, SckwWaybillOrder.class);
        AtomicInteger i = new AtomicInteger(1);
        wOrders.forEach(e -> {
            ManagementWaybillOrderExcelVO export = BeanUtils.copyProperties(e, ManagementWaybillOrderExcelVO.class);
            export.setSerialNumber(String.valueOf(i.getAndIncrement()))
                    .setStatus(CarWaybillEnum.getName(e.getStatus()))
                    .setWOrderNo(e.getWOrderNo())
                    .setTruckNo(e.getTruckNo())
                    .setDriverName(e.getDriverName())
                    .setType(e.getType().equals(NumberConstant.ONE) ? "趟次" : "循环")
                    .setSendCarTime(e.getCreateTime() == null ? null : DateUtil.getDateTime(e.getCreateTime()))
                    .setStartTime(e.getStartTime() == null ? null : DateUtil.getDateTime(e.getStartTime()))
                    .setEndTime(e.getEndTime() == null ? null : DateUtil.getDateTime(e.getEndTime()))
                    .setEntrustAmount(String.valueOf(e.getEntrustAmount()))
                    .setLoadName(e.getLoadName())
                    .setLoadAddress((e.getLoadCityName() == null ? "" : e.getLoadCityName())
                            .concat(e.getLoadDetailAddress() == null ? "" : e.getLoadDetailAddress()))
                    .setUnloadName(e.getUnloadName())
                    .setUnloadAddress((e.getUnloadCityName() == null ? "" : e.getUnloadCityName())
                            .concat(e.getUnloadDetailAddress() == null ? "" : e.getUnloadDetailAddress()))
                    .setLoadAmount(String.valueOf(e.getLoadAmount()))
                    .setUnloadAmount(String.valueOf(e.getUnloadAmount()))
                    .setDeficitAmount(String.valueOf(e.getDeficitAmount()))
                    .setLoadDateTime(e.getLoadTime() == null ? null : DateUtil.getDateTime(e.getLoadTime()))
                    .setUnloadDateTime(e.getUnloadTime() == null ? null : DateUtil.getDateTime(e.getUnloadTime()))
                    .setUpdateTime(e.getUpdateTime() == null ? null : DateUtil.getDateTime(e.getUpdateTime()));
            list.add(export);
        });
        return list;
    }

    /**
     * 运单详情
     *
     * @param id
     * @return
     */
    public HttpResult getOrderDetail(Long id) {
        return waybillManagementService.waybillData(id);
    }
}
