package cn.iocoder.yudao.module.member.service.billing;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.unit.DataUnit;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.member.controller.admin.billing.vo.BillingPageDataVo;
import cn.iocoder.yudao.module.member.controller.admin.billing.vo.BillingPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.billing.vo.BillingRespMoneyVO;
import cn.iocoder.yudao.module.member.controller.admin.billing.vo.BillingSaveReqVO;
import cn.iocoder.yudao.module.member.controller.admin.orderdetail.vo.OrderDetailRespVO;
import cn.iocoder.yudao.module.member.controller.admin.orderspacecapsule.vo.OrderSpaceCapsuleRespVO;
import cn.iocoder.yudao.module.member.controller.admin.storeorder.vo.StoreOrderRespVO;
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.AppStoreOrderDetailVo;
import cn.iocoder.yudao.module.member.dal.dataobject.billing.BillingDO;
import cn.iocoder.yudao.module.member.dal.dataobject.card.CardDO;
import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO;
import cn.iocoder.yudao.module.member.dal.dataobject.order.DishOrderDO;
import cn.iocoder.yudao.module.member.dal.dataobject.orderspacecapsule.OrderSpaceCapsuleDO;
import cn.iocoder.yudao.module.member.dal.dataobject.storeorder.StoreOrderDO;
import cn.iocoder.yudao.module.member.dal.mysql.billing.BillingMapper;
import cn.iocoder.yudao.module.member.dal.mysql.card.CardMapper;
import cn.iocoder.yudao.module.member.dal.mysql.group.MemberGroupMapper;
import cn.iocoder.yudao.module.member.dal.mysql.order.DishOrderMapper;
import cn.iocoder.yudao.module.member.dal.mysql.orderspacecapsule.OrderSpaceCapsuleMapper;
import cn.iocoder.yudao.module.member.dal.mysql.storeorder.StoreOrderMapper;
import cn.iocoder.yudao.module.member.enums.*;
import cn.iocoder.yudao.module.member.service.group.MemberGroupService;
import cn.iocoder.yudao.module.member.service.orderdetail.OrderDetailService;
import cn.iocoder.yudao.module.member.service.storeorderdetail.StoreOrderDetailService;
import cn.iocoder.yudao.module.system.api.carteen.CarteenApi;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import lombok.Data;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.BillingEnum.BILLING_CANTEEN;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;

