package com.cool.store.service.order.impl;

import cn.hutool.core.util.PageUtil;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.CommonConstants;
import com.cool.store.constants.RedisConstant;
import com.cool.store.context.LoginUserInfo;
import com.cool.store.dao.*;
import com.cool.store.dao.config.ConfigItemCategoryDAO;
import com.cool.store.dao.config.ConfigItemDAO;
import com.cool.store.dao.config.ConfigOptionDAO;
import com.cool.store.dao.dict.SysDictTableDAO;
import com.cool.store.dao.fees.WalletPayInfoDAO;

import com.cool.store.dao.order.PreAllocationRecordDAO;
import com.cool.store.dao.order.StoreOrderDAO;
import com.cool.store.dao.order.StoreOrderOptionSnapshotDAO;
import com.cool.store.dao.order.StoreWishlistDAO;
import com.cool.store.dao.order.StoreWishlistOptionDAO;
import com.cool.store.dao.store.StoreTypeDAO;
import com.cool.store.dao.store.StoreTypeOptionDAO;
import com.cool.store.dao.wallet.WalletTradeDAO;
import com.cool.store.dto.PointInfoDTO;
import com.cool.store.entity.*;
import com.cool.store.entity.config.ConfigOptionDO;
import com.cool.store.entity.dict.SysDictTableDO;
import com.cool.store.entity.fees.WalletPayInfoDO;
import com.cool.store.entity.order.PreAllocationRecordDO;
import com.cool.store.entity.order.StoreOrderDO;
import com.cool.store.entity.order.StoreOrderOptionSnapshotDO;
import com.cool.store.entity.order.StoreWishlistDO;
import com.cool.store.entity.order.StoreWishlistOptionDO;
import com.cool.store.entity.store.StoreTypeDO;
import com.cool.store.entity.store.StoreTypeOptionDO;
import com.cool.store.entity.wallet.WalletTradeDO;
import com.cool.store.enums.*;
import com.cool.store.enums.fees.AllocationPayStatusEnum;
import com.cool.store.enums.fees.PayTypeEnum;
import com.cool.store.enums.fees.WalletFeeItemEnum;
import com.cool.store.enums.order.StoreOrderStatusEnum;
import com.cool.store.enums.order.WishlistStatusEnum;
import com.cool.store.enums.point.ShopSubStageStatusEnum;
import com.cool.store.enums.wallet.WalletTradeModuleEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.dto.wallet.BatchTransferDTO;
import com.cool.store.mapper.FranchiseFeeMapper;
import com.cool.store.mapper.ShopAuditInfoMapper;
import com.cool.store.request.PointRecommendLineRequest;
import com.cool.store.request.SelectPointRequest;
import com.cool.store.request.SysRoleRequest;
import com.cool.store.request.order.*;
import com.cool.store.request.dict.DictColumnQueryRequest;
import com.cool.store.request.wallet.BatchTransferRequest;
import com.cool.store.request.xgj.PushFranchiseFeeRequest;
import com.cool.store.service.*;
import com.cool.store.service.dict.DictColumnService;
import com.cool.store.service.order.MiniStoreOrderService;
import com.cool.store.service.store.PreAllocationRecordService;
import com.cool.store.service.wallet.WalletApiService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.utils.GenerateNoUtil;
import com.cool.store.utils.RedisUtil;
import com.cool.store.vo.PartnerUserInfoVO;
import com.cool.store.vo.config.ConfigItemCategoryVO;
import com.cool.store.vo.config.ConfigItemVO;
import com.cool.store.vo.dict.DictColumnVO;
import com.cool.store.vo.order.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import groovy.util.logging.Slf4j;
import io.swagger.models.auth.In;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.cool.store.enums.UserRoleEnum.*;
import static com.cool.store.enums.fees.AllocationPayStatusEnum.PAID;
import static com.cool.store.enums.order.StoreOrderStatusEnum.*;
import static com.cool.store.enums.wallet.WalletTradeModuleEnum.STANDARD_STORE;

@lombok.extern.slf4j.Slf4j
@Service
@Slf4j
@RequiredArgsConstructor
public class MiniStoreOrderServiceImpl implements MiniStoreOrderService {

    private final StoreOrderDAO storeOrderDAO;
    private final StoreOrderOptionSnapshotDAO snapshotDAO;
    private final StoreWishlistDAO storeWishlistDAO;
    private final StoreWishlistOptionDAO storeWishlistOptionDAO;
    private final ShopInfoDAO shopInfoDAO;
    private final LineInfoDAO lineInfoDAO;
    private final StoreTypeDAO storeTypeDAO;
    private final StoreTypeOptionDAO storeTypeOptionDAO;
    private final ConfigOptionDAO configOptionDAO;
    private final DictColumnService dictColumnService;
    private final SysDictTableDAO dictTableInfoDAO;
    private final EnterpriseUserDAO enterpriseUserDAO;
    private final PreAllocationRecordService preAllocationRecordService;
    private final WalletApiService walletApiService;
    private final WalletPayInfoDAO walletPayInfoDAO;
    private final WalletTradeDAO walletTradeDAO;
    private final PreAllocationRecordDAO preAllocationRecordDAO;
    private final RedisUtil redisUtil;
    private final ShopStageInfoDAO shopStageInfoDAO;
    private final OperationLogService operationLogService;
    private final UserAuthMappingService userAuthMappingService;
    private final ShopAuditInfoMapper shopAuditInfoMapper;
    private final OperationLogDAO operationLogDAO;
    private final ConfigItemCategoryDAO configItemCategoryDAO;
    private final ConfigItemDAO configItemDAO;
    private final QualificationsInfoDAO qualificationsInfoDAO;
    private final PointService pointService;
    private final PointInfoDAO pointInfoDAO;
    private final ShopService shopService;
    private final FranchiseFeeMapper franchiseFeeMapper;
    private final PushService pushService;
    private final StoreOrderOptionSnapshotDAO storeOrderOptionSnapshotDAO;
    @Value("${spring.profiles.active}")
    private String active;


    @Override
    @Transactional
    public Long createOrder(MiniStoreOrderCreateRequest request,PartnerUserInfoVO user) {
        if (request == null || request.getShopId() == null || request.getStoreTypeId() == null) {
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }

        // 1) 未结束订单校验：草稿/待确认/待调整/待支付 不能重复新建
        if (storeOrderDAO.existsUnfinishedOrder(request.getShopId(), Arrays.asList(DRAFT.getCode(), WAIT_CONFIRM.getCode(),INVEST_MANAGER_CONFIRM.getCode(),
                WAIT_ADJUST.getCode(), WAIT_PAY.getCode(),PAY_FAIL.getCode()))) {
            throw new ServiceException(ErrorCodeEnum.SHOP_HAS_UNFINISHED_ORDER);
        }

        // 2) 已支付校验：门店已支付完成，不支持新建
        if (storeOrderDAO.existsPaidOrder(request.getShopId(), StoreOrderStatusEnum.PAID.getCode())) {
            throw new ServiceException(ErrorCodeEnum.SHOP_HAS_PAID_ORDER);
        }

        StoreTypeDO storeType = storeTypeDAO.getById(request.getStoreTypeId());
        if (storeType == null || Boolean.TRUE.equals(storeType.getDeleted()) || Boolean.FALSE.equals(storeType.getActive())) {
            throw new ServiceException(ErrorCodeEnum.CONFIG_NOT_EXIST);
        }

        ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(request.getShopId());
        if (shopInfo == null) {
            throw new ServiceException(ErrorCodeEnum.SHOP_NOT_EXIST);
        }

        Long lineId = shopInfo.getLineId();
        String investmentManager = shopInfo.getInvestmentManager();

        String partnerName = null;
        String partnerMobile = null;
        if (lineId != null) {
            LineInfoDO lineInfo = lineInfoDAO.getLineInfo(lineId);
            if (lineInfo != null) {
                partnerName = lineInfo.getUsername();
                partnerMobile = lineInfo.getMobile();
            }
        }

        List<StoreTypeOptionDO> bindings = storeTypeOptionDAO.listByStoreTypeId(request.getStoreTypeId());
        Map<Long, StoreTypeOptionDO> bindingMap = bindings.stream()
                .collect(Collectors.toMap(StoreTypeOptionDO::getOptionId, Function.identity(), (a, b) -> a));

        // 仅取本次下单所需的启用选项模板，避免全量查询
        Set<Long> optionIds = new HashSet<>();
        if (CollectionUtils.isNotEmpty(request.getSelectedOptions())) {
            for (MiniStoreOrderCreateRequest.SelectedOption selected : request.getSelectedOptions()) {
                if (selected == null || selected.getOptionId() == null) {
                    continue;
                }
                optionIds.add(selected.getOptionId());
            }
        }

        Map<Long, ConfigOptionDO> optionTemplateMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(optionIds)) {
            List<ConfigOptionDO> optionTemplates = configOptionDAO.listActiveByIds(new ArrayList<>(optionIds));
            optionTemplateMap = optionTemplates.stream()
                    .collect(Collectors.toMap(ConfigOptionDO::getId, Function.identity(), (a, b) -> a));
        }

