package com.sckw.report.service;

import com.sckw.core.common.enums.NumberConstant;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.utils.BeanUtils;
import com.sckw.core.utils.CollectionUtils;
import com.sckw.core.utils.DateUtils;
import com.sckw.core.utils.StringUtils;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.mongo.model.SckwTradeOrder;
import com.sckw.payment.api.dubbo.PaymentDubboService;
import com.sckw.payment.api.model.dto.SettlementMoney;
import com.sckw.product.api.dubbo.GoodsStatisticsService;
import com.sckw.product.api.model.GoodsNumStsParam;
import com.sckw.report.model.dto.WorkbenchOrderStsDTO;
import com.sckw.report.model.vo.TOrderDataStsResVO;
import com.sckw.report.model.vo.WbTOrderDataStsParam;
import com.sckw.report.model.vo.WbTOrderDataStsResVO;
import com.sckw.report.model.vo.WorkbenchPurchaseVO;
import com.sckw.system.api.RemoteSystemService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
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.time.LocalDateTime;
import java.util.*;

/**
 * @desc: 贸易订单统计
 * @author: yzc
 * @date: 2023-09-11 14:33
 */
@Service
@Slf4j
@AllArgsConstructor
public class KwOrderStatisticsService {

    private final MongoTemplate mongoTemplate;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private GoodsStatisticsService goodsStatisticsService;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private PaymentDubboService paymentDubboService;
    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteSystemService remoteSystemService;


