package com.czg.service.order.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ReflectUtil;
import com.czg.order.entity.OrderInfo;
import com.czg.order.entity.ShopOrderStatistic;
import com.czg.order.enums.PayEnums;
import com.czg.order.param.DataSummaryProductSaleParam;
import com.czg.order.param.DataSummaryTradeParam;
import com.czg.order.service.DataSummaryService;
import com.czg.order.vo.DataSummaryDateAmountVo;
import com.czg.order.vo.DataSummaryPayTypeVo;
import com.czg.order.vo.DataSummaryProductSaleRankingVo;
import com.czg.service.order.mapper.OrderInfoMapper;
import com.czg.service.order.mapper.ShopOrderStatisticMapper;
import com.czg.service.order.mapper.ShopProdStatisticMapper;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 数据统计Service实现类
 *
 * @author tankaikai
 * @since 2025-03-07 15:32
 */
@Service
public class DataSummaryServiceImpl implements DataSummaryService {

    @Resource
    private ShopOrderStatisticMapper shopOrderStatisticMapper;
    @Resource
    private OrderInfoMapper orderInfoMapper;
    @Resource
    private ShopProdStatisticMapper shopProdStatisticMapper;

    @Override
    public ShopOrderStatistic getTradeData(DataSummaryTradeParam param) {
        List<String> funs = Arrays.asList("getPayTypeAmountCount", "getVipRechargeAmountCount", "getNewMemberCount", "getCustomerUnitPrice", "getTableTurnoverRate");
        Map<String, Object> collect = funs.parallelStream().collect(Collectors.toMap(fun -> fun, fun ->
                ReflectUtil.invoke(shopOrderStatisticMapper, fun, param)
        ));
        /*Map<String, Object> collect = new ConcurrentHashMap<>();
        for (String fun : funs) {
            Object invoke = ReflectUtil.invoke(shopOrderStatisticMapper, fun, param);
            collect.put(fun, ObjUtil.defaultIfNull(invoke,BigDecimal.ZERO));
        }*/
        ShopOrderStatistic data = new ShopOrderStatistic();
        //List<Map<String, Object>> list = shopOrderStatisticMapper.getPayTypeAmountCount(param);
        List<Map<String, Object>> list = (List<Map<String, Object>>) collect.get("getPayTypeAmountCount");
        if (CollUtil.isEmpty(list)) {
            return data;
        }
        Map<String, BigDecimal> sum = list.stream().collect(Collectors.toMap(item -> Convert.toStr(item.get("payType")), item -> Convert.toBigDecimal(item.get("amount"))));
        Map<String, Long> count = list.stream().collect(Collectors.toMap(item -> Convert.toStr(item.get("payType")), item -> Convert.toLong(item.get("count"))));
        data.setWechatPayAmount(sum.getOrDefault(PayEnums.WECHAT_MINI.getValue(), BigDecimal.ZERO));
        data.setWechatPayCount(count.getOrDefault(PayEnums.WECHAT_MINI.getValue(), 0L));
        data.setAliPayAmount(sum.getOrDefault(PayEnums.ALIPAY_MINI.getValue(), BigDecimal.ZERO));
        data.setAliPayCount(count.getOrDefault(PayEnums.ALIPAY_MINI.getValue(), 0L));
        data.setScanPayAmount(sum.getOrDefault(PayEnums.MAIN_SCAN.getValue(), BigDecimal.ZERO));
        data.setScanPayCount(count.getOrDefault(PayEnums.MAIN_SCAN.getValue(), 0L));
        data.setCashPayAmount(sum.getOrDefault(PayEnums.CASH_PAY.getValue(), BigDecimal.ZERO));
        data.setCashPayCount(count.getOrDefault(PayEnums.CASH_PAY.getValue(), 0L));
        data.setCreditPayAmount(sum.getOrDefault(PayEnums.CREDIT_PAY.getValue(), BigDecimal.ZERO));
        data.setCreditPayCount(count.getOrDefault(PayEnums.CREDIT_PAY.getValue(), 0L));
        //List<Map<String, Object>> list1 = shopOrderStatisticMapper.getVipRechargeAmountCount(param);
        List<Map<String, Object>> list1 = (List<Map<String, Object>>) collect.get("getVipRechargeAmountCount");
        Map<String, BigDecimal> sum1 = list1.stream().collect(Collectors.toMap(item -> Convert.toStr(item.get("bizCode")), item -> Convert.toBigDecimal(item.get("amount"))));
        Map<String, Long> count1 = list1.stream().collect(Collectors.toMap(item -> Convert.toStr(item.get("bizCode")), item -> Convert.toLong(item.get("count"))));
        data.setRechargeAmount(NumberUtil.add(sum1.getOrDefault("cashIn", BigDecimal.ZERO), sum1.getOrDefault("wechatIn", BigDecimal.ZERO), sum1.getOrDefault("alipayIn", BigDecimal.ZERO)));
        data.setRechargeRefundAmount(sum1.getOrDefault("rechargeRefund", BigDecimal.ZERO).abs());
        data.setMemberPayAmount(sum1.getOrDefault("orderPay", BigDecimal.ZERO).abs());
        data.setMemberPayCount(count1.getOrDefault("orderPay", 0L));
        data.setSaleAmount(NumberUtil.add(data.getWechatPayAmount(), data.getAliPayAmount(), data.getScanPayAmount(), data.getCashPayAmount(), data.getCreditPayAmount()));
        data.setSaleCount(NumberUtil.add(data.getWechatPayCount(), data.getAliPayCount(), data.getScanPayCount(), data.getCashPayCount(), data.getCreditPayCount()).longValue());
        BigDecimal refundAmount = list.stream().filter(item -> item.get("payType") != null).map(item -> Convert.toBigDecimal(item.get("refund"), BigDecimal.ZERO)).reduce(BigDecimal.ZERO, BigDecimal::add);
        data.setRefundAmount(refundAmount);
        long refundCount = list.stream().filter(item -> item.get("payType") != null).map(item -> Convert.toLong(item.get("refundCount"), 0L)).reduce(0L, Long::sum);
        data.setRefundCount(refundCount);
        //long newMemberCount = shopOrderStatisticMapper.getNewMemberCount(param);
        long newMemberCount = (long) collect.get("getNewMemberCount");
        data.setNewMemberCount(newMemberCount);
        //BigDecimal customerUnitPrice = shopOrderStatisticMapper.getCustomerUnitPrice(param);
        BigDecimal customerUnitPrice = (BigDecimal) collect.get("getCustomerUnitPrice");
        data.setCustomerUnitPrice(NumberUtil.nullToZero(customerUnitPrice).setScale(2, java.math.RoundingMode.HALF_UP));
        //BigDecimal tableTurnoverRate = shopOrderStatisticMapper.getTableTurnoverRate(param);
        BigDecimal tableTurnoverRate = (BigDecimal) collect.get("getTableTurnoverRate");
        data.setTableTurnoverRate(tableTurnoverRate);
        BigDecimal discountAmount = list.stream().filter(item -> item.get("payType") != null).map(item -> Convert.toBigDecimal(item.get("discount"), BigDecimal.ZERO)).reduce(BigDecimal.ZERO, BigDecimal::add);
        long discountCount = list.stream().filter(item -> item.get("payType") != null).map(item -> Convert.toLong(item.get("discountCount"), 0L)).reduce(0L, Long::sum);
        data.setDiscountAmount(discountAmount);
        data.setDiscountCount(discountCount);
        return data;

        /*ShopOrderStatistic shopOrderStatistic = shopOrderStatisticMapper.getTradeData(param);
        long newMemberCount = shopOrderStatisticMapper.getNewMemberCount(param);
        data.setNewMemberCount(newMemberCount);
        shopOrderStatistic.setCustomerUnitPrice(shopOrderStatistic.getCustomerUnitPrice().setScale(2, java.math.RoundingMode.HALF_UP));
        shopOrderStatistic.setTableTurnoverRate(shopOrderStatistic.getTableTurnoverRate().setScale(2, java.math.RoundingMode.HALF_UP));
        return shopOrderStatistic;*/
    }

