package com.sckw.report.service;

import com.sckw.core.common.enums.enums.DictEnum;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.model.page.PageResult;
import com.sckw.core.model.vo.TableBottom;
import com.sckw.core.model.vo.TableStatisticRes;
import com.sckw.core.model.vo.TableTop;
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.excel.utils.DateUtil;
import com.sckw.mongo.model.SckwTradeOrder;
import com.sckw.report.dao.SckwTradeOrderRepository;
import com.sckw.report.service.param.*;
import com.sckw.report.service.vo.OrderListRes;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

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

/**
 * @author zk
 * @desc 订单服务
 * @date 2023/7/10 0010
 */
@Service
@Slf4j
@AllArgsConstructor
public class KwOrderService {

    private final SckwTradeOrderRepository sckwOrderRepository;

    private final MongoTemplate mongoTemplate;

    /**
     * @desc: 贸易订单详情
     * @author: yzc
     * @date: 2023-07-14 9:03
     * @Param id:
     * @return: com.sckw.mongo.model.SckwTradeOrder
     */
    public SckwTradeOrder tradeOrderDetail(Long id) {
        Long entId = LoginUserHolder.getEntId();
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.andOperator(Criteria.where("_id").is(id).and("delFlag").is(0));
        criteria.orOperator(Criteria.where("procureTopEntId").is(entId), Criteria.where("supplyTopEntId").is(entId));
        query.addCriteria(criteria);
        return mongoTemplate.findOne(query, SckwTradeOrder.class);
    }

    /**
     * @desc: 贸易订单列表分页查询
     * @author: yzc
     * @date: 2023-07-17 18:04
     * @Param params:
     * @return: com.sckw.core.model.page.PageResult
     */
    public PageResult tradeOrderSelect(TradeOrderListSelectParam params) {
        Query query = getQuery(params, false);
        return getResult(query, params.getPage(), params.getPageSize());
    }

    /**
     * @desc: 获取分页结果
     * @author: yzc
     * @date: 2023-07-20 15:02
     * @Param query:
     * @Param page:
     * @Param pageSize:
     * @return: com.sckw.core.model.page.PageResult
     */
    private PageResult getResult(Query query, int page, int pageSize) {
        long count = mongoTemplate.count(query, SckwTradeOrder.class);
        Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
        SpringDataPageAble pageAble = new SpringDataPageAble(page, pageSize, sort);
        query.with(pageAble);
        List<SckwTradeOrder> list = mongoTemplate.find(query, SckwTradeOrder.class);
        List<OrderListRes> result = new ArrayList<>();
        list.forEach(e -> {
            OrderListRes order = BeanUtils.copyProperties(e, OrderListRes.class);
            order.setStatus(DictEnum.getLabel(DictTypeEnum.TORDER_STATUS.getType(), String.valueOf(e.getStatus())))
                    .setTrading(DictEnum.getLabel(DictTypeEnum.TRADE_TYPE.getType(), e.getTrading()))
                    .setDeliveryType(DictEnum.getLabel(DictTypeEnum.DELIVERY_TYPE.getType(), e.getDeliveryType()))
                    .setPickupType(DictEnum.getLabel(DictTypeEnum.PICKUP_TYPE.getType(), e.getPickupType()))
                    .setConsignmentStatus(Objects.isNull(e.getEntrustAmount()) || e.getEntrustAmount().compareTo(e.getAmount()) < 0 ? "待托运" : "已托运")
                    .setSource(DictEnum.getLabel(DictTypeEnum.TORDER_SOURCE.getType(), e.getSource()));
            result.add(order);
        });
        return PageResult.build(page, pageSize, count, result);
    }

