package cn.newfeifan.mall.module.distri.service.dailybill;

import cn.newfeifan.mall.module.distri.dal.dataobject.ptdailybill.PtDailyBillDO;
import cn.newfeifan.mall.module.distri.dal.mysql.ptdailybill.PtDailyBillMapper;
import cn.newfeifan.mall.module.distri.service.dailybill.dto.OrderDTO;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import cn.newfeifan.mall.module.distri.controller.admin.dailybill.vo.*;
import cn.newfeifan.mall.module.distri.dal.dataobject.dailybill.DailyBillDO;
import cn.newfeifan.mall.framework.common.pojo.PageResult;
import cn.newfeifan.mall.framework.common.util.object.BeanUtils;

import cn.newfeifan.mall.module.distri.dal.mysql.dailybill.DailyBillMapper;

import java.time.LocalDate;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.newfeifan.mall.module.distri.enums.ErrorCodeConstants.*;

/**
 * 每日账单 Service 实现类
 *
 * @author 非繁人
 */
@Service
@Validated
public class DailyBillServiceImpl implements DailyBillService {

    @Resource
    private DailyBillMapper dailyBillMapper;
    @Resource
    private PtDailyBillMapper ptDailyBillMapper;

    @Override
    public Long createDailyBill(DailyBillSaveReqVO createReqVO) {
        // 插入
        DailyBillDO dailyBill = BeanUtils.toBean(createReqVO, DailyBillDO.class);
        dailyBillMapper.insert(dailyBill);
        // 返回
        return dailyBill.getId();
    }

    @Override
    public void updateDailyBill(DailyBillSaveReqVO updateReqVO) {
        // 校验存在
        validateDailyBillExists(updateReqVO.getId());
        // 更新
        DailyBillDO updateObj = BeanUtils.toBean(updateReqVO, DailyBillDO.class);
        dailyBillMapper.updateById(updateObj);
    }

    @Override
    public void deleteDailyBill(Long id) {
        // 校验存在
        validateDailyBillExists(id);
        // 删除
        dailyBillMapper.deleteById(id);
    }

    private void validateDailyBillExists(Long id) {
        if (dailyBillMapper.selectById(id) == null) {
            throw exception(DAILY_BILL_NOT_EXISTS);
        }
    }

    @Override
    public DailyBillDO getDailyBill(Long id) {
        return dailyBillMapper.selectById(id);
    }

    @Override
    public PageResult<DailyBillRespVO> getDailyBillPage(DailyBillPageReqVO pageReqVO) {
        PageResult<DailyBillDO> dailyBillDOPageResult = dailyBillMapper.selectPage(pageReqVO);
        PageResult<DailyBillRespVO> result = BeanUtils.toBean(dailyBillDOPageResult, DailyBillRespVO.class);
        for (DailyBillRespVO dailyBillRespVO : result.getList()) {
            dailyBillRespVO.setMerchantName(dailyBillMapper.getMerchantName(dailyBillRespVO.getMerchantId()));
            dailyBillRespVO.setShopName(dailyBillMapper.getShopName(dailyBillRespVO.getShopId()));
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void caleDailyBill() {
        // 获取每天的订单列表
        List<OrderDTO> orderDetails = dailyBillMapper.getOrderDetails();
        // 使用Stream API和Collectors.groupingBy按照日期分组，并按时间倒序排序每个日期的Order列表
        Map<LocalDate, List<OrderDTO>> ordersByDate = orderDetails.stream()
                .collect(Collectors.groupingBy(order -> order.getCreateTime().toLocalDate(),
                        LinkedHashMap::new, // 保持插入顺序
                        Collectors.toList()));

        ordersByDate.forEach((date, orderList) -> {
            // 计算分组结果，并按订单创建时间倒序输出每个日期的订单

            Long ptIntegral = orderList.stream()
                    .mapToLong(OrderDTO::getPayIntegral)
                    .sum();
            Long ptRefundIntegral = orderList.stream()
                    .filter(order -> order.getRefundIntegral() != null)  // 过滤掉 getRefundIntegral 为空的订单
                    .mapToLong(OrderDTO::getRefundIntegral)
                    .sum();

            PtDailyBillDO ptDailyBillDO = PtDailyBillDO.builder()
                    .integral(ptIntegral)
                    .refundIntegral(ptRefundIntegral)
                    .receivedIntegral(ptIntegral - ptRefundIntegral)
                    .orderCount((long) orderList.size())
                    .orderIds(orderList.stream().map(OrderDTO::getId).collect(Collectors.toList()).toString())
                    .orderCalcTime(date)
                    .build();

            ptDailyBillMapper.insert(ptDailyBillDO);

            Map<Long, List<OrderDTO>> dailyBillByShop = orderList.stream()
                    .collect(Collectors.groupingBy(OrderDTO::getShopId,
                            Collectors.toList()));

            dailyBillByShop.forEach((shopId, shopOrderList) -> {
                Long integral = shopOrderList.stream()
                        .mapToLong(OrderDTO::getPayIntegral)
                        .sum();
                Long refundIntegral = shopOrderList.stream()
                        .filter(order -> order.getRefundIntegral() != null)  // 过滤掉 getRefundIntegral 为空的订单
                        .mapToLong(OrderDTO::getRefundIntegral)
                        .sum();

                DailyBillDO dailyBillDO = DailyBillDO.builder()
                        .integral(integral)
                        .refundIntegral(refundIntegral)
                        .receivedIntegral(integral - refundIntegral)
                        .orderCount((long) shopOrderList.size())
                        .orderIds(shopOrderList.stream().map(OrderDTO::getId).collect(Collectors.toList()).toString())
                        .orderCalcTime(date)
                        .shopId(shopId)
                        .merchantId(shopOrderList.get(0).getMerchantId())
                        .ptDailyBillId(ptDailyBillDO.getId())
                        .build();

                dailyBillMapper.insert(dailyBillDO);
            });
            //修改订单状态为已经计算每日账单
            dailyBillMapper.updateOrderItemByOrderId(orderList.stream().map(OrderDTO::getId).collect(Collectors.toList()));
        });
    }

}