        BigDecimal optionAmount = BigDecimal.ZERO;
        BigDecimal originalOptionAmount = BigDecimal.ZERO;
        List<StoreOrderOptionSnapshotDO> snapshotList = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(request.getSelectedOptions())) {
            Set<String> selectedItemCodes = new HashSet<>();

            for (MiniStoreOrderCreateRequest.SelectedOption selected : request.getSelectedOptions()) {
                if (selected == null || selected.getOptionId() == null) {
                    continue;
                }

                StoreTypeOptionDO binding = bindingMap.get(selected.getOptionId());
                if (binding == null) {
                    throw new ServiceException(ErrorCodeEnum.THE_OPTION_IS_NOT_PART_OF_THIS_STORE_TYPE);
                }

                ConfigOptionDO template = optionTemplateMap.get(selected.getOptionId());
                if (template == null || !Boolean.TRUE.equals(template.getActive())) {
                    throw new ServiceException(ErrorCodeEnum.CONFIG_NOT_EXIST);
                }

                /*String itemCode = template.getItemCode();
                if (itemCode != null && !selectedItemCodes.add(itemCode)) {
                    throw new ServiceException(ErrorCodeEnum.STORE_ORDER_ITEM_CODE_DUPLICATE);
                }*/

                //数量必须大于0
                BigDecimal quantity = selected.getQuantity();
                if (quantity == null) {
                    quantity = binding.getDefaultQuantity();
                }
                if (quantity == null || quantity.compareTo(BigDecimal.ZERO) < 0) {
                    throw new ServiceException(ErrorCodeEnum.THE_QUANTITY_MUST_BE_GREATER_THAN_0);
                }

                //校验选项数量不能修改
                BigDecimal defaultQty = binding.getDefaultQuantity();
//                if (binding.getAllowQuantityEdit() != null && binding.getAllowQuantityEdit() == 0) {
//                    if (defaultQty != null && defaultQty.compareTo(quantity)!=0) {
//                        throw new ServiceException(ErrorCodeEnum.THE_NUMBER_OF_OPTIONS_IS_NOT_MODIFIABLE);
//                    }
//                }

                BigDecimal price = binding.getOptionPrice() == null ? BigDecimal.ZERO : binding.getOptionPrice();
                BigDecimal originalPrice = template.getOriginalOptionPrice() == null ? BigDecimal.ZERO : template.getOriginalOptionPrice();

                BigDecimal amount = BigDecimal.ZERO;
                //小于默认数的时候
                if(defaultQty.compareTo(quantity)<=0){
                    amount = price.multiply(quantity);
                }else {
                    // 店型优惠价*默认数量 + 原价 *（选择数量-默认数量）
                    amount = price.multiply(defaultQty).add(originalPrice.multiply(quantity.subtract(defaultQty)));
                }
                BigDecimal originalAmount = originalPrice.multiply(quantity);
                optionAmount = optionAmount.add(amount);
                originalOptionAmount = originalOptionAmount.add(originalAmount);

                StoreOrderOptionSnapshotDO snapshot = StoreOrderOptionSnapshotDO.builder()
                        .shopId(request.getShopId())
                        .storeTypeId(request.getStoreTypeId())
                        .optionId(selected.getOptionId())
                        .categoryCode(template.getCategoryCode())
                        .itemCode(template.getItemCode())
                        .optionCode(template.getOptionCode())
                        .optionName(template.getOptionName())
                        .optionPrice(price)
                        .originalOptionPrice(originalPrice)
                        .optionRemark(template.getOptionRemark())
                        .imageUrl(template.getImageUrl())
                        .optionUnit(template.getOptionUnit())
                        .expenseTypeCode(template.getExpenseTypeCode())
                        .videoUrl(template.getVideoUrl())
                        .quantity(quantity)
                        .amount(amount)
                        .originalAmount(originalAmount)
                        .build();
                snapshotList.add(snapshot);
            }
        }

        BigDecimal storeFixedAmount = safe(storeType.getFranchiseFee())
                .add(safe(storeType.getBrandUsageFee()))
                .add(safe(storeType.getManagementFee()))
                .add(safe(storeType.getSystemUsageFee()))
                .add(safe(storeType.getDesignFee()))
                .add(safe(storeType.getFirstOrderFee()))
                .add(safe(storeType.getContractDeposit()))
                .add(safe(storeType.getDeviceDeposit()));

        BigDecimal originalStoreFixedAmount = safe(storeType.getOriginalFranchiseFee())
                .add(safe(storeType.getOriginalBrandUsageFee()))
                .add(safe(storeType.getOriginalManagementFee()))
                .add(safe(storeType.getOriginalSystemUsageFee()))
                .add(safe(storeType.getOriginalDesignFee()))
                .add(safe(storeType.getOriginalContractDeposit()))
                .add(safe(storeType.getOriginalDeviceDeposit()));

        BigDecimal totalAmount = storeFixedAmount.add(optionAmount);

        BigDecimal originalTotalAmount   = originalStoreFixedAmount.add(originalOptionAmount);

        StoreOrderDO order = StoreOrderDO.builder()
                .orderNo(generateOrderNo())
                .shopId(request.getShopId())
                .lineId(lineId)
                .partnerName(partnerName)
                .partnerMobile(partnerMobile)
                .investmentManager(investmentManager)
                .storeTypeId(storeType.getId())
                .storeTypeCode(storeType.getStoreTypeCode())
                .storeTypeName(storeType.getStoreTypeName())
                .storeType(storeType.getStoreType())
                .brand(storeType.getBrand())
                .franchiseFee(safe(storeType.getFranchiseFee()))
                .originalFranchiseFee(safe(storeType.getOriginalFranchiseFee()))
                .brandUsageFee(safe(storeType.getBrandUsageFee()))
                .originalBrandUsageFee(safe(storeType.getOriginalBrandUsageFee()))
                .managementFee(safe(storeType.getManagementFee()))
                .originalManagementFee(safe(storeType.getOriginalManagementFee()))
                .systemUsageFee(safe(storeType.getSystemUsageFee()))
                .originalSystemUsageFee(safe(storeType.getOriginalSystemUsageFee()))
                .contractDeposit(safe(storeType.getContractDeposit()))
                .originalContractDeposit(safe(storeType.getOriginalContractDeposit()))
                .deviceDeposit(safe(storeType.getDeviceDeposit()))
                .originalDeviceDeposit(safe(storeType.getOriginalDeviceDeposit()))
                .designFee(safe(storeType.getDesignFee()))
                .originalDesignFee(safe(storeType.getOriginalDesignFee()))
                .firstOrderFee(safe(storeType.getFirstOrderFee()))
                .storeFixedAmount(storeFixedAmount)
                .originalStoreFixedAmount(originalStoreFixedAmount)
                .optionAmount(optionAmount)
                .originalOptionAmount(originalOptionAmount)
                .totalAmount(totalAmount)
                .originalTotalAmount(originalTotalAmount)
                .paidAmount(BigDecimal.ZERO)
                .unpaidAmount(totalAmount)
                .status(WAIT_CONFIRM.getCode())
                .build();

        storeOrderDAO.insertSelective(order);

        if (CollectionUtils.isNotEmpty(snapshotList)) {
            for (StoreOrderOptionSnapshotDO snapshot : snapshotList) {
                snapshot.setOrderId(order.getId());
            }
            snapshotDAO.insertBatch(snapshotList);
        }
        //阶段状态
        shopStageInfoDAO.updateShopStageInfo(request.getShopId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_281);

        if (user!=null){
            operationLogService.addOperationLog(request.getShopId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_280, user.getPartnerId(), user.getUsername(),
                    OperationTypeEnum.OPERATION_TYPE_0, "店型选购提交", OperationStatusEnum.PROCESSED);

            SysRoleRequest sysRoleRequest = new SysRoleRequest();
            sysRoleRequest.setRoleName(AI_STORE_TYPE_APPROVE.getDesc());
            List<EnterpriseUserDO> userListByRole = userAuthMappingService.findUserListByRole(sysRoleRequest, false);
            operationLogService.addOperationLog(request.getShopId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_281,
                    user.getPartnerId(), userListByRole,
                    OperationTypeEnum.OPERATION_TYPE_1, "店型选购待立规审批", OperationStatusEnum.NOT_PROCESSED, 1);
        }

        return order.getId();
    }

    @Override
    public MiniStoreOrderDetailVO getDetail(Long orderId) {
        StoreOrderDO order = storeOrderDAO.getById(orderId);
        if (order == null) {
            return null;
        }

        List<StoreOrderOptionSnapshotDO> list = snapshotDAO.listByOrderId(orderId);

        ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(order.getShopId());

        StoreTypeDO storeType = storeTypeDAO.getById(order.getStoreTypeId());

        MiniStoreOrderDetailVO vo = new MiniStoreOrderDetailVO();

        MiniStoreOrderDetailVO.OrderInfoVO orderInfo = new MiniStoreOrderDetailVO.OrderInfoVO();
        orderInfo.setStoreType(order.getStoreType());
        orderInfo.setStoreTypeId(order.getStoreTypeId());
        orderInfo.setStoreTypeName(storeType.getStoreTypeName());
        orderInfo.setOrderNo(order.getOrderNo());
        orderInfo.setOrderId(order.getId());
        orderInfo.setShopId(order.getShopId());
        if (shopInfo!=null){
            orderInfo.setStoreId(shopInfo.getStoreId());
        }
        orderInfo.setCreateTime(order.getCreateTime());
        orderInfo.setStatus(order.getStatus());
        orderInfo.setPartnerName(order.getPartnerName());
        orderInfo.setPartnerMobile(order.getPartnerMobile());
        if (StringUtils.isNotBlank(order.getInvestmentManager())){
            orderInfo.setInvestmentManager(order.getInvestmentManager());
            String userName = enterpriseUserDAO.getUserName(order.getInvestmentManager());
            orderInfo.setInvestmentManagerName(userName);
        }
        vo.setOrderInfo(orderInfo);

        MiniStoreOrderDetailVO.PayInfoVO payInfo = new MiniStoreOrderDetailVO.PayInfoVO();
        payInfo.setTotalAmount(order.getTotalAmount());
        payInfo.setPaidAmount(order.getPaidAmount());
        payInfo.setUnpaidAmount(order.getUnpaidAmount());
        vo.setPayInfo(payInfo);

        MiniStoreOrderDetailVO.FeeInfoVO feeInfo = new MiniStoreOrderDetailVO.FeeInfoVO();
        feeInfo.setFranchiseFee(order.getFranchiseFee());
        feeInfo.setBrandUsageFee(order.getBrandUsageFee());
        feeInfo.setManagementFee(order.getManagementFee());
        feeInfo.setSystemUsageFee(order.getSystemUsageFee());
        feeInfo.setDesignFee(order.getDesignFee());
        feeInfo.setContractDeposit(order.getContractDeposit());
        feeInfo.setDeviceDeposit(order.getDeviceDeposit());
        feeInfo.setFirstOrderFee(order.getFirstOrderFee());
        feeInfo.setStoreFixedAmount(order.getStoreFixedAmount());
        vo.setFeeInfo(feeInfo);

        Map<String, String> categoryNameMap = configItemCategoryDAO.queryAllListMap();
        Map<String, String>  itemNameMap = configItemDAO.queryAllActiveMap();

        Map<String, Map<String, List<StoreOrderOptionSnapshotDO>>> groupMap = list.stream()
                .collect(Collectors.groupingBy(StoreOrderOptionSnapshotDO::getCategoryCode,
                        LinkedHashMap::new,
                        Collectors.groupingBy(StoreOrderOptionSnapshotDO::getItemCode,
                                LinkedHashMap::new,
                                Collectors.toList())));

        Set<Long> optinIdList = list.stream().map(StoreOrderOptionSnapshotDO::getOptionId).collect(Collectors.toSet());
        List<StoreTypeOptionDO> storeTypeOptionDOS = storeTypeOptionDAO.selectByIds(new ArrayList<>(optinIdList),orderInfo.getStoreTypeId());

        List<ConfigOptionDO> configOptionDOS = configOptionDAO.listActiveByIds(new ArrayList<>(optinIdList));
        Map<Long, ConfigOptionDO> doMap = configOptionDOS.stream().collect(Collectors.toMap(ConfigOptionDO::getId, data -> data));

        Map<Long, BigDecimal> defaultQuantityMap = storeTypeOptionDOS.stream().collect(Collectors.toMap(StoreTypeOptionDO::getOptionId, StoreTypeOptionDO::getDefaultQuantity,(existing, replacement) -> existing));
       List<MiniStoreOrderDetailVO.CategoryVO> categoryVOList = new ArrayList<>();
        for (Map.Entry<String, Map<String, List<StoreOrderOptionSnapshotDO>>> cEntry : groupMap.entrySet()) {
            String categoryCode = cEntry.getKey();
            MiniStoreOrderDetailVO.CategoryVO cvo = new MiniStoreOrderDetailVO.CategoryVO();
            cvo.setCategoryCode(categoryCode);
            cvo.setCategoryName(categoryNameMap.getOrDefault(categoryCode, categoryCode));

            List<MiniStoreOrderDetailVO.ItemVO> itemVOList = new ArrayList<>();
            for (Map.Entry<String, List<StoreOrderOptionSnapshotDO>> iEntry : cEntry.getValue().entrySet()) {
                String itemCode = iEntry.getKey();
                MiniStoreOrderDetailVO.ItemVO ivo = new MiniStoreOrderDetailVO.ItemVO();
                ivo.setItemCode(itemCode);
                ivo.setItemName(itemNameMap.getOrDefault(itemCode, itemCode));

                List<MiniStoreOrderDetailVO.OptionVO> optionVOList = iEntry.getValue().stream()
                        .map(v -> {
                            MiniStoreOrderDetailVO.OptionVO ovo = new MiniStoreOrderDetailVO.OptionVO();
                            ovo.setOptionId(v.getOptionId());
                            ovo.setOptionName(v.getOptionName());
                            ovo.setOptionPrice(v.getOptionPrice());
                            ovo.setOriginalOptionPrice(v.getOriginalOptionPrice());
                            ovo.setQuantity(v.getQuantity());
                            ovo.setOptionUnit(v.getOptionUnit());
                            ovo.setAmount(v.getAmount());
                            ovo.setOriginalAmount(v.getOriginalAmount());
                            ovo.setImageUrl(v.getImageUrl());
                            ovo.setExpenseTypeCode(v.getExpenseTypeCode());
                            ovo.setDefaultQuantity(defaultQuantityMap.get(v.getOptionId()));
                            ConfigOptionDO configOptionDO = doMap.getOrDefault(v.getOptionId(),new ConfigOptionDO());
                            ovo.setOptionRemark(configOptionDO.getOptionRemark());
                            return ovo;
                        })
                        .collect(Collectors.toList());
                ivo.setOptions(optionVOList);
                itemVOList.add(ivo);
            }
            cvo.setItems(itemVOList);
            categoryVOList.add(cvo);
        }
        vo.setConfigSnapshot(categoryVOList);

        return vo;
    }

    @Override
    public MiniStoreOrderDetailVO getCurrentShopDraft(Long shopId) {
        if (shopId == null) {
            return null;
        }
        StoreOrderDO order = storeOrderDAO.getLatestByShopIdAndStatus(shopId, DRAFT.getCode());
        if (order == null || order.getId() == null) {
            return null;
        }
        return getDetail(order.getId());
    }

    @Override
    public MiniStoreOrderDetailVO getLatestOrderByShopId(Long shopId) {
        if (shopId == null) {
            return null;
        }
        StoreOrderDO order = storeOrderDAO.getLatestOrderByShopId(shopId);
        if (order == null || order.getId() == null) {
            return null;
        }
        return getDetail(order.getId());
    }

    @Override
    public PageInfo<MiniStoreOrderListVO> queryPage(MiniStoreOrderQueryRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<StoreOrderDO> list = storeOrderDAO.queryPage(request.getShopId(), request.getStatus());
        PageInfo<StoreOrderDO> page = new PageInfo<>(list);

        PageInfo<MiniStoreOrderListVO> result = BeanUtil.toPage(page, MiniStoreOrderListVO.class);

        List<Long> shopIds = result.getList().stream()
                .map(MiniStoreOrderListVO::getShopId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        List<ShopInfoDO> shopList = shopInfoDAO.getShopListByIds(shopIds);
        Map<Long, String> shopIdMap = shopList.stream().collect(Collectors.toMap(ShopInfoDO::getId, ShopInfoDO::getStoreId));

        List<Long> storeTypeList = result.getList().stream()
                .map(MiniStoreOrderListVO::getStoreTypeId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        List<StoreTypeDO> storeTypeDOS = storeTypeDAO.selectByIds(storeTypeList);
        Map<Long, String> imageMap = storeTypeDOS.stream().collect(Collectors.toMap(StoreTypeDO::getId, StoreTypeDO::getImageUrl));

        result.getList().forEach(x->{
            x.setStoreId(shopIdMap.get(x.getShopId()));
            x.setImageUrl(imageMap.get(x.getStoreTypeId()));
        });

        return result;
    }

    @Override
    public PageInfo<MiniStoreOrderListVO> queryPageByLineId(MiniStoreOrderLineQueryRequest request) {
        if (request.getLineId()==null){
            return new PageInfo<>();
        }
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<StoreOrderDO> list = storeOrderDAO.queryPageByLineId(request.getLineId(), request.getStatus());

        PageInfo<MiniStoreOrderListVO> page = BeanUtil.toPage(new PageInfo<>(list), MiniStoreOrderListVO.class);

        List<MiniStoreOrderListVO> voList = page.getList();

        // 批量补齐门店名称
        List<Long> shopIds = voList.stream()
                .map(MiniStoreOrderListVO::getShopId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(shopIds)) {
            List<ShopInfoDO> shops = shopInfoDAO.getShopListByIds(shopIds);
            Map<Long, ShopInfoDO> shopNameMap = shops.stream()
                    .filter(s -> s.getId() != null)
                    .collect(Collectors.toMap(ShopInfoDO::getId, data->data));
            for (MiniStoreOrderListVO vo : voList) {
                if (vo.getShopId() == null) {
                    continue;
                }
                ShopInfoDO shopInfoDO = shopNameMap.get(vo.getShopId());
                if (shopInfoDO!=null){
                    vo.setShopName(shopInfoDO.getShopName());
                    vo.setStoreId(shopInfoDO.getStoreId());
                }

            }
        }
        return page;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean passOrder(OrderAuditRecordRequest request,LoginUserInfo user) {
        StoreOrderDO order = storeOrderDAO.getById(request.getOrderId());
        if (order==null){
            throw new ServiceException(ErrorCodeEnum.STORE_ORDER_NOT_FOUND);
        }
        //当前订单状态
        Integer currentStatus = order.getStatus();

        //校验订单是否是待审核
        if (!StoreOrderStatusEnum.approve(currentStatus)){
            throw new ServiceException(ErrorCodeEnum.CURRENT_ORDER_NOT_SUPPORT);
        }
        if (WAIT_CONFIRM.getCode().equals(currentStatus)){
            //修改订单状态
            order.setStatus(DEVICE_CONFIRM.getCode());
            storeOrderDAO.updateSelective(order);

            //修改阶段数据
            shopStageInfoDAO.updateShopStageInfo(order.getShopId(),ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_281_2);

            //处理审批记录 通过
            handleAudit(order.getShopId(),user,0,request.getRemark(),ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_281);

            //下一级审批记录
            SysRoleRequest sysRoleRequest = new SysRoleRequest();
            sysRoleRequest.setRoleName(AI_STORE_TYPE_APPROVE.getDesc());
            List<EnterpriseUserDO> userListByRole = userAuthMappingService.findUserListByRole(sysRoleRequest, false);
            operationLogService.addOperationLog(order.getShopId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_281_2,
                    user.getUserId(), userListByRole,
                    OperationTypeEnum.OPERATION_TYPE_1, "待采购设备确认", OperationStatusEnum.NOT_PROCESSED, 1);

        }
        if (DEVICE_CONFIRM.getCode().equals(currentStatus)){
            //修改订单状态
            order.setStatus(INVEST_MANAGER_CONFIRM.getCode());
            storeOrderDAO.updateSelective(order);

            //修改阶段数据
            shopStageInfoDAO.updateShopStageInfo(order.getShopId(),ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_281_5);

            //处理审批记录 通过
            handleAudit(order.getShopId(),user,0,request.getRemark(),ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_281_2);

        }
        if (INVEST_MANAGER_CONFIRM.getCode().equals(currentStatus)){
            order.setStatus(FINANCIAL_CONFIRM.getCode());
            storeOrderDAO.updateSelective(order);

            //修改阶段数据
            shopStageInfoDAO.updateShopStageInfo(order.getShopId(),ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_282);

            //推送加盟费账单
            preAllocationRecordService.pushStandardStoreFee(order);
        }
        return Boolean.TRUE;
    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean rejectOrder(OrderAuditRecordRequest request,LoginUserInfo userInfo) {
        StoreOrderDO order = storeOrderDAO.getById(request.getOrderId());
        if (order==null){
            throw new ServiceException(ErrorCodeEnum.STORE_ORDER_NOT_FOUND);
        }
        Integer currentStatus = order.getStatus();
        //校验订单是否是待审核
        if (!StoreOrderStatusEnum.approve(currentStatus)){
            throw new ServiceException(ErrorCodeEnum.CURRENT_ORDER_NOT_SUPPORT);
        }
        //修改订单状态 变为待调整
        order.setStatus(StoreOrderStatusEnum.WAIT_ADJUST.getCode());
        storeOrderDAO.updateSelective(order);

        //修改阶段数据 阶段变为审批拒绝
        shopStageInfoDAO.updateShopStageInfo(order.getShopId(),ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_283);

        ShopSubStageStatusEnum current = null;
        if (WAIT_CONFIRM.getCode().equals(currentStatus)){
            current = ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_281;
            //处理审批记录
            handleAudit(order.getShopId(),userInfo,1,request.getRemark(),current);
        }

        return Boolean.TRUE;
    }

    private void handleAudit(Long shopId,LoginUserInfo user,Integer resultType,String remark,ShopSubStageStatusEnum stageStatusEnum){
        ShopAuditInfoDO shopAuditInfoDO = new ShopAuditInfoDO();
        shopAuditInfoDO.setShopId(shopId);
        shopAuditInfoDO.setAuditType(AuditTypeEnum.STANDARD_STORE.getCode());
        shopAuditInfoDO.setSubmittedUserId(user.getUserId());
        shopAuditInfoDO.setSubmittedUserName(user.getName());
        shopAuditInfoDO.setResultType(resultType);
        if (resultType==0){
            shopAuditInfoDO.setPassReason(remark);
        }else {
            shopAuditInfoDO.setRejectReason(remark);
        }
        shopAuditInfoMapper.insertSelective(shopAuditInfoDO);
        Long auditId = shopAuditInfoDO.getId();
        List<OperationLogDO> operationLogs = operationLogDAO.getBySubStageStatusEnumAndsStatus(shopId, stageStatusEnum, OperationTypeEnum.OPERATION_TYPE_1.getCode());
        operationLogService.batchUpdateProcessed(operationLogs, auditId, user.getUserId(), remark);
    }


    @Override
    @Transactional
    public Long updateOrder(MiniStoreOrderUpdateRequest request,PartnerUserInfoVO user) {
        log.info("updateOrder request:{},操作人:{}",JSONObject.toJSONString(request),user.getUsername());
        if (request == null || request.getOrderId() == null || request.getShopId() == null || request.getStoreTypeId() == null) {
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }

        // 1. 查询原订单
        StoreOrderDO order = storeOrderDAO.getById(request.getOrderId());
        if (order == null || !order.getShopId().equals(request.getShopId())) {
            throw new ServiceException(ErrorCodeEnum.STORE_ORDER_NOT_FOUND);
        }

        // 2. 校验订单状态：仅草稿(0)和待调整(10)状态允许修改
        Integer status = order.getStatus();
        if (!StoreOrderStatusEnum.DRAFT.getCode().equals(status)  && !StoreOrderStatusEnum.WAIT_ADJUST.getCode().equals(status)) {
            throw new ServiceException(ErrorCodeEnum.STORE_ORDER_UPDATE_FORBIDDEN);
        }

        // 3. 查询新店型信息
        StoreTypeDO storeType = storeTypeDAO.getById(request.getStoreTypeId());
        if (storeType == null || Boolean.TRUE.equals(storeType.getDeleted()) ||
                !Boolean.TRUE.equals(storeType.getActive())) {
            throw new ServiceException(ErrorCodeEnum.CONFIG_NOT_EXIST);
        }

        // 4. 获取新店型的选项绑定关系
        List<StoreTypeOptionDO> bindings = storeTypeOptionDAO.listByStoreTypeId(request.getStoreTypeId());
        Map<Long, StoreTypeOptionDO> bindingMap = bindings.stream()
                .collect(Collectors.toMap(StoreTypeOptionDO::getOptionId, Function.identity(), (a, b) -> a));

        // 5. 处理选中的配置选项
        BigDecimal optionAmount = BigDecimal.ZERO;
        BigDecimal originalOptionAmount = BigDecimal.ZERO;
        List<StoreOrderOptionSnapshotDO> snapshotList = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(request.getSelectedOptions())) {
            Set<Long> optionIds = request.getSelectedOptions().stream()
                    .filter(Objects::nonNull)
                    .map(MiniStoreOrderCreateRequest.SelectedOption::getOptionId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            // 查询选项模板
            Map<Long, ConfigOptionDO> optionTemplateMap = new HashMap<>();
            if (!optionIds.isEmpty()) {
                List<ConfigOptionDO> optionTemplates = configOptionDAO.listActiveByIds(new ArrayList<>(optionIds));
                optionTemplateMap = optionTemplates.stream()
                        .collect(Collectors.toMap(ConfigOptionDO::getId, Function.identity(), (a, b) -> a));
            }

            // 校验并计算金额
            Set<String> selectedItemCodes = new HashSet<>();
            for (MiniStoreOrderCreateRequest.SelectedOption selected : request.getSelectedOptions()) {
                if (selected == null || selected.getOptionId() == null) {
                    continue;
                }

                StoreTypeOptionDO binding = bindingMap.get(selected.getOptionId());
                if (binding == null) {
                    throw new ServiceException(ErrorCodeEnum.THE_OPTION_IS_NOT_PART_OF_THIS_STORE_TYPE);
                }

                ConfigOptionDO template = optionTemplateMap.get(selected.getOptionId());
                if (template == null || !Boolean.TRUE.equals(template.getActive())) {
                    throw new ServiceException(ErrorCodeEnum.CONFIG_NOT_EXIST);
                }

//                String itemCode = template.getItemCode();
//                if (itemCode != null && !selectedItemCodes.add(itemCode)) {
//                    throw new ServiceException(ErrorCodeEnum.STORE_ORDER_ITEM_CODE_DUPLICATE);
//                }

                // 处理数量
                BigDecimal quantity = selected.getQuantity();
                if (quantity == null) {
                    quantity = binding.getDefaultQuantity();
                }
                if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) {
                    throw new ServiceException(ErrorCodeEnum.THE_QUANTITY_MUST_BE_GREATER_THAN_0);
                }

                // 校验不可修改数量的选项
                BigDecimal defaultQty = binding.getDefaultQuantity();
                if (binding.getAllowQuantityEdit() != null && binding.getAllowQuantityEdit() == 0) {
                    if (defaultQty != null && defaultQty.compareTo(quantity)!=0) {
                        throw new ServiceException(ErrorCodeEnum.THE_NUMBER_OF_OPTIONS_IS_NOT_MODIFIABLE);
                    }
                }

                //使用店型上配置的价格 不能使用选项的配置上的价格
                BigDecimal price = binding.getOptionPrice() == null ? BigDecimal.ZERO : binding.getOptionPrice();
                BigDecimal originalPrice = template.getOriginalOptionPrice() == null ? BigDecimal.ZERO : template.getOriginalOptionPrice();

                BigDecimal amount = BigDecimal.ZERO;
                //小于默认数的时候
                if(quantity.compareTo(defaultQty)<=0){
                    amount = price.multiply(quantity);
                }else {
                    // 店型优惠价*默认数量 + 原价 *（选择数量-默认数量）
                    amount = price.multiply(defaultQty).add(originalPrice.multiply(quantity.subtract(defaultQty)));
                }
                BigDecimal originalAmount = originalPrice.multiply(quantity);
                optionAmount = optionAmount.add(amount);
                originalOptionAmount = originalOptionAmount.add(originalAmount);

                // 创建快照
                StoreOrderOptionSnapshotDO snapshot = StoreOrderOptionSnapshotDO.builder()
                        .orderId(order.getId())
                        .shopId(order.getShopId())
                        .storeTypeId(storeType.getId())
                        .optionId(selected.getOptionId())
                        .categoryCode(template.getCategoryCode())
                        .itemCode(template.getItemCode())
                        .optionCode(template.getOptionCode())
                        .optionName(template.getOptionName())
                        .optionPrice(price)
                        .originalOptionPrice(originalPrice)
                        .optionUnit(template.getOptionUnit())
                        .optionRemark(template.getOptionRemark())
                        .expenseTypeCode(template.getExpenseTypeCode())
                        .imageUrl(template.getImageUrl())
                        .videoUrl(template.getVideoUrl())
                        .quantity(quantity)
                        .amount(amount)
                        .originalAmount(originalAmount)
                        .build();
                snapshotList.add(snapshot);
            }
        }

        // 6. 计算固定费用和总金额
        BigDecimal storeFixedAmount = safe(storeType.getFranchiseFee())
                .add(safe(storeType.getBrandUsageFee()))
                .add(safe(storeType.getManagementFee()))
                .add(safe(storeType.getSystemUsageFee()))
                .add(safe(storeType.getDesignFee()))
                .add(safe(storeType.getFirstOrderFee()))
                .add(safe(storeType.getContractDeposit()))
                .add(safe(storeType.getDeviceDeposit()));


        BigDecimal originalStoreFixedAmount = safe(storeType.getOriginalFranchiseFee())
                .add(safe(storeType.getOriginalBrandUsageFee()))
                .add(safe(storeType.getOriginalManagementFee()))
                .add(safe(storeType.getOriginalSystemUsageFee()))
                .add(safe(storeType.getOriginalDesignFee()))
                .add(safe(storeType.getOriginalContractDeposit()))
                .add(safe(storeType.getOriginalDeviceDeposit()));

        BigDecimal totalAmount = storeFixedAmount.add(optionAmount);

        BigDecimal originalTotalAmount   = originalStoreFixedAmount.add(originalOptionAmount);

        // 7. 更新订单信息
        StoreOrderDO updateOrder = StoreOrderDO.builder()
                .id(order.getId())
                .storeTypeId(storeType.getId())
                .storeTypeCode(storeType.getStoreTypeCode())
                .storeTypeName(storeType.getStoreTypeName())
                .storeType(storeType.getStoreType())
                .brand(storeType.getBrand())
                .franchiseFee(safe(storeType.getFranchiseFee()))
                .originalFranchiseFee(safe(storeType.getOriginalFranchiseFee()))
                .brandUsageFee(safe(storeType.getBrandUsageFee()))
                .originalBrandUsageFee(safe(storeType.getOriginalBrandUsageFee()))
                .managementFee(safe(storeType.getManagementFee()))
                .originalManagementFee(safe(storeType.getOriginalManagementFee()))
                .systemUsageFee(safe(storeType.getSystemUsageFee()))
                .originalSystemUsageFee(safe(storeType.getOriginalSystemUsageFee()))
                .contractDeposit(safe(storeType.getContractDeposit()))
                .originalContractDeposit(safe(storeType.getOriginalContractDeposit()))
                .deviceDeposit(safe(storeType.getDeviceDeposit()))
                .originalDeviceDeposit(safe(storeType.getOriginalDeviceDeposit()))
                .designFee(safe(storeType.getDesignFee()))
                .originalDesignFee(safe(storeType.getOriginalDesignFee()))
                .firstOrderFee(safe(storeType.getFirstOrderFee()))
                .storeFixedAmount(storeFixedAmount)
                .originalStoreFixedAmount(originalStoreFixedAmount)
                .optionAmount(optionAmount)
                .originalOptionAmount(originalOptionAmount)
                .totalAmount(totalAmount)
                .originalTotalAmount(originalTotalAmount)
                .unpaidAmount(totalAmount.subtract(order.getPaidAmount()))
                .status(WAIT_CONFIRM.getCode())
                .updateTime(new Date())
                .build();

        // 8. 删除旧快照并保存新快照
        snapshotDAO.deleteByOrderId(order.getId());
        if (!snapshotList.isEmpty()) {
            snapshotDAO.insertBatch(snapshotList);
        }

        // 9. 更新订单
        storeOrderDAO.updateSelective(updateOrder);

        //阶段变为待选购
        shopStageInfoDAO.updateShopStageInfo(order.getShopId(),ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_281);

        operationLogService.addOperationLog(request.getShopId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_280, user.getPartnerId(), user.getUsername(),
                OperationTypeEnum.OPERATION_TYPE_0, "店型选购提交", OperationStatusEnum.PROCESSED);

        SysRoleRequest sysRoleRequest = new SysRoleRequest();
        sysRoleRequest.setRoleName(AI_STORE_TYPE_APPROVE.getDesc());
        List<EnterpriseUserDO> userListByRole = userAuthMappingService.findUserListByRole(sysRoleRequest, false);
        operationLogService.addOperationLog(request.getShopId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_281,
                user.getPartnerId(), userListByRole,
                OperationTypeEnum.OPERATION_TYPE_1, "店型选购待立规审批", OperationStatusEnum.NOT_PROCESSED, 1);

        return order.getId();
    }

//    @Override
//    @Transactional
//    public Boolean withdraw(Long orderId) {
//        if (orderId == null) {
//            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
//        }
//
//        // 1. 查询订单
//        StoreOrderDO order = storeOrderDAO.getById(orderId);
//        if (order == null) {
//            throw new ServiceException(ErrorCodeEnum.STORE_ORDER_NOT_FOUND);
//        }
//
//        // 2. 校验状态：仅待确认(5)和待支付(15)状态允许撤回
//        Integer status = order.getStatus();
//        if (!StoreOrderStatusEnum.canWithdraw(status)) {
//            throw new ServiceException(ErrorCodeEnum.STORE_ORDER_WITHDRAW_FORBIDDEN);
//        }
//
//        // 3. 更新订单状态为草稿(0)
//        StoreOrderDO updateOrder = StoreOrderDO.builder()
//                .id(orderId)
//                .status(StoreOrderStatusEnum.DRAFT.getCode())
//                .updateTime(new Date())
//                .build();
//
//        shopStageInfoDAO.updateShopStageInfo(order.getShopId(),ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_280);
//
//        return storeOrderDAO.updateSelective(updateOrder);
//    }
//
//    @Override
//    @Transactional
//    public Boolean cancel(Long orderId) {
//        if (orderId == null) {
//            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
//        }
//
//        // 1. 查询订单
//        StoreOrderDO order = storeOrderDAO.getById(orderId);
//        if (order == null) {
//            throw new ServiceException(ErrorCodeEnum.STORE_ORDER_NOT_FOUND);
//        }
//
//        // 2. 校验状态：仅草稿(0)状态允许作废
//        if (!StoreOrderStatusEnum.DRAFT.getCode().equals(order.getStatus())) {
//            throw new ServiceException(ErrorCodeEnum.STORE_ORDER_CANCEL_FORBIDDEN);
//        }
//
//        // 3. 更新订单状态为已结束(25)
//        StoreOrderDO updateOrder = StoreOrderDO.builder()
//                .id(orderId)
//                .status(StoreOrderStatusEnum.CLOSED.getCode()) // 已结束状态
//                .updateTime(new Date())
//                .build();
//
//
//        return storeOrderDAO.updateSelective(updateOrder);
//    }

    @Override
    @Transactional
    public Boolean payOrder(MiniStoreOrderPayRequest request, PartnerUserInfoVO userInfo) {
//        log.info("订单开始支付 payOrder：{},userInfo:{}", JSONObject.toJSONString(request),JSONObject.toJSONString(userInfo));
//        //重复支付校验
//        String lockKey = MessageFormat.format(RedisConstant.STANDARD_STORE_PAY_LOCK_KEY, request.getOrderId());
//        Boolean lock = redisUtil.tryLock(lockKey, lockKey, 10, TimeUnit.SECONDS);
//        if (!Boolean.TRUE.equals(lock)) {
//            throw new ServiceException(ErrorCodeEnum.DUPLICATE_PAYMENTS);
//        }
//        try {
//            // 1. 参数校验
//            if (request == null || request.getOrderId() == null || request.getAmount() == null ||
//                    StringUtils.isBlank(request.getPayPwd())) {
//                throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
//            }
//
//            // 2. 查询订单信息
//            StoreOrderDO order = storeOrderDAO.getById(request.getOrderId());
//            if (order == null) {
//                throw new ServiceException(ErrorCodeEnum.STORE_ORDER_NOT_FOUND);
//            }
//
//            // 3. 校验订单状态：仅待支付状态可以支付
//            if (!StoreOrderStatusEnum.WAIT_PAY.getCode().equals(order.getStatus())) {
//                throw new ServiceException(ErrorCodeEnum.STORE_ORDER_STATUS_INVALID);
//            }
//
//            // 4. 校验支付金额与订单金额是否一致
//            if (request.getAmount().compareTo(order.getTotalAmount()) != 0) {
//                throw new ServiceException(ErrorCodeEnum.PAY_AMOUNT_ERROR);
//            }
//
//            // 5. 查询门店信息
//            ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(order.getShopId());
//            if (shopInfo == null) {
//                throw new ServiceException(ErrorCodeEnum.SHOP_NOT_EXIST);
//            }
//
//            // 6. 按门店查询预分账明细
//            List<PreAllocationRecordDO> allocationRecords = preAllocationRecordService.listDOByShop(order.getShopId());
//            if (CollectionUtils.isEmpty(allocationRecords)) {
//                throw new ServiceException(ErrorCodeEnum.THERE_IS_NO_PAYMENT_INFORMATION);
//            }
//
//            // 7. 校验预分账明细金额总和是否等于订单金额
//            BigDecimal allocationTotal = allocationRecords.stream()
//                    .filter(record -> record != null && record.getPayAmount() != null)
//                    .map(PreAllocationRecordDO::getPayAmount)
//                    .reduce(BigDecimal.ZERO, BigDecimal::add);
//
//            if (allocationTotal.compareTo(order.getTotalAmount()) != 0) {
//                throw new ServiceException(ErrorCodeEnum.FEE_NOT_CONSISTENT);
//            }
//
//            // 9. 封装批量分账请求
//            BatchTransferRequest batchTransferRequest = new BatchTransferRequest();
//            batchTransferRequest.setOutStoreId(shopInfo.getStoreId());
//            batchTransferRequest.setPayPwd(request.getPayPwd());
//            batchTransferRequest.setWalletType(2);
//
//            List<BatchTransferRequest.TransDataRequest> transArray = new ArrayList<>();
//            for (PreAllocationRecordDO record : allocationRecords) {
//                BatchTransferRequest.TransDataRequest transData = new BatchTransferRequest.TransDataRequest();
//
//                // payNo 必须唯一且失败重试要沿用第一次的 payNo
//                String payNo = record.getPayNo();
//                if (StringUtils.isBlank(payNo)) {
//                    payNo = GenerateNoUtil.generateMillsNoWithRandom();
//                    record.setPayNo(payNo);
//                }
//                transData.setReqNo(payNo);
//
//                // 根据费用类型获取费用科目ID
//                WalletFeeItemEnum feeItem = WalletFeeItemEnum.getByExpenseType(record.getExpenseType());
//                if (feeItem == null) {
//                    throw new ServiceException(ErrorCodeEnum.NONSUPPORT_EXPENSE_TYPE);
//                }
//                transData.setFeeItemId(feeItem.getFeeItemId());
//                transData.setCompanyCode(record.getPayeeCode());
//                transData.setAmount(record.getPayAmount().toString());
//
//                transArray.add(transData);
//            }
//            batchTransferRequest.setTransArray(transArray);
//            Map<String, PreAllocationRecordDO> map = allocationRecords.stream().collect(Collectors.toMap(PreAllocationRecordDO::getPayNo, data -> data));
//
//            // 调用第三方前先固化 payNo（失败重试需要复用）
//            preAllocationRecordDAO.updateBatch(allocationRecords);
//
//            // 10. 调用第三方分账接口
//            BatchTransferDTO batchTransferResult;
//            try {
//                batchTransferResult = walletApiService.batchTransfer(batchTransferRequest);
//            } catch (Exception e) {
//                throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR.getCode(), "支付失败：" + e.getMessage());
//            }
//
//            // 11. 处理分账结果
//            if (batchTransferResult == null || batchTransferResult.getTradeStatus() == null) {
//                throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR.getCode(), "支付失败：分账接口返回异常");
//            }
//
//            // 12. 根据分账结果更新状态和记录
//            List<WalletPayInfoDO> walletPayInfoList = new ArrayList<>();
//            List<WalletTradeDO> walletTradeList = new ArrayList<>();
//            List<PreAllocationRecordDO> updatedRecords = new ArrayList<>();
//
//            //批量支付状态 1.成功 2.失败 3.处理中（目前是实时转账 无处理中）
//            Integer tradeStatus = batchTransferResult.getTradeStatus();
//
//            // 订单状态
//            Integer orderStatus = null;
//
//            // 按批次结果全成/全败
//            Integer allocationStatus;
//            Integer payStatus;
//            if (tradeStatus != null && tradeStatus == 1) {
//                allocationStatus = 1;
//                payStatus = AllocationPayStatusEnum.PAID.getStatus();
//                orderStatus = StoreOrderStatusEnum.PAID.getCode();
//            } else {
//                allocationStatus = 0;
//                payStatus = AllocationPayStatusEnum.FAIL.getStatus();
//                orderStatus = PAY_FAIL.getCode();
//            }
//
//            // 无论成功失败，都需要落库，并更新预分账状态
//            if (batchTransferResult.getTransArray() != null) {
//                for (int i = 0; i < batchTransferResult.getTransArray().size() && i < allocationRecords.size(); i++) {
//                    BatchTransferDTO.TransDataRequest result = batchTransferResult.getTransArray().get(i);
//                    PreAllocationRecordDO record = map.get(result.getReqNo());
//                    if (record == null) {
//                        continue;
//                    }
//
//                    record.setAllocationStatus(allocationStatus);
//                    updatedRecords.add(record);
//
//                    WalletPayInfoDO walletPayInfo = new WalletPayInfoDO();
//                    walletPayInfo.setShopId(order.getShopId());
//                    walletPayInfo.setModule(STANDARD_STORE.getModule());
//                    walletPayInfo.setPayNo(result.getReqNo());
//                    walletPayInfo.setPayUserName(userInfo.getUsername());
//                    walletPayInfo.setPayAmount(new BigDecimal(result.getAmount()));
//                    walletPayInfo.setPayStatus(payStatus);
//                    walletPayInfo.setPayTime(new Date());
//                    walletPayInfo.setClaimStatus(ClaimStatusEnum.TO_BE_CLAIMED.getCode());
//                    walletPayInfo.setExpenseTypes(record.getExpenseType());
//                    walletPayInfo.setCreateTime(new Date());
//                    walletPayInfo.setTradeId(result.getTradeId());
//                    walletPayInfoList.add(walletPayInfo);
//
//                    WalletTradeDO walletTrade = new WalletTradeDO();
//                    walletTrade.setModule(STANDARD_STORE.getModule());
//                    walletTrade.setPayNo(result.getReqNo());
//                    walletTrade.setTradeId(result.getTradeId());
//                    walletTrade.setType(1);
//                    walletTrade.setPayUserName(userInfo.getUsername());
//                    walletTrade.setPayAmount(new BigDecimal(result.getAmount()));
//                    walletTrade.setPayStatus(payStatus);
//                    walletTrade.setPayTime(new Date());
//                    walletTrade.setCreateTime(new Date());
//                    walletTradeList.add(walletTrade);
//                }
//            }
//
//            // 13. 保存钱包支付信息/交易单：payNo 唯一索引，存在则更新，不存在则插入（批量处理）
//            List<String> payNoList = walletPayInfoList.stream()
//                    .map(WalletPayInfoDO::getPayNo)
//                    .filter(StringUtils::isNotBlank)
//                    .distinct()
//                    .collect(Collectors.toList());
//
//            Set<String> existPayNoSet = new HashSet<>();
//            if (CollectionUtils.isNotEmpty(payNoList)) {
//                List<WalletPayInfoDO> existList = walletPayInfoDAO.getByPayNoList(payNoList);
//                if (CollectionUtils.isNotEmpty(existList)) {
//                    existPayNoSet = existList.stream().map(WalletPayInfoDO::getPayNo).collect(Collectors.toSet());
//                }
//            }
//
//            List<WalletPayInfoDO> walletPayInfoInsertList = new ArrayList<>();
//            List<WalletPayInfoDO> walletPayInfoUpdateList = new ArrayList<>();
//            for (WalletPayInfoDO v : walletPayInfoList) {
//                if (v == null || StringUtils.isBlank(v.getPayNo())) {
//                    continue;
//                }
//                if (existPayNoSet.contains(v.getPayNo())) {
//                    walletPayInfoUpdateList.add(v);
//                } else {
//                    walletPayInfoInsertList.add(v);
//                }
//            }
//
//            if (CollectionUtils.isNotEmpty(walletPayInfoInsertList)) {
//                walletPayInfoDAO.insertBatch(walletPayInfoInsertList);
//            }
//            if (CollectionUtils.isNotEmpty(walletPayInfoUpdateList)) {
//                walletPayInfoDAO.updateBatchByPayNo(walletPayInfoUpdateList);
//            }
//
//            // WalletTrade：同样按 payNo 分批新增/更新
//            List<WalletTradeDO> walletTradeInsertList = new ArrayList<>();
//            List<WalletTradeDO> walletTradeUpdateList = new ArrayList<>();
//            for (WalletTradeDO v : walletTradeList) {
//                if (v == null || StringUtils.isBlank(v.getPayNo())) {
//                    continue;
//                }
//                if (existPayNoSet.contains(v.getPayNo())) {
//                    walletTradeUpdateList.add(v);
//                } else {
//                    walletTradeInsertList.add(v);
//                }
//            }
//
//            if (CollectionUtils.isNotEmpty(walletTradeInsertList)) {
//                walletTradeDAO.insertBatch(walletTradeInsertList);
//            }
//            if (CollectionUtils.isNotEmpty(walletTradeUpdateList)) {
//                walletTradeDAO.updateBatchByPayNo(walletTradeUpdateList);
//            }
//
//            // 更新预分账明细
//            if (CollectionUtils.isNotEmpty(updatedRecords)) {
//                preAllocationRecordDAO.updateBatch(updatedRecords);
//            }
//
//            StoreOrderDO updateOrder = StoreOrderDO.builder()
//                    .id(order.getId())
//                    .status(orderStatus)
//                    .updateTime(new Date())
//                    .build();
//
//            if (batchTransferResult.getTradeStatus()==1) {
//                //支付成功 改订单下所有分账详情变为已分账
//                preAllocationRecordDAO.updateBatch(allocationRecords);
//                //todo 推送数据到新管家？
//
//                shopStageInfoDAO.batchUpdateShopStageStatus(order.getShopId(),Arrays.asList(ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_80,ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_285));
//
//                //支付成功 修改金额，支付中 回调的时候习惯
//                updateOrder.setPaidAmount(order.getTotalAmount());
//                updateOrder.setUnpaidAmount(BigDecimal.ZERO);
//                updateOrder.setPayTime(new Date());
//            }
//
//            storeOrderDAO.updateSelective(updateOrder);
//        }finally {
//            redisUtil.unlock(lockKey);
//        }

        return true;
    }

    @Override
    public PageInfo<PCStoreOrderListVO> list(PCStoreOrderQueryRequest request) {
        if (request == null) {
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<PCStoreOrderListVO> list = storeOrderDAO.queryPCPage(request);
        return new PageInfo<>(list);
    }

    @Override
    public List<WalletPayVO> payList(Long shopId) {
        List<WalletPayInfoDO> list = walletPayInfoDAO.getByShopId(shopId, STANDARD_STORE.getModule(),null);
        List<WalletPayVO> walletPayVOS = BeanUtil.copyToList(list, WalletPayVO.class);
        return walletPayVOS;
    }

    @Override
    public Boolean managerOrder(PCStoreOrderOptionQuantityUpdateRequest request, LoginUserInfo userInfo) {
        log.info("managerOrder request:{},操作人:{}",JSONObject.toJSONString(request),userInfo.getName());
        if (request == null || request.getOrderId() == null ) {
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }

        // 1. 查询原订单
        StoreOrderDO order = storeOrderDAO.getById(request.getOrderId());
        if (order == null || !order.getShopId().equals(order.getShopId())) {
            throw new ServiceException(ErrorCodeEnum.STORE_ORDER_NOT_FOUND);
        }

        // 2. 待立规审核 可管理订单
        Integer status = order.getStatus();
//        if (!StoreOrderStatusEnum.WAIT_CONFIRM.getCode().equals(status)) {
//            throw new ServiceException(ErrorCodeEnum.STORE_ORDER_UPDATE_FORBIDDEN);
//        }

        // 3. 查询新店型信息
        StoreTypeDO storeType = storeTypeDAO.getById(order.getStoreTypeId());
        if (storeType == null || Boolean.TRUE.equals(storeType.getDeleted()) ||
                !Boolean.TRUE.equals(storeType.getActive())) {
            throw new ServiceException(ErrorCodeEnum.CONFIG_NOT_EXIST);
        }

        // 4. 获取新店型的选项绑定关系
        List<StoreTypeOptionDO> bindings = storeTypeOptionDAO.listByStoreTypeId(order.getStoreTypeId());
        Map<Long, StoreTypeOptionDO> bindingMap = bindings.stream()
                .collect(Collectors.toMap(StoreTypeOptionDO::getOptionId, Function.identity(), (a, b) -> a));

        // 5. 处理选中的配置选项
        BigDecimal optionAmount = BigDecimal.ZERO;
        BigDecimal originalOptionAmount = BigDecimal.ZERO;
        List<StoreOrderOptionSnapshotDO> snapshotList = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(request.getSelectedOptions())) {
            Set<Long> optionIds = request.getSelectedOptions().stream()
                    .filter(Objects::nonNull)
                    .map(PCStoreOrderOptionQuantityUpdateRequest.SelectedOption::getOptionId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            // 查询选项模板
            Map<Long, ConfigOptionDO> optionTemplateMap = new HashMap<>();
            if (!optionIds.isEmpty()) {
                List<ConfigOptionDO> optionTemplates = configOptionDAO.listActiveByIds(new ArrayList<>(optionIds));
                optionTemplateMap = optionTemplates.stream()
                        .collect(Collectors.toMap(ConfigOptionDO::getId, Function.identity(), (a, b) -> a));
            }

            // 校验并计算金额
            Set<String> selectedItemCodes = new HashSet<>();
            for (PCStoreOrderOptionQuantityUpdateRequest.SelectedOption selected : request.getSelectedOptions()) {
                if (selected == null || selected.getOptionId() == null) {
                    continue;
                }

                StoreTypeOptionDO binding = bindingMap.get(selected.getOptionId());
                if (binding == null) {
                    throw new ServiceException(ErrorCodeEnum.THE_OPTION_IS_NOT_PART_OF_THIS_STORE_TYPE);
                }

                ConfigOptionDO template = optionTemplateMap.get(selected.getOptionId());
                if (template == null || !Boolean.TRUE.equals(template.getActive())) {
                    throw new ServiceException(ErrorCodeEnum.CONFIG_NOT_EXIST);
                }

                // 处理数量
                BigDecimal quantity = selected.getQuantity();

                // 校验不可修改数量的选项
                BigDecimal defaultQty = binding.getDefaultQuantity();


                //使用店型上配置的价格 不能使用选项的配置上的价格
                BigDecimal price = binding.getOptionPrice() == null ? BigDecimal.ZERO : binding.getOptionPrice();
                BigDecimal originalPrice = template.getOriginalOptionPrice() == null ? BigDecimal.ZERO : template.getOriginalOptionPrice();

                BigDecimal amount = BigDecimal.ZERO;
                //小于默认数的时候
                if(quantity.compareTo(defaultQty)<=0){
                    amount = price.multiply(quantity);
                }else {
                    // 店型优惠价*默认数量 + 原价 *（选择数量-默认数量）
                    amount = price.multiply(defaultQty).add(originalPrice.multiply(quantity.subtract(defaultQty)));
                }
                BigDecimal originalAmount = originalPrice.multiply(quantity);
                optionAmount = optionAmount.add(amount);
                originalOptionAmount = originalOptionAmount.add(originalAmount);

                // 创建快照
                StoreOrderOptionSnapshotDO snapshot = StoreOrderOptionSnapshotDO.builder()
                        .orderId(order.getId())
                        .shopId(order.getShopId())
                        .storeTypeId(storeType.getId())
                        .optionId(selected.getOptionId())
                        .categoryCode(template.getCategoryCode())
                        .itemCode(template.getItemCode())
                        .optionCode(template.getOptionCode())
                        .optionName(template.getOptionName())
                        .optionPrice(price)
                        .originalOptionPrice(originalPrice)
                        .optionUnit(template.getOptionUnit())
                        .optionRemark(template.getOptionRemark())
                        .imageUrl(template.getImageUrl())
                        .videoUrl(template.getVideoUrl())
                        .quantity(quantity)
                        .expenseTypeCode(template.getExpenseTypeCode())
                        .amount(amount)
                        .originalAmount(originalAmount)
                        .build();
                snapshotList.add(snapshot);
            }
        }

        // 6. 计算固定费用和总金额
        BigDecimal storeFixedAmount = safe(storeType.getFranchiseFee())
                .add(safe(storeType.getBrandUsageFee()))
                .add(safe(storeType.getManagementFee()))
                .add(safe(storeType.getSystemUsageFee()))
                .add(safe(storeType.getDesignFee()))
                .add(safe(storeType.getFirstOrderFee()))
                .add(safe(storeType.getContractDeposit()))
                .add(safe(storeType.getDeviceDeposit()));


        BigDecimal originalStoreFixedAmount = safe(storeType.getOriginalFranchiseFee())
                .add(safe(storeType.getOriginalBrandUsageFee()))
                .add(safe(storeType.getOriginalManagementFee()))
                .add(safe(storeType.getOriginalSystemUsageFee()))
                .add(safe(storeType.getOriginalDesignFee()))
                .add(safe(storeType.getOriginalContractDeposit()))
                .add(safe(storeType.getOriginalDeviceDeposit()));

        BigDecimal totalAmount = storeFixedAmount.add(optionAmount);

        BigDecimal originalTotalAmount   = originalStoreFixedAmount.add(originalOptionAmount);

        // 7. 更新订单信息
        StoreOrderDO updateOrder = StoreOrderDO.builder()
                .id(order.getId())
                .storeTypeId(storeType.getId())
                .storeTypeCode(storeType.getStoreTypeCode())
                .storeTypeName(storeType.getStoreTypeName())
                .storeType(storeType.getStoreType())
                .brand(storeType.getBrand())
                .franchiseFee(safe(storeType.getFranchiseFee()))
                .originalFranchiseFee(safe(storeType.getOriginalFranchiseFee()))
                .brandUsageFee(safe(storeType.getBrandUsageFee()))
                .originalBrandUsageFee(safe(storeType.getOriginalBrandUsageFee()))
                .managementFee(safe(storeType.getManagementFee()))
                .originalManagementFee(safe(storeType.getOriginalManagementFee()))
                .systemUsageFee(safe(storeType.getSystemUsageFee()))
                .originalSystemUsageFee(safe(storeType.getOriginalSystemUsageFee()))
                .contractDeposit(safe(storeType.getContractDeposit()))
                .originalContractDeposit(safe(storeType.getOriginalContractDeposit()))
                .deviceDeposit(safe(storeType.getDeviceDeposit()))
                .originalDeviceDeposit(safe(storeType.getOriginalDeviceDeposit()))
                .designFee(safe(storeType.getDesignFee()))
                .originalDesignFee(safe(storeType.getOriginalDesignFee()))
                .firstOrderFee(safe(storeType.getFirstOrderFee()))
                .storeFixedAmount(storeFixedAmount)
                .originalStoreFixedAmount(originalStoreFixedAmount)
                .optionAmount(optionAmount)
                .originalOptionAmount(originalOptionAmount)
                .totalAmount(totalAmount)
                .originalTotalAmount(originalTotalAmount)
                .unpaidAmount(totalAmount.subtract(order.getPaidAmount()))
                .status(order.getStatus())
                .updateTime(new Date())
                .build();

        // 8. 删除旧快照并保存新快照
        snapshotDAO.deleteByOrderId(order.getId());
        if (!snapshotList.isEmpty()) {
            snapshotDAO.insertBatch(snapshotList);
        }

        // 9. 更新订单
        storeOrderDAO.updateSelective(updateOrder);
        return Boolean.TRUE;
    }

    @Override
    @Transactional
    public Boolean batchUpdateOptionQuantity(PCStoreOrderOptionQuantityUpdateRequest request,LoginUserInfo userInfo) {
        log.info("batchUpdateOptionQuantity request:{},操作人:{}",JSONObject.toJSONString(request),userInfo.getName());
        if (request == null || request.getOrderId() == null || CollectionUtils.isEmpty(request.getSelectedOptions())) {
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }

        StoreOrderDO order = storeOrderDAO.getById(request.getOrderId());
        if (order == null) {
            throw new ServiceException(ErrorCodeEnum.STORE_ORDER_NOT_FOUND);
        }

        List<StoreTypeOptionDO> bindings = storeTypeOptionDAO.listByStoreTypeId(order.getStoreTypeId());
        Map<Long, StoreTypeOptionDO> bindingMap = bindings.stream()
                .collect(Collectors.toMap(StoreTypeOptionDO::getOptionId, Function.identity(), (a, b) -> a));


        List<StoreOrderOptionSnapshotDO> snapshots = snapshotDAO.listByOrderId(order.getId());
        if (CollectionUtils.isEmpty(snapshots)) {
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }

        Map<Long, StoreOrderOptionSnapshotDO> snapshotMap = snapshots.stream()
                .collect(Collectors.toMap(StoreOrderOptionSnapshotDO::getOptionId, Function.identity(), (a, b) -> a));

        if (request.getSelectedOptions().size() != snapshots.size()) {
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }

        BigDecimal newOptionAmount = BigDecimal.ZERO;
        BigDecimal newOriginalOptionAmount = BigDecimal.ZERO;

        List<StoreOrderOptionSnapshotDO> batchUpdateList = new ArrayList<>();
        for (PCStoreOrderOptionQuantityUpdateRequest.SelectedOption selected : request.getSelectedOptions()) {
            if (selected == null || selected.getOptionId() == null || selected.getQuantity() == null
                    || selected.getQuantity().compareTo(BigDecimal.ZERO) < 0) {
                throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
            }

            StoreOrderOptionSnapshotDO snapshot = snapshotMap.get(selected.getOptionId());
            if (snapshot == null) {
                throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
            }
            
            StoreTypeOptionDO binding = bindingMap.get(selected.getOptionId());
            if (binding == null) {
                throw new ServiceException(ErrorCodeEnum.THE_OPTION_IS_NOT_PART_OF_THIS_STORE_TYPE);
            }

            BigDecimal optionPrice = snapshot.getOptionPrice() == null ? BigDecimal.ZERO : snapshot.getOptionPrice();
            BigDecimal originalOptionPrice = snapshot.getOriginalOptionPrice() == null ? BigDecimal.ZERO : snapshot.getOriginalOptionPrice();

            BigDecimal quantity = selected.getQuantity();
            BigDecimal defaultQty = binding.getDefaultQuantity();

            BigDecimal amount = BigDecimal.ZERO;
            //小于默认数的时候
            if(quantity.compareTo(defaultQty)<=0){
                amount = optionPrice.multiply(quantity);
            }else {
                // 店型优惠价*默认数量 + 原价 *（选择数量-默认数量）
                amount = optionPrice.multiply(defaultQty).add(originalOptionPrice.multiply(quantity.subtract(defaultQty)));
            }
            BigDecimal originalAmount = originalOptionPrice.multiply(selected.getQuantity());

            snapshot.setQuantity(selected.getQuantity());
            snapshot.setAmount(amount);
            snapshot.setOriginalAmount(originalAmount);
            batchUpdateList.add(snapshot);

            newOptionAmount = newOptionAmount.add(amount);
            newOriginalOptionAmount = newOriginalOptionAmount.add(originalAmount);
        }
        //批量更新
        snapshotDAO.batchUpdateQuantityAndAmount(batchUpdateList);

        BigDecimal newTotalAmount = safe(order.getStoreFixedAmount()).add(newOptionAmount);
        BigDecimal newOriginalTotalAmount = safe(order.getOriginalStoreFixedAmount()).add(newOriginalOptionAmount);

        StoreOrderDO updateOrder = StoreOrderDO.builder()
                .id(order.getId())
                .optionAmount(newOptionAmount)
                .originalOptionAmount(newOriginalOptionAmount)
                .totalAmount(newTotalAmount)
                .originalTotalAmount(newOriginalTotalAmount)
                .unpaidAmount(newTotalAmount.subtract(safe(order.getPaidAmount())))
                .updateTime(new Date())
                .build();

        storeOrderDAO.updateSelective(updateOrder);
        return Boolean.TRUE;
    }

    @Override
    @Transactional
    public Boolean saveOrUpdateWishlist(MiniStoreWishlistSaveRequest request, PartnerUserInfoVO userInfoVO) {
        log.info("saveOrUpdateWishlist:{}",JSONObject.toJSONString(request));
        if (request == null || request.getStoreTypeId() == null || userInfoVO == null || userInfoVO.getLineId() == null) {
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }
        if (CollectionUtils.isEmpty(request.getSelectedOptions())) {
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }

        StoreTypeDO storeType = storeTypeDAO.getById(request.getStoreTypeId());
        if (storeType == null || Boolean.TRUE.equals(storeType.getDeleted()) || Boolean.FALSE.equals(storeType.getActive())) {
            throw new ServiceException(ErrorCodeEnum.CONFIG_NOT_EXIST);
        }

        List<StoreTypeOptionDO> bindings = storeTypeOptionDAO.listByStoreTypeId(request.getStoreTypeId());
        Map<Long, StoreTypeOptionDO> bindingMap = bindings.stream()
                .collect(Collectors.toMap(StoreTypeOptionDO::getOptionId, Function.identity(), (a, b) -> a));

        Set<Long> optionIds = request.getSelectedOptions().stream()
                .filter(Objects::nonNull)
                .map(MiniStoreWishlistSaveRequest.SelectedOption::getOptionId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        Map<Long, ConfigOptionDO> optionMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(optionIds)) {
            List<ConfigOptionDO> options = configOptionDAO.listActiveByIds(new ArrayList<>(optionIds));
            optionMap = options.stream().collect(Collectors.toMap(ConfigOptionDO::getId, Function.identity(), (a, b) -> a));
        }

        if (request.getWishlistId() != null) {
            MiniStoreWishlistDelRequest miniStoreWishlistDelRequest = new MiniStoreWishlistDelRequest();
            miniStoreWishlistDelRequest.setWishlistId(request.getWishlistId());
            //删除逻辑
            deleted(miniStoreWishlistDelRequest,null);
        }

        String versionNo = generateOrderNo();
        BigDecimal totalAmount = BigDecimal.ZERO;

        BigDecimal storeFixedAmount = safe(storeType.getFranchiseFee())
                .add(safe(storeType.getBrandUsageFee()))
                .add(safe(storeType.getManagementFee()))
                .add(safe(storeType.getSystemUsageFee()))
                .add(safe(storeType.getDesignFee()))
                .add(safe(storeType.getFirstOrderFee()))
                .add(safe(storeType.getContractDeposit()))
                .add(safe(storeType.getDeviceDeposit()));

        for (MiniStoreWishlistSaveRequest.SelectedOption selected : request.getSelectedOptions()) {
            if (selected == null || selected.getOptionId() == null || selected.getQuantity() == null
                    || selected.getQuantity().compareTo(BigDecimal.ZERO) < 0) {
                throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
            }
            StoreTypeOptionDO binding = bindingMap.get(selected.getOptionId());
            if (binding == null) {
                throw new ServiceException(ErrorCodeEnum.THE_OPTION_IS_NOT_PART_OF_THIS_STORE_TYPE);
            }
            ConfigOptionDO cfg = optionMap.get(selected.getOptionId());
            if (cfg == null || !Boolean.TRUE.equals(cfg.getActive())) {
                throw new ServiceException(ErrorCodeEnum.CONFIG_NOT_EXIST);
            }

            BigDecimal price = binding.getOptionPrice() == null ? BigDecimal.ZERO : binding.getOptionPrice();
            BigDecimal quantity = selected.getQuantity();
            BigDecimal defaultQty = binding.getDefaultQuantity();
            BigDecimal amount = BigDecimal.ZERO;
            BigDecimal originalPrice = cfg.getOriginalOptionPrice();
            if (quantity.compareTo(defaultQty) <= 0) {
                amount = price.multiply(quantity);
            } else {
                amount = price.multiply(defaultQty).add(originalPrice.multiply(quantity.subtract(defaultQty)));
            }
            totalAmount = totalAmount.add(amount);
        }

        totalAmount = storeFixedAmount.add(totalAmount);

        StoreWishlistDO wishlist = StoreWishlistDO.builder()
                .lineId(userInfoVO.getLineId())
                .storeTypeId(request.getStoreTypeId())
                .totalAmount(totalAmount)
                .versionNo(versionNo)
                .wishlistStatus(getWishlistStatus(userInfoVO.getLineId()))
                .deleted(0)
                .build();
        storeWishlistDAO.insert(wishlist);

        List<StoreWishlistOptionDO> optionSaveList = new ArrayList<>();
        for (MiniStoreWishlistSaveRequest.SelectedOption selected : request.getSelectedOptions()) {
            optionSaveList.add(StoreWishlistOptionDO.builder()
                    .wishlistId(wishlist.getId())
                    .optionId(selected.getOptionId())
                    .quantity(selected.getQuantity())
                    .deleted(0)
                    .build());
        }
        storeWishlistOptionDAO.insertBatch(optionSaveList);
        return Boolean.TRUE;
    }


    /**
     * 获取线索阶段
     * @param lineId
     * @return
     */
    private Integer getWishlistStatus(Long lineId){
        LineInfoDO lineInfo = lineInfoDAO.getLineInfo(lineId);
        if (lineInfo.getWorkflowSubStageStatus()>=WorkflowSubStageStatusEnum.INTENT_5.getCode()){
            return WishlistStatusEnum.COMPLETE_POINT.getCode();
        }
        return WishlistStatusEnum.AGREE.getCode();
    }



    @Override
    public Boolean deleted(MiniStoreWishlistDelRequest request, PartnerUserInfoVO userInfoVO) {
        StoreWishlistDO storewishlist = storeWishlistDAO.getById(request.getWishlistId());
        if (storewishlist==null){
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }
        storewishlist.setDeleted(1);
        storeWishlistDAO.updateByExampleSelective(storewishlist);
        //更新配置项数据
        storeWishlistOptionDAO.softDeleteByWishlistIds(Arrays.asList(request.getWishlistId()));
        return Boolean.TRUE;
    }

    @Override
    public MiniStoreWishlistDetailVO wishlistDetail(Long wishlistId) {
        StoreWishlistDO storeWishlistDO = storeWishlistDAO.getById(wishlistId);
        if (storeWishlistDO==null){
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }
        return convert(storeWishlistDO);
    }

    @Override
    public List<MiniStoreWishlistListVO> wishlistList( Long lineId,Integer wishlistStatus) {
        if (lineId == null) {
            return Collections.emptyList();
        }
        List<MiniStoreWishlistListVO> wishlistList = storeWishlistDAO.listByLineId(lineId, null,wishlistStatus);
        if (CollectionUtils.isEmpty(wishlistList)) {
            return Collections.emptyList();
        }

        List<Long> wishlistIds = wishlistList.stream().map(MiniStoreWishlistListVO::getWishlistId).filter(Objects::nonNull).collect(Collectors.toList());
        List<StoreWishlistOptionDO> optionRows = storeWishlistOptionDAO.listByWishlistIds(wishlistIds);

        Map<Long, List<StoreWishlistOptionDO>> map = optionRows.stream().collect(Collectors.groupingBy(StoreWishlistOptionDO::getWishlistId));

        List<Long> optionIds = optionRows.stream().distinct().map(StoreWishlistOptionDO::getOptionId).collect(Collectors.toList());
        Map<Long, ConfigOptionDO> optionMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(optionIds)) {
            List<ConfigOptionDO> options = configOptionDAO.listActiveByIds(optionIds);
            optionMap = options.stream().collect(Collectors.toMap(ConfigOptionDO::getId, Function.identity(), (a, b) -> a));
        }
        List<Long> pointList = wishlistList.stream().filter(x -> x.getPointId() != null).map(MiniStoreWishlistListVO::getPointId).collect(Collectors.toList());
        List<PointInfoDO> pointDOList = pointInfoDAO.getPointListByIds(pointList);
        Map<Long, Long> pointMap = pointDOList.stream().filter(x -> x.getShopId() != null).collect(Collectors.toMap(PointInfoDO::getId, PointInfoDO::getShopId));

        for (MiniStoreWishlistListVO item : wishlistList) {
            List<StoreWishlistOptionDO> storeWishlistOptionDOS = map.get(item.getWishlistId());
            List<MiniStoreWishlistListVO.OptionVO> optionList = new ArrayList<>();
            if (item.getPointId()!=null){
                item.setShopId(pointMap.get(item.getPointId()));
            }
            for (StoreWishlistOptionDO row : storeWishlistOptionDOS) {
                MiniStoreWishlistListVO.OptionVO vo = new MiniStoreWishlistListVO.OptionVO();
                vo.setOptionId(row.getOptionId());
                vo.setQuantity(row.getQuantity());
                ConfigOptionDO cfg = optionMap.get(row.getOptionId());
                if (cfg != null) {
                    vo.setOptionName(cfg.getOptionName());
                    vo.setOptionPrice(cfg.getOptionPrice());
                    vo.setImageUrl(cfg.getImageUrl());
                }
                optionList.add(vo);
            }
            item.setOptions(optionList);
        }

        return wishlistList;
    }

    @Override
    public PageInfo<MiniStoreWishlistListVO> wishAllList(WishAllListRequest request) {
        PageHelper.startPage(request.getPageNum(),request.getPageSize());
        List<MiniStoreWishlistListVO> wishlist = storeWishlistDAO.listByVersionList(request.getKeyword(), request.getStoreTypeId(),request.getWishlistStatus());
        if (CollectionUtils.isEmpty(wishlist)){
            return new PageInfo<>();
        }
        PageInfo<MiniStoreWishlistListVO> result = new PageInfo<>(wishlist);
        List<Long> lineIdList = wishlist.stream().map(MiniStoreWishlistListVO::getLineId).collect(Collectors.toList());
        List<LineInfoDO> lineList = lineInfoDAO.getByLineIds(lineIdList);
        Map<Long, LineInfoDO> map = lineList.stream().collect(Collectors.toMap(LineInfoDO::getId, data -> data));

        List<Long> wishlistIds = wishlist.stream().map(MiniStoreWishlistListVO::getWishlistId).filter(Objects::nonNull).collect(Collectors.toList());
        List<StoreWishlistOptionDO> optionRows = storeWishlistOptionDAO.listByWishlistIds(wishlistIds);

        Map<Long, List<StoreWishlistOptionDO>> wishlistOptionMap = optionRows.stream().collect(Collectors.groupingBy(StoreWishlistOptionDO::getWishlistId));

        List<Long> optionIds = optionRows.stream().distinct().map(StoreWishlistOptionDO::getOptionId).collect(Collectors.toList());
        Map<Long, ConfigOptionDO> optionMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(optionIds)) {
            List<ConfigOptionDO> options = configOptionDAO.listActiveByIds(optionIds);
            optionMap = options.stream().collect(Collectors.toMap(ConfigOptionDO::getId, Function.identity(), (a, b) -> a));
        }

        for (MiniStoreWishlistListVO item : wishlist) {
            LineInfoDO lineInfoDO = map.get(item.getLineId());
            if (lineInfoDO != null) {
                item.setPartnerMobile(lineInfoDO.getMobile());
                item.setPartnerName(lineInfoDO.getUsername());
            }
            List<StoreWishlistOptionDO> storeWishlistOptionDOS = wishlistOptionMap.get(item.getWishlistId());

            List<MiniStoreWishlistListVO.OptionVO> optionList = new ArrayList<>();
            for (StoreWishlistOptionDO row : storeWishlistOptionDOS) {
                MiniStoreWishlistListVO.OptionVO vo = new MiniStoreWishlistListVO.OptionVO();
                vo.setOptionId(row.getOptionId());
                vo.setQuantity(row.getQuantity());
                ConfigOptionDO cfg = optionMap.get(row.getOptionId());
                if (cfg != null) {
                    vo.setOptionName(cfg.getOptionName());
                    vo.setOptionPrice(cfg.getOptionPrice());
                    vo.setImageUrl(cfg.getImageUrl());
                }
                optionList.add(vo);
            }
            item.setOptions(optionList);
        }
        return result;
    }

    @Override
    public Boolean wishlistBindPoint(WishlistBindPointRequest request) {
        StoreWishlistDO storeWishlist = storeWishlistDAO.getById(request.getWishlistId());
        if (!WishlistStatusEnum.COMPLETE_POINT.getCode().equals(storeWishlist.getWishlistStatus())){
            throw new ServiceException(ErrorCodeEnum.TASK_STATUS_NOT_ALLOW_OPERATE);
        }
        //校验铺位是否关联了其他心愿单 且心愿单不是拒绝状态
        Integer pointBindWishlistCount = storeWishlistDAO.getPointBindWishlistCount(request.getPointId(), WishlistStatusEnum.REJECT.getCode());
        if (pointBindWishlistCount>0){
            throw new ServiceException(ErrorCodeEnum.CURRENT_POINT_BIND_OTHER_WISHLIST);
        }
        storeWishlist.setPointId(request.getPointId());
        storeWishlist.setWishlistStatus(WishlistStatusEnum.LI_GUI_APPROVE.getCode());
        storeWishlistDAO.updateByExampleSelective(storeWishlist);
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean wishlistApprove(WishlistAuditRequest request, LoginUserInfo userInfo) {
        log.info("wishlistApprove:{},审批人：{}",JSONObject.toJSONString(request),userInfo.getName());
        //查看心愿单状态
        StoreWishlistDO wishlistDO = storeWishlistDAO.getById(request.getWishlistId());
        if (wishlistDO==null){
            throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE);
        }
        if (!WishlistStatusEnum.LI_GUI_APPROVE.getCode().equals(wishlistDO.getWishlistStatus())){
            throw new ServiceException(ErrorCodeEnum.TASK_STATUS_NOT_ALLOW_OPERATE);
        }
        Integer wishlistStatus = null;
        //通过
        if (request.getAuditStatus()==1){
            //查看线索阶段是否完成 如果没有完成 直接跳过意向金和意向协议阶段
            LineInfoDO lineInfo = lineInfoDAO.getLineInfo(wishlistDO.getLineId());
            if (Objects.isNull(lineInfo.getRegionId())||lineInfo.getRegionId() == 0){
                throw new ServiceException(ErrorCodeEnum.LINE_REGION_NOT_EXIST);
            }
            lineInfo.setWorkflowStage(WorkflowStageEnum.STORE.getCode());
            lineInfo.setWorkflowSubStageStatus(WorkflowSubStageStatusEnum.SIGN_INTENT_AGREEMENT_125.getCode());
            lineInfo.setDevelopmentManager(lineInfo.getInvestmentManager());
            lineInfoDAO.updateLineInfo(lineInfo);
            //初始化店铺 AI店
            lineInfo.setUseStandardStore(1);
            Long shopId = shopService.initAiShop(lineInfo);
            //选址阶段直接完成
            PointRecommendLineRequest recommendLineRequest = new PointRecommendLineRequest();
            recommendLineRequest.setShopIds(Arrays.asList(Long.valueOf(shopId)));
            recommendLineRequest.setPointId(wishlistDO.getPointId());
            recommendLineRequest.setDevelopmentManager(lineInfo.getDevelopmentManager());
            //推荐逻辑
            pointService.pointRecommendLine(recommendLineRequest);
            SelectPointRequest selectPointRequest = new SelectPointRequest();
            selectPointRequest.setPointId(wishlistDO.getPointId());
            selectPointRequest.setLineId(wishlistDO.getLineId());
            selectPointRequest.setShopId(shopId);
            //选址
            pointService.lineSelectPoint(selectPointRequest);
            //修改心愿单状态
            wishlistStatus = WishlistStatusEnum.PASS.getCode();
        }
        if (request.getAuditStatus()==0){
            wishlistStatus = WishlistStatusEnum.REJECT.getCode();
        }
        wishlistDO.setWishlistStatus(wishlistStatus);
        wishlistDO.setRemark(request.getRemark());
        wishlistDO.setUpdateTime(new Date());
        storeWishlistDAO.updateByExampleSelective(wishlistDO);
        return Boolean.TRUE;
    }

    @Override
    public MiniStoreWishlistDetailVO getCurrentShopBindWishlist(Long shopId) {
        ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(shopId);
        if (shopInfo == null) {
            throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE);
        }
        if (shopInfo.getPointId()==null){
            return null;
        }
        StoreWishlistDO storelistDO = storeWishlistDAO.getByPointId(shopInfo.getLineId(), shopInfo.getPointId());
        return convert(storelistDO);
    }

    @Override
    @Transactional
    public Boolean changeWishlist(ChangeWishlistRequest request) {
        if (request.getWishlistId()==null||request.getOrderId()==null||request.getShopId()==null){
            throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE);
        }
        //校验订单状态
        StoreOrderDO storeOrderDO = storeOrderDAO.getById(request.getOrderId());
        if (storeOrderDO==null){
            throw new ServiceException(ErrorCodeEnum.STORE_ORDER_NOT_FOUND);
        }
        if (!WAIT_CONFIRM.getCode().equals(storeOrderDO.getStatus())){
            throw new ServiceException(ErrorCodeEnum.CURRENT_ORDER_STATUS_NOT_SUPPORT_CHANGE);
        }
        MiniStoreWishlistDetailVO miniStoreWishlistDetailVO = wishlistDetail(request.getWishlistId());
        if (miniStoreWishlistDetailVO==null){
            throw new ServiceException(ErrorCodeEnum.CURRENT_WISHLIST_NOT_EXIST);
        }

        //校验心愿单状态
        StoreWishlistDO wishlistDO = storeWishlistDAO.getById(request.getWishlistId());
        //校验心愿单是否绑定其他铺位
        if (!WishlistStatusEnum.COMPLETE_POINT.getCode().equals(wishlistDO.getWishlistStatus())){
            throw new ServiceException(ErrorCodeEnum.CURRENT_WISHLIST_BIND_OTHER_POINT);
        }

        //查询老的心愿单
        ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(request.getShopId());
        if (shopInfo.getPointId()==null){
            throw new ServiceException(ErrorCodeEnum.ORDER_DATA_EXCEPTION);
        }
        //老的心愿单
        StoreWishlistDO oldWishlist = storeWishlistDAO.getByPointId(shopInfo.getLineId(), shopInfo.getPointId());
        //老的心愿单解绑关系
        storeWishlistDAO.unbindPoint(oldWishlist.getId());
        //新的心愿单关联关系
        wishlistDO.setPointId(shopInfo.getPointId());
        wishlistDO.setWishlistStatus(WishlistStatusEnum.PASS.getCode());
        storeWishlistDAO.updateByExampleSelective(wishlistDO);

        //删除老的订单
        storeOrderDAO.deleteById(storeOrderDO);
        //删除快照
        storeOrderOptionSnapshotDAO.deleteByOrderId(storeOrderDO.getId());
        MiniStoreOrderCreateRequest miniStoreOrderCreateRequest = new MiniStoreOrderCreateRequest();
        miniStoreOrderCreateRequest.setStoreTypeId(miniStoreWishlistDetailVO.getStoreTypeId());
        miniStoreOrderCreateRequest.setShopId(request.getShopId());
        List<MiniStoreOrderCreateRequest.SelectedOption> selectedOptions = new ArrayList<>();

        miniStoreWishlistDetailVO.getOptions().forEach(x->{
            MiniStoreOrderCreateRequest.SelectedOption selectedOption = new MiniStoreOrderCreateRequest.SelectedOption();
            selectedOption.setOptionId(x.getOptionId());
            selectedOption.setQuantity(x.getQuantity());
            selectedOptions.add(selectedOption);
        });
        miniStoreOrderCreateRequest.setSelectedOptions(selectedOptions);
        //创建订单
        createOrder(miniStoreOrderCreateRequest,null);
        return Boolean.TRUE;
    }




    private MiniStoreWishlistDetailVO convert(StoreWishlistDO storeWishlistDO){
        if (storeWishlistDO==null){
            return null;
        }
        MiniStoreWishlistDetailVO vo = new MiniStoreWishlistDetailVO();
        vo.setStoreTypeId(storeWishlistDO.getStoreTypeId());
        vo.setId(storeWishlistDO.getId());
        vo.setVersionNo(storeWishlistDO.getVersionNo());
        vo.setTotalAmount(storeWishlistDO.getTotalAmount());
        vo.setPointId(storeWishlistDO.getPointId());
        vo.setWishlistStatus(storeWishlistDO.getWishlistStatus());
        vo.setCreateTime(storeWishlistDO.getCreateTime());
        LineInfoDO lineInfo = lineInfoDAO.getLineInfo(storeWishlistDO.getLineId());
        if (lineInfo != null) {
            vo.setPartnerMobile(lineInfo.getMobile());
            vo.setPartnerName(lineInfo.getUsername());
        }
        StoreTypeDO storeTypeDO = storeTypeDAO.getById(storeWishlistDO.getStoreTypeId());
        MiniStoreWishlistDetailVO.FeeInfoVO feeInfo = new MiniStoreWishlistDetailVO.FeeInfoVO();
        feeInfo.setFranchiseFee(storeTypeDO.getFranchiseFee());
        feeInfo.setBrandUsageFee(storeTypeDO.getBrandUsageFee());
        feeInfo.setManagementFee(storeTypeDO.getManagementFee());
        feeInfo.setSystemUsageFee(storeTypeDO.getSystemUsageFee());
        feeInfo.setDesignFee(storeTypeDO.getDesignFee());
        feeInfo.setContractDeposit(storeTypeDO.getContractDeposit());
        feeInfo.setDeviceDeposit(storeTypeDO.getDeviceDeposit());
        feeInfo.setFirstOrderFee(storeTypeDO.getFirstOrderFee());
        vo.setFeeInfoVO(feeInfo);
        vo.setStoreTypeName(storeTypeDO.getStoreTypeName());
        vo.setStoreType(storeTypeDO.getStoreType());

        if (storeWishlistDO.getPointId()!=null){
            PointInfoDO pointInfoDO = pointInfoDAO.getPointInfoById(storeWishlistDO.getPointId());
            vo.setShopId(pointInfoDO.getShopId());
        }

        List<StoreWishlistOptionDO> optionRows = storeWishlistOptionDAO.listByWishlistIds(Arrays.asList(storeWishlistDO.getId()));
        if (CollectionUtils.isEmpty(optionRows)) {
            vo.setOptions(Collections.emptyList());
            return vo;
        }

        List<Long> optionIds = optionRows.stream().map(StoreWishlistOptionDO::getOptionId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<Long, ConfigOptionDO> optionMap = new HashMap<>();
        List<ConfigOptionDO> options = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(optionIds)) {
            options = configOptionDAO.listActiveByIds(optionIds);
            optionMap = options.stream().collect(Collectors.toMap(ConfigOptionDO::getId, Function.identity(), (a, b) -> a));
        }

        List<StoreTypeOptionDO> bindings = storeTypeOptionDAO.listByStoreTypeId(storeWishlistDO.getStoreTypeId());
        Map<Long, StoreTypeOptionDO> bindingMap = bindings.stream()
                .collect(Collectors.toMap(StoreTypeOptionDO::getOptionId, Function.identity(), (a, b) -> a));

        List<String> categoryCodeList = options.stream().map(ConfigOptionDO::getCategoryCode).collect(Collectors.toList());
        List<String> itemCodeList = options.stream().map(ConfigOptionDO::getItemCode).collect(Collectors.toList());

        Map<String, String> categoryCodeMap = configItemCategoryDAO.nameMap(categoryCodeList);
        Map<String, String> itemCodeMap = configItemDAO.nameMap(itemCodeList);

        List<MiniStoreWishlistDetailVO.OptionVO> list = new ArrayList<>();
        for (StoreWishlistOptionDO row : optionRows) {
            MiniStoreWishlistDetailVO.OptionVO item = new MiniStoreWishlistDetailVO.OptionVO();
            BigDecimal quantity = row.getQuantity();
            item.setOptionId(row.getOptionId());
            item.setQuantity(quantity);
            ConfigOptionDO cfg = optionMap.get(row.getOptionId());
            StoreTypeOptionDO storeTypeOptionDO = bindingMap.get(row.getOptionId());
            if (cfg != null) {
                item.setOptionName(cfg.getOptionName());
                item.setOriginalOptionPrice(cfg.getOriginalOptionPrice());
                item.setImageUrl(cfg.getImageUrl());
                item.setCategoryCode(cfg.getCategoryCode());
                item.setItemCode(cfg.getItemCode());
                item.setOptionUnit(cfg.getOptionUnit());
                item.setOptionRemark(cfg.getOptionRemark());
            }
            if (storeTypeOptionDO != null && cfg != null) {
                BigDecimal price = storeTypeOptionDO.getOptionPrice();
                BigDecimal amount = BigDecimal.ZERO;
                BigDecimal defaultQty = storeTypeOptionDO.getDefaultQuantity();
                BigDecimal originalPrice = cfg.getOriginalOptionPrice();
                if (quantity.compareTo(defaultQty) <= 0) {
                    amount = price.multiply(quantity);
                } else {
                    amount = price.multiply(defaultQty).add(originalPrice.multiply(quantity.subtract(defaultQty)));
                }
                item.setOptionPrice(price);
                item.setTotalPrice(amount);
                item.setCategoryName(categoryCodeMap.get(storeTypeOptionDO.getCategoryCode()));
                item.setItemName(itemCodeMap.get(storeTypeOptionDO.getItemCode()));
                item.setDefaultQuantity(storeTypeOptionDO.getDefaultQuantity());
            }
            list.add(item);
        }
        vo.setOptions(list);
        return vo;
    }


    private BigDecimal safe(BigDecimal v) {
        return v == null ? BigDecimal.ZERO : v;
    }

    private String generateOrderNo() {
        return new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + (new Random().nextInt(9000) + 1000);
    }

    private Map<String, String> buildDictNameMap(Long dictTableId) {
        if (dictTableId == null) {
            return Collections.emptyMap();
        }
        DictColumnQueryRequest dictReq = DictColumnQueryRequest.builder()
                .dictTableId(dictTableId)
                .openStatus(1)
                .build();
        dictReq.setPageNum(1);
        dictReq.setPageSize(10000);
        PageInfo<DictColumnVO> page = dictColumnService.getPage(dictReq);
        if (page == null || CollectionUtils.isEmpty(page.getList())) {
            return Collections.emptyMap();
        }
        return page.getList().stream()
                .filter(v -> StringUtils.isNotBlank(v.getColumnCode()))
                .collect(Collectors.toMap(DictColumnVO::getColumnCode, DictColumnVO::getColumnName, (a, b) -> a));
    }

    @Override
    public List<OrderDeviceDetailVO> queryOrderDeviceDetailByShopId(Long shopId) {
        StoreOrderDO order = storeOrderDAO.getLatestOrderByShopId(shopId);
        return queryOrderDeviceDetailByOrderId(order.getId());
    }


    @Override
    public List<OrderDeviceDetailVO> queryOrderDeviceDetailByOrderId(Long orderId) {
        if (orderId == null) {
            return Collections.emptyList();
        }

        // 查询订单快照列表
        List<StoreOrderOptionSnapshotDO> snapshotList = snapshotDAO.listByOrderId(orderId);
        if (CollectionUtils.isEmpty(snapshotList)) {
            return Collections.emptyList();
        }

        // 查询订单信息获取店型ID
        StoreOrderDO orderDO = storeOrderDAO.getById(orderId);
        if (orderDO == null) {
            return Collections.emptyList();
        }

        Boolean isOnline = active.equals(CommonConstants.HD_ENV) || active.equals(CommonConstants.ONLINE_ENV);
        Long tableId = isOnline ? 38L : 32L;

        // 获取费用类型字典映射（费用名称）
        Map<String, String> expenseTypeNameMap = buildDictNameMap(tableId);

        // 获取配置大类名称映射
        Set<String> categoryCodeSet = snapshotList.stream()
                .map(StoreOrderOptionSnapshotDO::getCategoryCode)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());
        Map<String, String> categoryNameMap = configItemCategoryDAO.nameMap(new ArrayList<>(categoryCodeSet));

        // 获取配置项名称映射
        Set<String> itemCodeSet = snapshotList.stream()
                .map(StoreOrderOptionSnapshotDO::getItemCode)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());
        Map<String, String> itemNameMap = configItemDAO.nameMap(new ArrayList<>(itemCodeSet));

        // 查询店型选项绑定（获取默认数量）
        Set<Long> optionIdSet = snapshotList.stream()
                .map(StoreOrderOptionSnapshotDO::getOptionId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        List<StoreTypeOptionDO> storeTypeOptionList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(optionIdSet)) {
            storeTypeOptionList = storeTypeOptionDAO.selectByIds(new ArrayList<>(optionIdSet), orderDO.getStoreTypeId());
        }
        Map<Long, BigDecimal> defaultQuantityMap = storeTypeOptionList.stream()
                .collect(Collectors.toMap(StoreTypeOptionDO::getOptionId, StoreTypeOptionDO::getDefaultQuantity, (a, b) -> a));

        // 按费用类型分组
        Map<String, List<StoreOrderOptionSnapshotDO>> expenseTypeGroupMap = snapshotList.stream()
                .filter(v -> StringUtils.isNotBlank(v.getExpenseTypeCode()))
                .collect(Collectors.groupingBy(StoreOrderOptionSnapshotDO::getExpenseTypeCode));

        List<OrderDeviceDetailVO> resultList = new ArrayList<>();

        for (Map.Entry<String, List<StoreOrderOptionSnapshotDO>> expenseEntry : expenseTypeGroupMap.entrySet()) {
            String expenseTypeCode = expenseEntry.getKey();
            OrderDeviceDetailVO expenseVO = new OrderDeviceDetailVO();
            expenseVO.setExpenseTypeCode(expenseTypeCode);
            expenseVO.setExpenseTypeName(expenseTypeNameMap.getOrDefault(expenseTypeCode, expenseTypeCode));

            // 转换为配置项明细
            List<OrderDeviceConfigItemVO> configItemList = expenseEntry.getValue().stream()
                    .map(snapshot -> {
                        OrderDeviceConfigItemVO configItem = new OrderDeviceConfigItemVO();
                        configItem.setExpenseTypeCode(snapshot.getExpenseTypeCode());
                        configItem.setCategoryCode(snapshot.getCategoryCode());
                        configItem.setCategoryName(categoryNameMap.getOrDefault(snapshot.getCategoryCode(), snapshot.getCategoryCode()));
                        configItem.setItemCode(snapshot.getItemCode());
                        configItem.setItemName(itemNameMap.getOrDefault(snapshot.getItemCode(), snapshot.getItemCode()));
                        configItem.setOptionName(snapshot.getOptionName());
                        configItem.setOriginalOptionPrice(snapshot.getOriginalOptionPrice());
                        configItem.setOptionPrice(snapshot.getOptionPrice());
                        configItem.setQuantity(snapshot.getQuantity());
                        configItem.setAmount(snapshot.getAmount());
                        configItem.setOptionUnit(snapshot.getOptionUnit());
                        // 从店型选项绑定获取默认数量
                        configItem.setDefaultQuantity(defaultQuantityMap.get(snapshot.getOptionId()));
                        return configItem;
                    })
                    .collect(Collectors.toList());

            expenseVO.setItems(configItemList);
            resultList.add(expenseVO);
        }

        return resultList;
    }
}