/**
 * 开票记录 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class BillingServiceImpl implements BillingService {

    @Resource
    private BillingMapper billingMapper;
    @Resource
    private OrderSpaceCapsuleMapper orderSpaceCapsuleMapper;
    @Resource
    private DishOrderMapper dishOrderMapper;
    @Resource
    private StoreOrderMapper storeOrderMapper;
    @Resource
    private MemberGroupMapper memberGroupMapper;
    @Resource
    private CardMapper cardMapper;
    @Resource
    private StoreOrderDetailService storeOrderDetailService;
    @Resource
    private CarteenApi carteenApi;
    @Resource
    private MemberGroupService memberGroupService;
    /**
     * 食堂
     * @param startTime
     * @param endTime
     * @return
     */
    public PageResult<DishOrderDO> getDishOrderDO(BillingPageDataVo vo,Date startTime, Date endTime, List<Long> ids){
        return dishOrderMapper.selectPage(vo,new LambdaQueryWrapperX<DishOrderDO>()
                .betweenIfPresent(DishOrderDO::getCreateTime,startTime,endTime)
                .eq(DishOrderDO::getOrderStatus,DishOrderDO.COMPLETE)
                .eq(DishOrderDO::getBillingExist,Boolean.FALSE)
                .eq(DishOrderDO::getStoreId,vo.getCarteenId())
                .in(DishOrderDO::getUserId,ids)
        );
    }
    /**
     * 超市
     * @param startTime
     * @param endTime
     * @return
     */
    public PageResult<StoreOrderDO> getStoreOrderDO(BillingPageDataVo vo,Date startTime, Date endTime, List<Long> ids){
        return storeOrderMapper.selectPage(vo,new LambdaQueryWrapperX<StoreOrderDO>()
                .betweenIfPresent(StoreOrderDO::getCreateTime,startTime,endTime)
                .eq(StoreOrderDO::getStatus, StoreOrderStatusEnum.COMPLETE.getCode())
                .eq(StoreOrderDO::getBillingExist,Boolean.FALSE)
                .eq(StoreOrderDO::getCarteenId,vo.getCarteenId())
                .in(StoreOrderDO::getUserId,ids)
        );
    }
    /**
     * 太空舱
     * @param startTime
     * @param endTime
     * @return
     */
    public PageResult<OrderSpaceCapsuleDO> getOrderSpaceCapsuleDO(BillingPageDataVo vo,Date startTime, Date endTime, List<Long> ids){
        return  orderSpaceCapsuleMapper.selectPage(vo,new LambdaQueryWrapperX<OrderSpaceCapsuleDO>()
                .betweenIfPresent(OrderSpaceCapsuleDO::getCreateTime,startTime,endTime)
                .eq(OrderSpaceCapsuleDO::getStatus, SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_DONE.getCode())
                .eq(OrderSpaceCapsuleDO::getBillingExist,Boolean.FALSE)
                .eq(OrderSpaceCapsuleDO::getCarteenId,vo.getCarteenId())
                .in(OrderSpaceCapsuleDO::getUserId,ids)
        );
    }
    /**
     * 食堂
     * @param startTime
     * @param endTime
     * @return
     */
    public List<DishOrderDO> getDishOrderDO(Date startTime, Date endTime, List<Long> ids,Long carteenId){
        return dishOrderMapper.selectList(new LambdaQueryWrapperX<DishOrderDO>()
                .betweenIfPresent(DishOrderDO::getCreateTime,startTime,endTime)
                .eq(DishOrderDO::getOrderStatus,DishOrderDO.COMPLETE)
                .eq(DishOrderDO::getBillingExist,Boolean.FALSE)
                .eq(DishOrderDO::getStoreId,carteenId)
                .in(DishOrderDO::getUserId,ids)
        );
    }
    /**
     * 超市
     * @param startTime
     * @param endTime
     * @return
     */
    public List<StoreOrderDO> getStoreOrderDO(Date startTime, Date endTime, List<Long> ids,Long carteenId){
        return storeOrderMapper.selectList(new LambdaQueryWrapperX<StoreOrderDO>()
                .betweenIfPresent(StoreOrderDO::getCreateTime,startTime,endTime)
                .eq(StoreOrderDO::getStatus, StoreOrderStatusEnum.COMPLETE.getCode())
                .eq(StoreOrderDO::getBillingExist,Boolean.FALSE)
                .eq(StoreOrderDO::getCarteenId,carteenId)
                .in(StoreOrderDO::getUserId,ids)
        );
    }
    /**
     * 太空舱
     * @param startTime
     * @param endTime
     * @return
     */
    public List<OrderSpaceCapsuleDO> getOrderSpaceCapsuleDO(Date startTime, Date endTime, List<Long> ids,Long carteenId){
        return  orderSpaceCapsuleMapper.selectList(new LambdaQueryWrapperX<OrderSpaceCapsuleDO>()
                .betweenIfPresent(OrderSpaceCapsuleDO::getCreateTime,startTime,endTime)
                .eq(OrderSpaceCapsuleDO::getStatus, SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_DONE.getCode())
                .eq(OrderSpaceCapsuleDO::getBillingExist,Boolean.FALSE)
                .eq(OrderSpaceCapsuleDO::getCarteenId,carteenId)
                .in(OrderSpaceCapsuleDO::getUserId,ids)
        );
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createBilling(BillingSaveReqVO createReqVO) {
        // 插入 BillingDO 对象并生成唯一主键
        BillingDO billing = BeanUtils.toBean(createReqVO, BillingDO.class);
        MemberGroupDO memberGroupDO = memberGroupDO(billing.getUserId());
        billing.setId(IdUtil.getSnowflakeNextId() + "");
        billing.setUserName(memberGroupDO.getName());
        billing.setUserPhone(String.valueOf(memberGroupDO.getId()));
        // 根据不同的 billingType 获取订单、金额和订单 ID 列表，并设置开票信息
        List<Long> orderIds;
        BigDecimal totalMoney;
        String billingName;
        //处理时间段
        Date startTime = createReqVO.getStartTime();
        DateTime start = DateUtil.beginOfMonth(startTime);
        DateTime end = DateUtil.endOfMonth(startTime);
        createReqVO.setStartTime(start);
        createReqVO.setEndTime(end);
        //获取当前单位下的所有人
        List<Long> memberList = memberGroupMapper.getMemberList(memberGroupDO.getId());
        switch (BillingEnum.fromCode(billing.getBillingType())) {
            case BILLING_CANTEEN:
                List<DishOrderDO> dishOrders = getDishOrderDO(createReqVO.getStartTime(), createReqVO.getEndTime(), memberList,billing.getCarteenId());
                if (CollUtil.isEmpty(dishOrders)) throw exception(BILLING_NOT_ORDER_EXISTS);
                totalMoney = calculateTotalMoney(dishOrders, DishOrderDO::getTotalMoney);
                orderIds = getOrderIds(dishOrders, DishOrderDO::getId);
                billingName = "食堂餐饮费";
                updateBillingExist(dishOrders, dishOrderMapper,billing.getId());
                break;
            case BILLING_SUPERMARKET:
                List<StoreOrderDO> storeOrders = getStoreOrderDO(createReqVO.getStartTime(), createReqVO.getEndTime(), memberList,billing.getCarteenId());
                if (CollUtil.isEmpty(storeOrders)) throw exception(BILLING_NOT_ORDER_EXISTS);
                totalMoney = calculateTotalMoney1(storeOrders, StoreOrderDO::getTotalPrice);
                List<Integer> orderIds1 = getOrderIds(storeOrders, StoreOrderDO::getOrderId);
                orderIds = orderIds1.stream().map(Integer::longValue).collect(Collectors.toList());
                billingName = "超市物品费";
                updateBillingExist(storeOrders, storeOrderMapper,billing.getId());
                break;
            case BILLING_SPACE_CAPSULE:
                List<OrderSpaceCapsuleDO> capsuleOrders = getOrderSpaceCapsuleDO(createReqVO.getStartTime(), createReqVO.getEndTime(),memberList,billing.getCarteenId());
                if (CollUtil.isEmpty(capsuleOrders)) throw exception(BILLING_NOT_ORDER_EXISTS);
                totalMoney = calculateTotalMoney(capsuleOrders, OrderSpaceCapsuleDO::getMoney);
                orderIds = getOrderIds(capsuleOrders, OrderSpaceCapsuleDO::getId);
                billingName = "太空舱费用";
                updateBillingExist(capsuleOrders, orderSpaceCapsuleMapper,billing.getId());
                break;
            default:
                throw new IllegalArgumentException("Unsupported billing type");
        }
        // 设置 BillingDO 对象的基本信息
        billing.setBillingMoney(totalMoney);
        billing.setStatus(BillingStatusEnum.BILLING_INVOICING.getCode());
        billing.setBillingName(billingName);
        billing.setOrderId(JsonUtils.toJsonString(orderIds));
        billing.setRequestBillingTime(LocalDateTime.now());
        // 插入 BillingDO 对象到数据库
        billingMapper.insert(billing);
        // 返回主键 ID
        return billing.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createBillingUnit(BillingSaveReqVO createReqVO) {
        // 插入 BillingDO 对象并生成唯一主键
        BillingDO billing = BeanUtils.toBean(createReqVO, BillingDO.class);
        Set<Long> orderId = createReqVO.getOrderId();
        if(orderId==null){
            createReqVO.setOrderId(new HashSet<>(getMemberListByUserId(billing.getUserId()))) ;
        }
        if(CollUtil.isEmpty(createReqVO.getOrderId()))throw exception(BILLING_NOT_ORDER_USER);
//        MemberGroupDO memberGroupDO = memberGroupDO(billing.getUserId());
        billing.setId(IdUtil.getSnowflakeNextId() + "");
//        billing.setUserName(memberGroupDO.getName());
        billing.setUserPhone(String.valueOf(createReqVO.getUserId()));
        billing.setCarteenId(memberGroupService.getGroup(createReqVO.getUserId()).getCarteenId());
        billing.setUserId(billing.getUserId());
        //查询单位充值的金额
        List<CardDO> moneyByUserIds = cardMapper.getMoneyByUserIds(createReqVO.getOrderId(), CardDO.ADD, CostTypeEnum.ADMIN_PAY.getCode(),BillingStatusEnum.BILLING_INVOICING_REJECTION.getCode(),getMonth(),createReqVO.getUserId());
        if(CollUtil.isEmpty(moneyByUserIds))throw exception(BILLING_NOT_ORDER_EXISTS);
        BigDecimal totalMoney = moneyByUserIds.stream()
                .map(CardDO::getChangeMoney)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        moneyByUserIds.forEach(f-> {
            f.setBillingExist(BillingStatusEnum.BILLING_INVOICING.getCode());
            f.setBillingNum(billing.getId());
        });
        billing.setBillingType(BillingEnum.BILLING_SPACE_DANWEI.getCode());
        cardMapper.updateBatch(moneyByUserIds);
        billing.setBillingMoney(totalMoney);
        billing.setOrderId(JSONUtil.toJsonStr(createReqVO.getOrderId()));
        billing.setBillingName(billing.getUserName()+" 消费 "+totalMoney+" 元");
        billing.setRequestBillingTime(LocalDateTime.now());
        billing.setStatus(BillingStatusEnum.BILLING_INVOICING.getCode());
        // 插入 BillingDO 对象到数据库
        billingMapper.insert(billing);
        // 返回主键 ID
        return billing.getId();
    }
    // 计算订单的总金额，处理 Double 到 BigDecimal 的转换
    private <T> BigDecimal calculateTotalMoney1(List<T> orders, Function<T, Double> moneyMapper) {
        return orders.stream()
                .map(moneyMapper)
                .filter(Objects::nonNull) // 过滤掉 null 值，避免空指针异常
                .map(BigDecimal::valueOf) // 将 Double 转换为 BigDecimal
                .reduce(BigDecimal.ZERO, BigDecimal::add); // 求和
    }
    // 计算订单的总金额
    private <T> BigDecimal calculateTotalMoney(List<T> orders, Function<T, BigDecimal> moneyMapper) {
        return orders.stream()
                .map(moneyMapper)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    // 获取订单 ID 列表
    private <T, R> List<R> getOrderIds(List<T> orders, Function<T, R> idMapper) {
        return orders.stream()
                .map(idMapper)
                .collect(Collectors.toList());
    }
    // 更新订单为开票状态
    private <T> void updateBillingExist(List<T> orders, BaseMapperX<T> mapper,String billingId) {
        orders.forEach(order -> {
            // Assuming that the order has a `setBillingExist` method
            try {
                Method setBillingExist = order.getClass().getMethod("setBillingExist", Boolean.class);
                setBillingExist.invoke(order, Boolean.TRUE);
            } catch (Exception e) {
                throw new RuntimeException("Error setting billing exist status", e);
            }
        });
        mapper.updateBatch(orders);
    }
    @Override
    public void updateBilling(BillingSaveReqVO updateReqVO) {
        // 校验存在
        BillingDO billingDO = billingMapper.selectById(updateReqVO.getId());
        if (billingDO== null) {
            throw exception(BILLING_NOT_EXISTS);
        }
        // 更新
        BillingDO updateObj = BeanUtils.toBean(updateReqVO, BillingDO.class);
        updateObj.setOrderId(billingDO.getOrderId());
        String orderId = updateObj.getOrderId();
        JSONArray jsonArray = JSONUtil.parseArray(orderId);
        // 转换为 Set<Long>
        Set<Long> orderIds = jsonArray.stream()
                .map(object -> Long.parseLong(object.toString())) // 将每个元素转换为 Long
                .collect(Collectors.toSet());
        //开票成功是根据pdf上传成功没
        if(StrUtil.isNotBlank(updateObj.getPdfUrl())){
            //上传成功 修改状态
            updateObj.setStatus(BillingStatusEnum.BILLING_INVOICING_IS_COMPLETE.getCode());
            //设置同意人
            updateObj.setSystemId(SecurityFrameworkUtils.getLoginUserId());
            //同意就把订单编号付上去
            switch (BillingEnum.fromCode(updateObj.getBillingType())){
                case BILLING_CANTEEN:
                    dishOrderMapper.updateByIdBillingNum(orderIds,updateObj.getId());
                    break;
                case BILLING_SUPERMARKET:
                    storeOrderMapper.updateByIdBillingNum(orderIds,updateObj.getId());
                    break;
                case BILLING_SPACE_CAPSULE:
                    orderSpaceCapsuleMapper.updateByIdBillingNum(orderIds,updateObj.getId());
                    break;
                default:
                    throw new IllegalArgumentException("Unsupported billing type");
            }
        }else{
            //开票回拒
            if(StrUtil.isBlank(updateObj.getRefuseDetails())){
                throw exception(BILLING_NOT_ORDER_REFUSE);
            }
            updateObj.setStatus(BillingStatusEnum.BILLING_INVOICING_REJECTION.getCode());
            updateObj.setRefuseTime(LocalDateTime.now());
            //拒绝就把锁住的订单释放掉
            switch (BillingEnum.fromCode(updateObj.getBillingType())){
                case BILLING_CANTEEN:
                    dishOrderMapper.updateByIdBillingExist(orderIds,Boolean.FALSE);
                    break;
                case BILLING_SUPERMARKET:
                    storeOrderMapper.updateByIdBillingExist(orderIds,Boolean.FALSE);
                    break;
                case BILLING_SPACE_CAPSULE:
                    orderSpaceCapsuleMapper.updateByIdBillingExist(orderIds,Boolean.FALSE);
                    break;
                default:
                    throw new IllegalArgumentException("Unsupported billing type");
            }
        }
        billingMapper.updateById(updateObj);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateBillingUnit(BillingSaveReqVO updateReqVO) {
        // 校验存在
        BillingDO billingDO = billingMapper.selectById(updateReqVO.getId());
        if (billingDO== null) {
            throw exception(BILLING_NOT_EXISTS);
        }
        // 更新
        BillingDO updateObj = BeanUtils.toBean(updateReqVO, BillingDO.class);
        updateObj.setOrderId(billingDO.getOrderId());
        String orderId = updateObj.getOrderId();
        JSONArray jsonArray = JSONUtil.parseArray(orderId);
        // 转换为 Set<Long>
        Set<Long> orderIds = jsonArray.stream()
                .map(object -> Long.parseLong(object.toString())) // 将每个元素转换为 Long
                .collect(Collectors.toSet());
        //开票成功是根据pdf上传成功没
        if(StrUtil.isNotBlank(updateObj.getPdfUrl())){
            //上传成功 修改状态
            updateObj.setStatus(BillingStatusEnum.BILLING_INVOICING_IS_COMPLETE.getCode());
            //设置同意人
            updateObj.setSystemId(SecurityFrameworkUtils.getLoginUserId());
            //拒绝就把锁住的订单释放掉
            cardMapper.udpateEXit(orderIds,BillingStatusEnum.BILLING_INVOICING_IS_COMPLETE.getCode(),null);
        }else{
            //开票回拒
            if(StrUtil.isBlank(updateObj.getRefuseDetails())){
                throw exception(BILLING_NOT_ORDER_REFUSE);
            }
            updateObj.setStatus(BillingStatusEnum.BILLING_INVOICING_REJECTION.getCode());
            updateObj.setRefuseTime(LocalDateTime.now());
            //拒绝就把锁住的订单释放掉
            cardMapper.udpateEXit(orderIds,BillingStatusEnum.BILLING_INVOICING_REJECTION.getCode(),"true");
        }
        billingMapper.updateById(updateObj);
    }
    @Override
    public void deleteBilling(String id) {
        // 校验存在
        validateBillingExists(id);
        // 删除
        billingMapper.deleteById(id);
    }

    private void validateBillingExists(String id) {
        if (billingMapper.selectById(id) == null) {
            throw exception(BILLING_NOT_EXISTS);
        }
    }
    @Override
    public BillingDO getBilling(String id) {
        return billingMapper.selectById(id);
    }

    @Override
    public PageResult<BillingDO> getBillingPage(BillingPageReqVO pageReqVO) {
        return billingMapper.selectPage(pageReqVO);
    }

    @Override
    public BillingRespMoneyVO getHaveWithoutMoney(Long userId,Long carteenId) {
        List<Long> memberList = getMemberListByUserId(userId);
        // 创建 BillingRespMoneyVO 对象
        BillingRespMoneyVO response = new BillingRespMoneyVO();
        // 查询已开票的金额
        BigDecimal haveMoney = getTotalMoneyForBilling(userId, BillingStatusEnum.BILLING_INVOICING_IS_COMPLETE.getCode());
        response.setHaveMoney(haveMoney);
        // 查询未开票的金额
        BigDecimal withoutMoney = getTotalMoneyForOrders(memberList, carteenId);
        response.setWithoutMoney(withoutMoney);
        return response;
    }

    @Override
    public BillingRespMoneyVO getUserHaveWithoutMoney(Long userId, Long carteenId) {
        List<Long> memberList = getMemberListByUserId(userId);
        // 创建 BillingRespMoneyVO 对象
        BillingRespMoneyVO response = new BillingRespMoneyVO();
        // 查询已开票的金额
        BigDecimal haveMoney = getTotalMoneyForBilling(userId, BillingStatusEnum.BILLING_INVOICING_IS_COMPLETE.getCode());
        response.setHaveMoney(haveMoney);
        if(CollUtil.isEmpty(memberList)){
            response.setWithoutMoney(new BigDecimal(0));
            response.setMothMoney(new BigDecimal(0));
            return response;
        }
        BigDecimal moneyByUserIds = cardMapper.getTotalMoneyByuserIds(memberList, CardDO.ADD, CostTypeEnum.ADMIN_PAY.getCode(),getMonth(),userId);
        int i = DateUtil.date().monthBaseOne();
        BigDecimal month = cardMapper.getTotalMoneyByuserIds(memberList, CardDO.ADD, CostTypeEnum.ADMIN_PAY.getCode(),i,userId);
        response.setWithoutMoney(moneyByUserIds);
        response.setMothMoney(month);
        return response;
    }
    private Integer getMonth(){
        DateTime date = DateUtil.date();
        Integer month=null;
        int day = date.dayOfMonth();
        if(day>26){
            month= date.monthBaseOne();
        }
        return month;
    }
    @Override
    public BillingRespMoneyVO getHaveWithoutMoney(Long userId) {
        List<Long> memberList = getMemberListByUserId(userId);
        // 创建 BillingRespMoneyVO 对象
        BillingRespMoneyVO response = new BillingRespMoneyVO();
        // 查询已开票的金额
        BigDecimal haveMoney = getTotalMoneyForBilling(userId, BillingStatusEnum.BILLING_INVOICING_IS_COMPLETE.getCode());
        response.setHaveMoney(haveMoney);
        // 查询未开票的金额
        BigDecimal withoutMoney = getTotalMoneyForOrders(memberList,null);
        response.setWithoutMoney(withoutMoney);
        return response;
    }

    /**
     * 查询已开票的金额
     * @param userId 用户 ID
     * @param billingStatus 账单状态
     * @return 已开票金额
     */
    private BigDecimal getTotalMoneyForBilling(Long userId, Integer billingStatus) {
        return billingMapper.selectList(new LambdaQueryWrapperX<BillingDO>()
                        .eq(BillingDO::getStatus, billingStatus)
                        .eq(BillingDO::getUserId, userId))
                .stream()
                .map(BillingDO::getBillingMoney)
                .reduce(BigDecimal.ZERO, BigDecimal::add); // 求和
    }

    /**
     * 查询未开票的金额（食堂、超市、太空舱）
     * @param memberList 成员 ID 列表
     * @return 未开票金额
     */
    private BigDecimal getTotalMoneyForOrders(List<Long> memberList,Long carteenId) {
        // 合并所有订单金额查询
        BigDecimal totalSpaceCapsuleMoney = getTotalMoneyForOrderSpaceCapsules(memberList,carteenId);
        BigDecimal totalDishOrderMoney = getTotalMoneyForDishOrders(memberList,carteenId);
        BigDecimal totalStoreOrderMoney = getTotalMoneyForStoreOrders(memberList,carteenId);

        return totalSpaceCapsuleMoney.add(totalDishOrderMoney).add(totalStoreOrderMoney);
    }

    /**
     * 查询未开票的太空舱订单金额
     * @param memberList 成员 ID 列表
     * @return 太空舱订单金额
     */
    private BigDecimal getTotalMoneyForOrderSpaceCapsules(List<Long> memberList,Long carteenId) {
        return orderSpaceCapsuleMapper.selectList(new LambdaQueryWrapperX<OrderSpaceCapsuleDO>()
                        .eq(OrderSpaceCapsuleDO::getStatus, SpaceCapsuleOrderEnum.SPACE_CAPSULE_ORDER_ENUM_DONE.getCode())
                        .eqIfPresent(OrderSpaceCapsuleDO::getCarteenId,carteenId)
                        .isNull(OrderSpaceCapsuleDO::getBillingNum)
                        .in(OrderSpaceCapsuleDO::getUserId, memberList))
                .stream()
                .map(OrderSpaceCapsuleDO::getMoney)
                .reduce(BigDecimal.ZERO, BigDecimal::add); // 求和
    }

    /**
     * 查询未开票的食堂订单金额
     * @param memberList 成员 ID 列表
     * @return 食堂订单金额
     */
    private BigDecimal getTotalMoneyForDishOrders(List<Long> memberList,Long carteenId) {
        return dishOrderMapper.selectList(new LambdaQueryWrapperX<DishOrderDO>()
                        .eq(DishOrderDO::getOrderStatus, DishOrderDO.COMPLETE)
                        .eqIfPresent(DishOrderDO::getStoreId,carteenId)
                        .isNull(DishOrderDO::getBillingNum)
                        .in(DishOrderDO::getUserId, memberList))
                .stream()
                .map(DishOrderDO::getTotalMoney)
                .reduce(BigDecimal.ZERO, BigDecimal::add); // 求和
    }

    /**
     * 查询未开票的超市订单金额
     * @param memberList 成员 ID 列表
     * @return 超市订单金额
     */
    private BigDecimal getTotalMoneyForStoreOrders(List<Long> memberList,Long carteenId) {
        return storeOrderMapper.selectList(new LambdaQueryWrapperX<StoreOrderDO>()
                        .eq(StoreOrderDO::getStatus, StoreOrderStatusEnum.COMPLETE.getCode())
                        .eqIfPresent(StoreOrderDO::getCarteenId,carteenId)
                        .eq(StoreOrderDO::getBillingExist, Boolean.FALSE)
                        .isNull(StoreOrderDO::getBillingNum)
                        .in(StoreOrderDO::getUserId, memberList))
                .stream()
                .map(f -> BigDecimal.valueOf(f.getTotalPrice()))
                .reduce(BigDecimal.ZERO, BigDecimal::add); // 求和
    }
    private List<?> getOrders(Date time, Integer billingType,List<Long> ids,Long carteenId) {
        // 获取时间内的订单
        DateTime start = DateUtil.beginOfMonth(time);
        DateTime end = DateUtil.endOfMonth(time);
        switch (BillingEnum.fromCode(billingType)) {
            case BILLING_CANTEEN:
                return getDishOrderDO(start, end, ids,carteenId);
            case BILLING_SUPERMARKET:
                return getStoreOrderDO(start, end, ids,carteenId);
            case BILLING_SPACE_CAPSULE:
                return getOrderSpaceCapsuleDO(start, end, ids,carteenId);
            default:
                throw new IllegalArgumentException("Unsupported billing type");
        }
    }
    @Override
    public BigDecimal getTotalMoney(BillingPageDataVo vo) {
        // 获取当前单位下的所有成员
        List<Long> ids = getMemberListByUserId(vo.getUserId());
        List<?> data = getOrders(vo.getTime(), vo.getBillingType(), ids, vo.getCarteenId());
        // 根据账单类型计算总金额
        return calculateTotalMoneyByBillingType(vo.getBillingType(), data);
    }

    @Override
    public BigDecimal getUserTotalMoney(BillingPageDataVo vo) {
        // 获取当前单位下的所有成员
        List<Long> ids = getMemberListByUserId(vo.getUserId());
        if(CollUtil.isEmpty(ids)){
            return new BigDecimal(0);
        }
        List<CardDO> moneyByUserIds = cardMapper.getMoneyByUserIds(ids, CardDO.ADD, CostTypeEnum.ADMIN_PAY.getCode(), BillingStatusEnum.BILLING_INVOICING_REJECTION.getCode(),getMonth(),vo.getUserId());
        return moneyByUserIds.stream()
                .map(CardDO::getChangeMoney)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    @Override
    public Object getData(BillingPageDataVo vo) {
        // 获取当前单位下的所有成员
        List<Long> memberList = getMemberListByUserId(vo.getUserId());
        // 获取订单并返回
        PageResult<?> orders = getOrders(vo, memberList);
        if (ObjUtil.isEmpty(orders)) {
            throw exception(BILLING_NOT_ORDER_EXISTS);
        }
        return orders;
    }

    @Override
    public String getMemberId(Long userId) {
        //校验是否为管理员
        return memberGroupDO(userId).getId()+"";
    }

    @Override
    public Map<Integer, Integer> getBillingTypeTotal(Long carteenId, Long userId) {
        Map<Integer,Integer> map= MapUtil.newHashMap();
//        MemberGroupDO memberGroupDO = memberGroupDO(userId);
//        Long id = memberGroupDO.getId();
        List<BillingDO> billingDOS = billingMapper.selectList(new LambdaQueryWrapperX<BillingDO>()
                .eq(BillingDO::getUserPhone, userId)
                .eqIfPresent(BillingDO::getCarteenId,carteenId)
        );
        Map<Integer, List<BillingDO>> collect = billingDOS.stream().collect(Collectors.groupingBy(BillingDO::getStatus));
        map.put(BillingStatusEnum.BILLING_INVOICING.getCode(),0);
        map.put(BillingStatusEnum.BILLING_INVOICING_IS_COMPLETE.getCode(),0);
        map.put(BillingStatusEnum.BILLING_INVOICING_REJECTION.getCode(),0);
        for (Map.Entry<Integer, List<BillingDO>> entry : collect.entrySet()) {
            if (BillingStatusEnum.BILLING_INVOICING.getCode().equals(entry.getKey())) {
                map.put(entry.getKey(),entry.getValue().size());
            }
            if (BillingStatusEnum.BILLING_INVOICING_IS_COMPLETE.getCode().equals(entry.getKey())) {
                map.put(entry.getKey(),entry.getValue().size());
            }
            if (BillingStatusEnum.BILLING_INVOICING_REJECTION.getCode().equals(entry.getKey())) {
                map.put(entry.getKey(),entry.getValue().size());
            }
        }
        return map;
    }

    /**
     * 获取当前用户所属单位的所有成员列表
     * @param userId 当前用户 ID
     * @return 当前单位的所有成员 ID 列表
     */
    private List<Long> getMemberListByUserId(Long userId) {
        // 获取当前单位下的所有成员
//      return memberGroupMapper.getMemberList(memberGroupDO(userId).getId());
        return memberGroupMapper.getMemberList(userId);
    }
    private  MemberGroupDO memberGroupDO(Long userId){
        // 校验是否为管理员
        MemberGroupDO memberGroupDO = memberGroupMapper.selectOne(new LambdaQueryWrapperX<MemberGroupDO>()
                .eq(MemberGroupDO::getId, userId)
                .last(" limit 1"));
        if (memberGroupDO == null) {
            throw exception(GROUP_NOT_EXISTS);
        }
        return memberGroupDO;
    }
    /**
     * 根据账单类型计算订单的总金额
     * @param billingType 账单类型
     * @param orders 订单列表
     * @return 计算后的总金额
     */
    private BigDecimal calculateTotalMoneyByBillingType(Integer billingType, List<?> orders) {
        switch (BillingEnum.fromCode(billingType)) {
            case BILLING_CANTEEN:
                return calculateTotalMoney((List<DishOrderDO>) orders, DishOrderDO::getTotalMoney);
            case BILLING_SUPERMARKET:
                return calculateTotalMoney1((List<StoreOrderDO>) orders, StoreOrderDO::getTotalPrice);
            case BILLING_SPACE_CAPSULE:
                return calculateTotalMoney((List<OrderSpaceCapsuleDO>) orders, OrderSpaceCapsuleDO::getMoney);
            default:
                throw new IllegalArgumentException("Unsupported billing type: " + billingType);
        }
    }
    private PageResult<?> getOrders(BillingPageDataVo vo, List<Long> ids) {
        // 获取时间内的订单
        DateTime start = DateUtil.beginOfMonth(vo.getTime());
        DateTime end = DateUtil.endOfMonth(vo.getTime());
        switch (BillingEnum.fromCode(vo.getBillingType())) {
            case BILLING_CANTEEN:
                PageResult<DishOrderDO> dishOrderDO = getDishOrderDO(vo, start, end, ids);
                return BeanUtils.toBean(dishOrderDO, OrderDetailRespVO.class);
            case BILLING_SUPERMARKET:
                PageResult<StoreOrderDO> pageResult =getStoreOrderDO(vo, start, end, ids);
                PageResult<StoreOrderRespVO> bean = BeanUtils.toBean(pageResult, StoreOrderRespVO.class);
                //处理订单详情
                for (StoreOrderRespVO vo1 : bean.getList()) {
                    List<AppStoreOrderDetailVo> listByOrderNo = storeOrderDetailService.getListByOrderNo(vo1.getOrderId());
                    vo1.setDetailDOS(listByOrderNo);
                    vo1.setStoresName(carteenApi.getCarteenById(vo.getCarteenId()).getStoresName());
                }
                return bean;
            case BILLING_SPACE_CAPSULE:
                PageResult<OrderSpaceCapsuleDO> orderSpaceCapsuleDO = getOrderSpaceCapsuleDO(vo, start, end, ids);
                return BeanUtils.toBean(orderSpaceCapsuleDO, OrderSpaceCapsuleRespVO.class);
            default:
                throw new IllegalArgumentException("Unsupported billing type");
        }
    }
}