    /**
     * @desc: 组装query
     * @author: yzc
     * @date: 2023-07-17 18:08
     * @Param params:
     * @Param isStatistic:
     * @return: org.springframework.data.mongodb.core.query.Query
     */
    private Query getQuery(TradeOrderListStatisticParam params, Boolean isStatistic) {
        Long entId = LoginUserHolder.getEntId();
        Query query = new Query();
        Criteria andCriteria = new Criteria();
        andCriteria.and("delFlag").is(0);
        if (Objects.equals(params.getOrderType(), 1)) {
            //采购订单
            andCriteria.and("procureTopEntId").is(entId);
        } else {
            //销售订单
            andCriteria.and("supplyTopEntId").is(entId);
        }
        //日期范围
        if (Objects.nonNull(params.getStartCreateTime()) && Objects.nonNull(params.getEndCreateTime())) {
            andCriteria.and("createTime").gte(params.getStartCreateTime()).lte(DateUtil.offsetDay(params.getEndCreateTime(), 1));
        } else if (Objects.nonNull(params.getStartCreateTime())) {
            andCriteria.and("createTime").gte(params.getStartCreateTime());
        } else if (Objects.nonNull(params.getEndCreateTime())) {
            andCriteria.and("createTime").lte(DateUtil.offsetDay(params.getEndCreateTime(), 1));
        }
        //装卸货地址
        String loadCode = params.getShippingAddressCode();
        if (StringUtils.isNotBlank(loadCode)) {
            switch (params.getShippingAddressLevel()) {
                case 1 -> andCriteria.and("loadCityCode")
                        .regex(Pattern.compile("^" + loadCode.substring(0, 2) + ".*$", Pattern.CASE_INSENSITIVE));
                case 2 -> andCriteria.and("loadCityCode")
                        .regex(Pattern.compile("^" + loadCode.substring(0, 4) + ".*$", Pattern.CASE_INSENSITIVE));
                case 3 -> andCriteria.and("loadCityCode").is(loadCode);
            }
        }
        String unloadCode = params.getUnloadingAddressCode();
        if (StringUtils.isNotBlank(unloadCode)) {
            switch (params.getUnloadingAddressLevel()) {
                case 1 -> andCriteria.and("unloadCityCode")
                        .regex(Pattern.compile("^" + unloadCode.substring(0, 2) + ".*$", Pattern.CASE_INSENSITIVE));
                case 2 -> andCriteria.and("unloadCityCode")
                        .regex(Pattern.compile("^" + unloadCode.substring(0, 4) + ".*$", Pattern.CASE_INSENSITIVE));
                case 3 -> andCriteria.and("unloadCityCode").is(unloadCode);
            }
        }
        //提货方式
        if (StringUtils.isNotBlank(params.getPickupType())) {
            andCriteria.and("pickupType").is(params.getPickupType());
        }
        //交易方式
        if (StringUtils.isNotBlank(params.getTrading())) {
            andCriteria.and("trading").is(params.getTrading());
        }
        //交付类型
        if (StringUtils.isNotBlank(params.getDeliveryType())) {
            andCriteria.and("deliveryType").is(params.getDeliveryType());
        }
        //下单方式
        if (StringUtils.isNotBlank(params.getSource())) {
            andCriteria.and("source").is(params.getSource());
        }
        List<Criteria> orCriteriaList = new ArrayList<>();
        //订单状态
        if (Objects.nonNull(params.getStatus()) && !isStatistic) {
            andCriteria.and("status").is(params.getStatus());
            if (Objects.equals(params.getStatus(), Integer.valueOf(DictEnum.TORDER_STATUS_0.getValue()))) {
                //草稿状态只能创建订单的企业能看
                andCriteria.and("entId").is(entId);
            }
        } else {
            //非草稿状态
            andCriteria.and("status").ne(Integer.valueOf(DictEnum.TORDER_STATUS_0.getValue()));
            //or草稿状态且是当前企业
            orCriteriaList.add(Criteria.where("entId").is(entId).and("status")
                    .is(Integer.valueOf(DictEnum.TORDER_STATUS_0.getValue())).and("delFlag").is(0));
        }
        orCriteriaList.add(andCriteria);
        //关键字模糊匹配
        if (StringUtils.isNotBlank(params.getKeywords())) {
            Pattern pattern = Pattern.compile("^.*" + params.getKeywords() + ".*$", Pattern.CASE_INSENSITIVE);
            orCriteriaList.add(Criteria.where("tOrderNo").regex(pattern).and("delFlag").is(0));
            orCriteriaList.add(Criteria.where("procureFirmName").regex(pattern).and("delFlag").is(0));
            orCriteriaList.add(Criteria.where("supplyFirmName").regex(pattern).and("delFlag").is(0));
            orCriteriaList.add(Criteria.where("goodsName").regex(pattern).and("delFlag").is(0));
        }
        Criteria criteria = new Criteria();
        if (CollectionUtils.isNotEmpty(orCriteriaList)) {
            criteria.orOperator(orCriteriaList);
        }
        return query.addCriteria(criteria);
    }

    /**
     * @desc: 贸易订单列表统计查询
     * @author: yzc
     * @date: 2023-07-17 18:05
     * @Param params:
     * @return: com.sckw.core.model.vo.TableStatisticRes
     */
    public TableStatisticRes tradeOrderStatistic(TradeOrderListStatisticParam params) {
        TableStatisticRes res = new TableStatisticRes();
        Query query = getQuery(params, true);
        List<SckwTradeOrder> orders = mongoTemplate.find(query, SckwTradeOrder.class);
        Map<Integer, List<SckwTradeOrder>> map = orders.stream().collect(Collectors.groupingBy(SckwTradeOrder::getStatus));
        List<TableTop> tableTops = new ArrayList<>();
        List<DictEnum> tOrderStatusEnums = DictEnum.getEnumsByType(DictTypeEnum.TORDER_STATUS.getType());
        tOrderStatusEnums.forEach(e -> {
            Integer value = Integer.valueOf(e.getValue());
            List<SckwTradeOrder> list = map.get(value);
            int total = CollectionUtils.isEmpty(list) ? 0 : list.size();
            TableTop tableTop = new TableTop();
            tableTop.setName(e.getLabel()).setValue(value).setTotal(total);
            tableTops.add(tableTop);
        });
        TableBottom tableBottom = new TableBottom();
        tableBottom.setTotal(CollectionUtils.isEmpty(orders) ? 0 : orders.size());
        res.setTableTops(tableTops).setTableBottom(tableBottom);
        return res;
    }