    @Override
    public Page<DataSummaryProductSaleRankingVo> getProductSaleRankingPage(DataSummaryProductSaleParam param) {
        LocalDate now = LocalDate.now();
        Integer day = param.getDay();
        LocalDate beginDate = now.plusDays(-day);
        List<String> days = new ArrayList<>();
        for (int i = 1; i <= day; i++) {
            String thisDay = beginDate.plusDays(i).format(DatePattern.NORM_DATE_FORMATTER);
            days.add(thisDay);
        }
        param.setDays(days);
        param.setBeginDate(days.getFirst() + " 00:00:00");
        param.setEndDate(days.getLast() + " 23:59:59");
        PageHelper.startPage(PageUtil.buildPageHelp());
        PageInfo<DataSummaryProductSaleRankingVo> pageInfo = new PageInfo<>(shopProdStatisticMapper.findProdRandingSummaryPage2(param));
        return PageUtil.convert(pageInfo);
    }

    @Override
    public DataSummaryDateAmountVo getSummaryAmountData(Long shopId, Integer day) {
        LocalDate now = LocalDate.now();
        LocalDate beginDate = now.plusDays(-day);
        DataSummaryDateAmountVo data = new DataSummaryDateAmountVo();
        List<DataSummaryDateAmountVo.TotalVo> total = new ArrayList<>();
        for (int i = 1; i <= day; i++) {
            String thisDay = beginDate.plusDays(i).format(DatePattern.NORM_DATE_FORMATTER);
            OrderInfo orderInfo = orderInfoMapper.selectOneByQuery(QueryWrapper.create()
                    .select("ifnull(sum(order_amount),0) as order_amount,ifnull(sum(pay_amount),0) as pay_amount,ifnull(sum(order_amount-pay_amount),0) as discount_amount")
                    .eq(OrderInfo::getShopId, shopId)
                    .eq(OrderInfo::getTradeDay, thisDay)
                    .isNotNull(OrderInfo::getPaidTime)
            );
            DataSummaryDateAmountVo.TotalVo totalVo = new DataSummaryDateAmountVo.TotalVo();
            if (orderInfo != null) {
                totalVo.setOrderAmount(orderInfo.getOrderAmount());
                totalVo.setActualAmount(orderInfo.getPayAmount());
                totalVo.setDiscountAmount(orderInfo.getDiscountAmount());
            }
            totalVo.setTradeDay(thisDay);
            total.add(totalVo);
        }
        data.setTotal(total);
        return data;
    }