    /**
     * @desc: 工作台贸易订单数据统计
     * @author: yzc
     * @date: 2023-09-11 15:32
     * @Param params:
     * @return: com.sckw.report.model.vo.WbTOrderDataStsResVO
     */
    public WbTOrderDataStsResVO workbenchData(WbTOrderDataStsParam params) {
        WbTOrderDataStsResVO res = new WbTOrderDataStsResVO();
        List<TOrderDataStsResVO> list = new ArrayList<>();
        Long entId = LoginUserHolder.getEntId();
        String unit = params.getUnit();
        Integer orderType = params.getOrderType();
        Integer dateType = params.getDateType();
        Date currentStart = DateUtils.getStartTime(dateType, LocalDateTime.now());
        Date lastEnd = DateUtils.getLastEndTime(dateType);
        Date lastStart = DateUtils.getStartTime(dateType, DateUtils.toLocalDateTime(lastEnd));
        //当前数据
        TOrderDataStsResVO currentDataSts = new TOrderDataStsResVO();
        //商品数量
        GoodsNumStsParam goodsNumStsParam = new GoodsNumStsParam();
        goodsNumStsParam.setTopEntId(entId).setUnit(unit);
        Long currentGoodsNum = goodsStatisticsService.getOnShelfGoodsNum(goodsNumStsParam);
        //待付款金额
        SettlementMoney settlement = Objects.equals(orderType, 1) ?
                paymentDubboService.countPurchase(entId, dateType) : paymentDubboService.countSell(entId, dateType);
        //订单统计
        WorkbenchOrderStsDTO currentOrderSts = getOrderStsInfo(orderType, unit, currentStart, null);
        BigDecimal currentAmount = BigDecimal.valueOf(currentOrderSts.getOrderAmount());
        BigDecimal currentPrice = BigDecimal.valueOf(currentOrderSts.getOrderPrice());
        currentDataSts.setType(NumberConstant.ONE)
                .setGoodsNum(currentGoodsNum)
                .setOrderAmount(currentAmount)
                .setOrderPrice(currentPrice)
                .setWaitCollectedPrice(new BigDecimal(settlement.getCurrent()))
                .setNotArrivedAmount(currentAmount.subtract(BigDecimal.valueOf(currentOrderSts.getOrderActualAmount())));
        list.add(currentDataSts);

        //上周/上月数据
        TOrderDataStsResVO lastDataSts = new TOrderDataStsResVO();
        //商品数量
        goodsNumStsParam.setEndDate(lastEnd);
        Long lastGoodsNum = goodsStatisticsService.getOnShelfGoodsNum(goodsNumStsParam);
        //订单统计
        WorkbenchOrderStsDTO lastOrderSts = getOrderStsInfo(orderType, unit, lastStart, lastEnd);
        BigDecimal lastAmount = BigDecimal.valueOf(lastOrderSts.getOrderAmount());
        BigDecimal lastPrice = BigDecimal.valueOf(lastOrderSts.getOrderPrice());
        lastDataSts.setType(NumberConstant.TWO)
                .setGoodsNum(lastGoodsNum)
                .setOrderAmount(lastAmount)
                .setOrderPrice(lastPrice)
                .setWaitCollectedPrice(new BigDecimal(settlement.getBefore()))
                .setNotArrivedAmount(lastAmount.subtract(BigDecimal.valueOf(lastOrderSts.getOrderActualAmount())));
        list.add(lastDataSts);
        res.setTOrderDataStsList(list);
        //商品数量环比
        BigDecimal goodsNumRingRate = getRingRate(new BigDecimal(currentGoodsNum), new BigDecimal(lastGoodsNum));
        boolean goodsNumFlag = goodsNumRingRate.compareTo(BigDecimal.ZERO) >= 0;
        goodsNumRingRate = goodsNumRingRate.abs();
        //订单总量环比
        BigDecimal orderAmountRingRate = getRingRate(currentAmount, lastAmount);
        boolean orderAmountFlag = orderAmountRingRate.compareTo(BigDecimal.ZERO) >= 0;
        orderAmountRingRate = orderAmountRingRate.abs();
        //订单总金额环比
        BigDecimal orderPriceRingRate = getRingRate(currentPrice, lastPrice);
        boolean orderPriceFlag = orderPriceRingRate.compareTo(BigDecimal.ZERO) >= 0;
        orderPriceRingRate = orderPriceRingRate.abs();
        //未到货量环比
        BigDecimal notArrivedAmountRingRate = getRingRate(currentDataSts.getNotArrivedAmount(), lastDataSts.getNotArrivedAmount());
        boolean notArrivedAmountFlag = notArrivedAmountRingRate.compareTo(BigDecimal.ZERO) >= 0;
        notArrivedAmountRingRate = notArrivedAmountRingRate.abs();

        res.setGoodsNumRingRate(goodsNumRingRate)
                .setGoodsNumFlag(goodsNumFlag)
                .setOrderAmountRingRate(orderAmountRingRate)
                .setOrderAmountFlag(orderAmountFlag)
                .setOrderPriceRingRate(orderPriceRingRate)
                .setOrderPriceFlag(orderPriceFlag)
                .setNotArrivedAmountRingRate(notArrivedAmountRingRate)
                .setNotArrivedAmountFlag(notArrivedAmountFlag)
                .setWaitCollectedPriceRingRate(new BigDecimal(settlement.getPercent().replace("%", "")))
                .setWaitCollectedPriceFlag(Objects.equals(settlement.getFlag(), 1));
        return res;
    }

    private BigDecimal getRingRate(BigDecimal current, BigDecimal last) {
        BigDecimal res;
        if (last.compareTo(BigDecimal.ZERO) == 0) {
            res = (current.subtract(last)).compareTo(BigDecimal.ZERO) != 0 ? NumberConstant.ONE_HUNDRED : BigDecimal.ZERO;
        } else {
            res = (current.subtract(last)).multiply(NumberConstant.ONE_HUNDRED).divide(last, 2, RoundingMode.HALF_UP);
        }
        return res;
    }

