package cn.iocoder.yudao.module.member.job;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.member.dal.dataobject.business.BusinessDO;
import cn.iocoder.yudao.module.member.dal.dataobject.card.CardDO;
import cn.iocoder.yudao.module.member.dal.dataobject.order.DishOrderDO;
import cn.iocoder.yudao.module.member.dal.dataobject.orderdetail.OrderDetailDO;
import cn.iocoder.yudao.module.member.dal.mysql.business.BusinessMapper;
import cn.iocoder.yudao.module.member.dal.mysql.card.CardMapper;
import cn.iocoder.yudao.module.member.dal.mysql.order.DishOrderMapper;
import cn.iocoder.yudao.module.member.dal.mysql.orderdetail.OrderDetailMapper;
import cn.iocoder.yudao.module.member.enums.CostTypeEnum;
import cn.iocoder.yudao.module.member.enums.TimePeriodEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author:qjq
 * @Date:2024/4/3 14:50
 */
@Slf4j
@Component
public class BusinessBatchJob implements JobHandler {
    @Resource
    private BusinessMapper businessMapper;
    @Resource
    private DishOrderMapper dishOrderMapper;
    @Resource
    private OrderDetailMapper orderDetailMapper;
    @Resource
    private CardMapper cardMapper;
    /**
     * 执行任务
     *
     * @param param 参数
     * @return 结果
     * @throws Exception 异常
     */
    @Override
    @TenantIgnore
    public String execute(String param) throws Exception {
        LocalDateTime now = LocalDateTimeUtil.now();
        //昨天时间
        LocalDateTime offset = LocalDateTimeUtil.offset(now, -1, ChronoUnit.DAYS);
        //获取昨天开始与结束
        LocalDateTime startDate = LocalDateTimeUtil.beginOfDay(offset);
        LocalDateTime endDate = LocalDateTimeUtil.endOfDay(offset);
        List<DishOrderDO> dishOrderDOS = dishOrderMapper.selectList(new LambdaQueryWrapperX<DishOrderDO>()
                .betweenIfPresent(DishOrderDO::getCreateTime, startDate, endDate)
                .eq(DishOrderDO::getOrderStatus, DishOrderDO.COMPLETE)
                .isNotNull(DishOrderDO::getStoreId));
        //根据名店id进行分组
        Map<Long, List<DishOrderDO>> collect = dishOrderDOS.stream().collect(Collectors.groupingBy(DishOrderDO::getStoreId));
        List<BusinessDO> list=new ArrayList<>();
        for (Map.Entry<Long, List<DishOrderDO>> map : collect.entrySet()) {
            BusinessDO build = BusinessDO.builder().build();
            List<DishOrderDO> value = map.getValue();
            Long carteenId = map.getKey();
            //获取营业额
            BigDecimal sum = value.stream().map(DishOrderDO::getTotalMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            //double sum = value.stream().mapToDouble(d -> d.getTotalMoney().doubleValue()).sum();
            build.setTurnover(sum);
            //订单数
            build.setOrderSum(value.size());
            //顾客数 根据用户id进行去重统计
            long count = value.stream().map(DishOrderDO::getUserId).distinct().count();
            build.setCustomerSum((int) count);
            //均单价 总价和/订单数
            BigDecimal divide = value.stream()
                    .map(DishOrderDO::getTotalMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add)
                    .divide(BigDecimal.valueOf(build.getOrderSum()), RoundingMode.CEILING);
            build.setPriceAvg(divide);
            //充值钱包
            BigDecimal reduce = cardMapper.selectList(new LambdaQueryWrapperX<CardDO>()
                            .betweenIfPresent(CardDO::getCreateTime, startDate, endDate)
                            .inIfPresent(CardDO::getUserId, value
                                    .stream()
                                    .map(DishOrderDO::getUserId)
                                    .collect(Collectors.toList()))
                            .eq(CardDO::getFlag, CardDO.ADD))
                    .stream()
                    .map(CardDO::getMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            build.setRechargePurse(reduce);
            //提现金额
            BigDecimal withdrawal =cardMapper.selectList(new LambdaQueryWrapperX<CardDO>()
                    .betweenIfPresent(CardDO::getCreateTime, startDate, endDate)
                    .in(CardDO::getType, Arrays.asList(CostTypeEnum.WITHDRAW.getCode(),CostTypeEnum.CASH_WITHDRAW.getCode())))
                    .stream()
                    .map(CardDO::getChangeMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            build.setWithdrawal(withdrawal);
            //早餐
            value.forEach(x-> x.setPayMethods(TimePeriodEnum.getTimePeriod(x.getCreateTime())));
            Map<String, List<DishOrderDO>> collect1 = value.stream().collect(Collectors.groupingBy(DishOrderDO::getPayMethods));
            for (Map.Entry<String, List<DishOrderDO>> maps : collect1.entrySet()) {
                List<DishOrderDO> value1 = maps.getValue();
                String key = maps.getKey();
                //早餐
                if(key.equalsIgnoreCase(CostTypeEnum.MORNING.getCode())){
                    build.setBreakfast(value1
                            .stream()
                            .map(DishOrderDO::getTotalMoney)
                            .reduce(BigDecimal.ZERO, BigDecimal::add));
                }
                //午餐
                else if(key.equalsIgnoreCase(CostTypeEnum.NOON.getCode())){
                    build.setLunch(value1
                            .stream()
                            .map(DishOrderDO::getTotalMoney)
                            .reduce(BigDecimal.ZERO, BigDecimal::add));
                }else {
                    build.setDinner(value1
                            .stream()
                            .map(DishOrderDO::getTotalMoney)
                            .reduce(BigDecimal.ZERO, BigDecimal::add));
                }
            }
            //统计称重数据
            List<Long> orderIds = value.stream().map(DishOrderDO::getId).collect(Collectors.toList());
            BigDecimal decimal = orderDetailMapper.selectList(new LambdaQueryWrapperX<OrderDetailDO>()
                            .inIfPresent(OrderDetailDO::getOrderId, orderIds))
                    .stream()
                    .map(OrderDetailDO::getWeight)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            build.setWeigh(decimal);
            //设置门店编号
            build.setCarteenId(carteenId);
            build.setCreateTime(LocalDateTime.now().minusDays(1));
            list.add(build);
        }
        Boolean b = businessMapper.insertBatch(list);
        log.info("[execute][定时插入统计营业数据是否成功 {}]", b);
        return String.format("定时插入统计营业数据是否成功  %s ", b);
    }
}