    /**
     * @desc: 贸易订单列表导出
     * @author: yzc
     * @date: 2023-07-17 18:05
     * @Param params:
     * @return: java.util.List<com.sckw.report.service.param.TradeOrderListExport>
     */

    public List<TradeOrderListExport> export(TradeOrderListExportParam params) {
        Query query = new Query();
        if (StringUtils.isNotBlank(params.getIds())) {
            List<Long> ids = StringUtils.splitStrToList(params.getIds(), ",", Long.class);
            Long entId = LoginUserHolder.getEntId();
            Criteria criteria = new Criteria();
            criteria.and("tOrderId").in(ids).and("delFlag").is(0);
            if (Objects.equals(params.getOrderType(), 1)) {
                //采购订单
                criteria.and("procureTopEntId").is(entId);
            } else {
                //销售订单
                criteria.and("supplyTopEntId").is(entId);
            }
            query.addCriteria(criteria);
        } else {
            query = getQuery(params, false);
        }
        List<SckwTradeOrder> orders = mongoTemplate.find(query, SckwTradeOrder.class);
        if (CollectionUtils.isEmpty(orders)) {
            return Collections.emptyList();
        }
        List<TradeOrderListExport> list = new ArrayList<>();
        orders.forEach(e -> {
            TradeOrderListExport export = BeanUtils.copyProperties(e, TradeOrderListExport.class);
            export.setStatus(DictEnum.getLabel(DictTypeEnum.TORDER_STATUS.getType(), String.valueOf(e.getStatus())))
                    .setTrading(DictEnum.getLabel(DictTypeEnum.TRADE_TYPE.getType(), e.getTrading()))
                    .setDeliveryType(DictEnum.getLabel(DictTypeEnum.DELIVERY_TYPE.getType(), e.getDeliveryType()))
                    .setPickupType(DictEnum.getLabel(DictTypeEnum.PICKUP_TYPE.getType(), e.getPickupType()))
                    .setConsignmentStatus(Objects.equals(e.getAmount(), e.getEntrustAmount()) ? "待托运" : "已托运")
                    .setSource(DictEnum.getLabel(DictTypeEnum.TORDER_SOURCE.getType(), e.getSource()))
                    .setUnitPrice(String.valueOf(e.getUnitPrice())).setPrice(String.valueOf(e.getPrice()))
                    .setAmount(String.valueOf(e.getAmount())).setActualAmount(String.valueOf(e.getActualAmount()))
                    .setActualAmount(Objects.isNull(e.getActualAmount()) ? "0.00" : String.valueOf(e.getActualAmount()))
                    .setStartTime(Objects.isNull(e.getStartTime()) ? null : DateUtil.dateToStr(e.getStartTime()))
                    .setAddedTime(Objects.isNull(e.getEndTime()) ? null : DateUtil.dateToStr(e.getEndTime()))
                    .setCreateTime(DateUtil.getDateTime(e.getCreateTime()));
            list.add(export);
        });
        return list;
    }

    /**
     * @desc: 贸易订单对账单分页列表查询
     * @author: yzc
     * @date: 2023-07-20 15:03
     * @Param params:
     * @return: com.sckw.core.model.page.PageResult
     */
    public PageResult tradeOrderStatementList(TradeOrderStatementList params) {
        Query query = new Query();
        Long entId = LoginUserHolder.getEntId();
        Criteria criteria = new Criteria();
        criteria.and("status").is(Integer.valueOf(DictEnum.TORDER_STATUS_5.getValue())).and("delFlag").is(0);
        if (Objects.equals(params.getOrderType(), 1)) {
            //采购订单
            criteria.and("procureTopEntId").is(entId);
        } else {
            //销售订单
            criteria.and("supplyTopEntId").is(entId);
        }
        //采购企业
        if (Objects.nonNull(params.getProcureEntId())) {
            criteria.and("procureEntId").is(params.getProcureEntId());
        }
        //计划开始时间
        if (Objects.nonNull(params.getStartTime())) {
            criteria.and("startTime").gte(params.getStartTime());
        }
        //计划结束时间
        if (Objects.nonNull(params.getEndTime())) {
            criteria.and("endTime").lte(params.getEndTime());
        }
        //商品税率
        if (Objects.nonNull(params.getGoodsTaxRate())) {
            criteria.and("goodsTaxRate").is(params.getGoodsTaxRate());
        }
        //商品名称
        if (StringUtils.isNotBlank(params.getGoodsName())) {
            Pattern pattern = Pattern.compile("^.*" + params.getGoodsName() + ".*$", Pattern.CASE_INSENSITIVE);
            criteria.and("goodsName").regex(pattern);
        }
        query.addCriteria(criteria);
        return getResult(query, params.getPage(), params.getPageSize());
    }
}