    @Override
    public DataSummaryPayTypeVo getSummaryPayTypeData(Long shopId, Integer day) {
        LocalDate now = LocalDate.now();
        LocalDate beginDate = now.plusDays(-day);
        DataSummaryPayTypeVo data = new DataSummaryPayTypeVo();
        List<DataSummaryPayTypeVo.CountPayTypeVo> total = new ArrayList<>();
        List<String> days = new ArrayList<>();
        for (int i = 1; i <= day; i++) {
            String thisDay = beginDate.plusDays(i).format(DatePattern.NORM_DATE_FORMATTER);
            days.add(thisDay);
        }
        List<OrderInfo> orderList = orderInfoMapper.selectListByQuery(QueryWrapper.create()
                .select("pay_type,count(1) as place_num")
                .eq(OrderInfo::getShopId, shopId)
                .in(OrderInfo::getTradeDay, days)
                .isNotNull(OrderInfo::getPaidTime)
                .groupBy(OrderInfo::getPayType)
        );

        PayEnums[] pays = PayEnums.values();
        if (CollUtil.isEmpty(orderList)) {
            for (PayEnums pay : pays) {
                DataSummaryPayTypeVo.CountPayTypeVo payTypeVo = new DataSummaryPayTypeVo.CountPayTypeVo();
                payTypeVo.setPayType(pay.getMsg());
                payTypeVo.setCount(0);
                total.add(payTypeVo);
            }
            data.setCountPayType(total);
            return data;
        }
        for (PayEnums pay : pays) {
            OrderInfo orderInfo = orderList.stream().filter(order -> pay.getValue().equals(order.getPayType())).findFirst().orElse(null);
            DataSummaryPayTypeVo.CountPayTypeVo payTypeVo = new DataSummaryPayTypeVo.CountPayTypeVo();
            payTypeVo.setPayType(pay.getMsg());
            payTypeVo.setCount(0);
            if (orderInfo != null) {
                payTypeVo.setPayType(PayEnums.getText(orderInfo.getPayType()));
                payTypeVo.setCount(orderInfo.getPlaceNum());
            }
            total.add(payTypeVo);
        }
        data.setCountPayType(total);
        return data;
    }

    @Override
    public List<Long> getShopIdList() {
        return shopOrderStatisticMapper.getShopIdList();
    }
}