    /**
     * @desc: 获取订单统计信息
     * @author: yzc
     * @date: 2023-09-11 17:55
     * @Param orderType:
     * @Param unit:
     * @Param start:
     * @Param end:
     * @return: com.sckw.report.model.dto.WorkbenchOrderStsDTO
     */
    private WorkbenchOrderStsDTO getOrderStsInfo(Integer orderType, String unit, Date start, Date end) {
        WorkbenchOrderStsDTO dto = new WorkbenchOrderStsDTO();
        Long entId = LoginUserHolder.getEntId();
        String topEnt = Objects.equals(orderType, 1) ? "procureTopEntId" : "supplyTopEntId";
        Criteria criteria = new Criteria();
        criteria.and(topEnt).is(entId).and("status").nin(0, 2).and("delFlag").is(0);
        if (StringUtils.isNotBlank(unit)) {
            criteria.and("unit").is(unit);
        }
        if (Objects.nonNull(start) && Objects.nonNull(end)) {
            criteria.and("createTime").gte(start).lte(end);
        } else if (Objects.nonNull(start)) {
            criteria.and("createTime").gte(start);
        } else if (Objects.nonNull(end)) {
            criteria.and("createTime").lte(end);
        }
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.group().sum("amount").as("orderAmount")
                        .sum("price").as("orderPrice")
                        .sum("actualAmount").as("orderActualAmount"));
        AggregationResults<WorkbenchOrderStsDTO> aggregate =
                mongoTemplate.aggregate(aggregation, SckwTradeOrder.class, WorkbenchOrderStsDTO.class);
        List<WorkbenchOrderStsDTO> mappedResults = aggregate.getMappedResults();
        if (CollectionUtils.isEmpty(mappedResults)) {
            return dto;
        }
        return mappedResults.get(0);
    }

    /**
     * @desc: 工作台采购订单列表
     * @author: yzc
     * @date: 2023-09-13 19:37
     * @return: java.util.List<com.sckw.report.model.vo.WorkbenchPurchaseVO>
     */
    public List<WorkbenchPurchaseVO> workbenchPurchaseList() {
        Long entId = LoginUserHolder.getEntId();
        Criteria criteria = new Criteria();
        criteria.and("procureTopEntId").is(entId)
                .and("status").nin(0, 2, 7)
                .and("delFlag").is(0);
        Query query = new Query();
        query.addCriteria(criteria)
                .with(Sort.by(Sort.Direction.DESC, "createTime"))
                .limit(10);
        List<SckwTradeOrder> orders = mongoTemplate.find(query, SckwTradeOrder.class);
        if (CollectionUtils.isEmpty(orders)) {
            return Collections.emptyList();
        }
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(List.of(
                DictTypeEnum.UNIT_TYPE.getType(), DictTypeEnum.PRODUCT_NAME_TYPE.getType()));
        Map<String, String> unitMap, goodsNameMap;
        if (CollectionUtils.isNotEmpty(dict)) {
            unitMap = CollectionUtils.isNotEmpty(dict.get(DictTypeEnum.UNIT_TYPE.getType())) ?
                    dict.get(DictTypeEnum.UNIT_TYPE.getType()) : new HashMap<>();
            goodsNameMap = CollectionUtils.isNotEmpty(dict.get(DictTypeEnum.PRODUCT_NAME_TYPE.getType())) ?
                    dict.get(DictTypeEnum.PRODUCT_NAME_TYPE.getType()) : new HashMap<>();
        } else {
            unitMap = new HashMap<>();
            goodsNameMap = new HashMap<>();
        }
        List<WorkbenchPurchaseVO> result = new ArrayList<>();
        orders.forEach(e -> {
            WorkbenchPurchaseVO vo = BeanUtils.copyProperties(e, WorkbenchPurchaseVO.class);
            vo.setUnitLabel(unitMap.get(e.getUnit()))
                    .setAmount(setScale(e.getAmount()))
                    .setGoodsTypeLabel(goodsNameMap.get(e.getGoodsType()));
            result.add(vo);
        });
        return result;
    }


    /**
     * @desc: 设置两位小数
     * @author: yzc
     * @date: 2023-09-26 10:11
     * @Param d:
     * @return: java.lang.BigDecimal
     */
    private BigDecimal setScale(Double d) {
        if (Objects.isNull(d) || BigDecimal.ZERO.compareTo(BigDecimal.valueOf(d)) == 0) {
            return new BigDecimal("0.00");
        }
        return BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP);
    }
}
