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.concurrent.atomic.AtomicInteger;
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);
            String loadCityName = Objects.isNull(e.getLoadCityName()) ? "" : e.getLoadCityName();
            String unloadCityName = Objects.isNull(e.getUnloadCityName()) ? "" : e.getUnloadCityName();
            String loadDetailAddress = Objects.isNull(e.getLoadDetailAddress()) ? "" : e.getLoadDetailAddress();
            String unloadDetailAddress = Objects.isNull(e.getUnloadDetailAddress()) ? "" : e.getUnloadDetailAddress();
            order.setStatusLabel(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()))
                    .setPickupTypeLabel(DictEnum.getLabel(DictTypeEnum.PICKUP_TYPE.getType(), e.getPickupType()))
                    .setLoadDetailAddressInfo(loadCityName + loadDetailAddress)
                    .setUnloadDetailAddressInfo(unloadCityName + unloadDetailAddress)
                    .setConsignmentStatus(Objects.isNull(e.getEntrustAmount()) || Objects.isNull(e.getAmount())
                            || 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();
        Long userId = LoginUserHolder.getUserId();
        Query query = new Query();
        Criteria criteria = new Criteria();
        String topEnt = Objects.equals(params.getOrderType(), 1) ? "procureTopEntId" : "supplyTopEntId";
        criteria.and(topEnt).is(entId).and("delFlag").is(0);
        //日期范围
        if (Objects.nonNull(params.getStartCreateTime()) && Objects.nonNull(params.getEndCreateTime())) {
            criteria.and("createTime").gte(params.getStartCreateTime()).lte(DateUtil.offsetDay(params.getEndCreateTime(), 1));
        } else if (Objects.nonNull(params.getStartCreateTime())) {
            criteria.and("createTime").gte(params.getStartCreateTime());
        } else if (Objects.nonNull(params.getEndCreateTime())) {
            criteria.and("createTime").lte(DateUtil.offsetDay(params.getEndCreateTime(), 1));
        }
        //装卸货地址
        String loadCode = params.getShippingAddressCode();
        if (StringUtils.isNotBlank(loadCode)) {
            switch (params.getShippingAddressLevel()) {
                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 = params.getUnloadingAddressCode();
        if (StringUtils.isNotBlank(unloadCode)) {
            switch (params.getUnloadingAddressLevel()) {
                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);
            }
        }
        //提货方式
        if (StringUtils.isNotBlank(params.getPickupType())) {
            criteria.and("pickupType").is(params.getPickupType());
        }
        //交易方式
        if (StringUtils.isNotBlank(params.getTrading())) {
            criteria.and("trading").is(params.getTrading());
        }
        //交付类型
        if (StringUtils.isNotBlank(params.getDeliveryType())) {
            criteria.and("deliveryType").is(params.getDeliveryType());
        }
        //下单方式
        if (StringUtils.isNotBlank(params.getSource())) {
            criteria.and("source").is(params.getSource());
        }
        List<Criteria> orOperators = new ArrayList<>();
        //订单状态
        if (Objects.nonNull(params.getStatus()) && !isStatistic) {
            criteria.and("status").is(params.getStatus());
            if (Objects.equals(params.getStatus(), 0)) {
                //草稿状态只能创建订单的人能看
                criteria.and("createBy").is(userId);
            }
        } else {
            //非草稿状态or草稿状态且是当前人且一级企业匹配
            Criteria orOperator = new Criteria().orOperator(
                    Criteria.where("status").ne(0),
                    new Criteria().andOperator(Criteria.where("status").is(0),
                            Criteria.where("createBy").is(userId)));
            orOperators.add(orOperator);
        }
        //关键字模糊匹配
        if (StringUtils.isNotBlank(params.getKeywords())) {
            Pattern pattern = Pattern.compile("^.*" + params.getKeywords() + ".*$", Pattern.CASE_INSENSITIVE);
            Criteria orOperator = new Criteria().orOperator(
                    Criteria.where("tOrderNo").regex(pattern), Criteria.where("procureFirmName").regex(pattern),
                    Criteria.where("supplyFirmName").regex(pattern), Criteria.where("goodsName").regex(pattern));
            orOperators.add(orOperator);
        }
        if (CollectionUtils.isNotEmpty(orOperators)) {
            criteria.andOperator(orOperators);
        }
        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<>();
        TableTop all = new TableTop();
        all.setName("全部").setTotal(CollectionUtils.isEmpty(orders) ? 0 : orders.size());
        tableTops.add(all);
        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();
            String topEnt = Objects.equals(params.getOrderType(), 1) ? "procureTopEntId" : "supplyTopEntId";
            criteria.and("_id").in(ids).and(topEnt).is(entId).and("delFlag").is(0);
            query.addCriteria(criteria);
        } else {
            query = getQuery(params, false);
        }
        query.with(Sort.by(Sort.Order.desc("createTime")));
        List<SckwTradeOrder> orders = mongoTemplate.find(query, SckwTradeOrder.class);
        if (CollectionUtils.isEmpty(orders)) {
            return Collections.emptyList();
        }
        List<TradeOrderListExport> list = new ArrayList<>();
        AtomicInteger i = new AtomicInteger(1);
        orders.forEach(e -> {
            TradeOrderListExport export = BeanUtils.copyProperties(e, TradeOrderListExport.class);
            export.setSerialNumber(String.valueOf(i.getAndIncrement()))
                    .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()))
                    .setLoadDetailAddressInfo(e.getLoadCityName() + e.getUnloadDetailAddress())
                    .setUnloadDetailAddressInfo(e.getUnloadCityName() + e.getUnloadDetailAddress())
                    .setActualAmount(Objects.isNull(e.getActualAmount()) ? "0.00" : String.valueOf(e.getActualAmount()))
                    .setStartTime(Objects.isNull(e.getStartTime()) ? null : DateUtil.dateToStr(e.getStartTime()))
                    .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();
        String topEnt = Objects.equals(params.getOrderType(), 1) ? "procureTopEntId" : "supplyTopEntId";
        criteria.and(topEnt).is(entId).and("status").is(Integer.valueOf(DictEnum.TORDER_STATUS_5.getValue()))
                .and("associateStatement").ne(1).and("delFlag").is(0);
        //排除订单ids
        if (StringUtils.isNotBlank(params.getExcludeIds())) {
            List<Long> ids = StringUtils.splitStrToList(params.getExcludeIds(), ",", Long.class);
            criteria.and("_id").nin(ids);
        }
        //采购企业
        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());
    }

    /**
     * @desc: 合同关联订单列表
     * @author: yzc
     * @date: 2023-07-27 17:05
     * @Param params:
     * @return: com.sckw.core.model.page.PageResult
     */
    public PageResult tradeOrderContractList(TradeOrderContractParam params) {
        Long entId = LoginUserHolder.getEntId();
        Query query = new Query();
        Criteria criteria = new Criteria();
        String topEnt = Objects.equals(params.getOrderType(), 1) ? "procureTopEntId" : "supplyTopEntId";
        List<Long> ids = StringUtils.splitStrToList(params.getContractIds(), ",", Long.class);
        criteria.and("contractId").in(ids).and(topEnt).is(entId).and("delFlag").is(0);
        query.addCriteria(criteria);
        long count = mongoTemplate.count(query, SckwTradeOrder.class);
        Sort sort = Sort.by(Sort.Direction.DESC, "contractId", "createTime");
        SpringDataPageAble pageAble = new SpringDataPageAble(params.getPage(), params.getPageSize(), 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.setStatusLabel(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()))
                    .setPickupTypeLabel(DictEnum.getLabel(DictTypeEnum.PICKUP_TYPE.getType(), e.getPickupType()))
                    .setLoadDetailAddressInfo(e.getLoadCityName() + e.getUnloadDetailAddress())
                    .setUnloadDetailAddressInfo(e.getUnloadCityName() + e.getUnloadDetailAddress())
                    .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(params.getPage(), params.getPageSize(), count, result);
    }
}
