package org.jeecg.modules.app.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.DictAnnotationUtil;
import org.jeecg.modules.app.dto.AppOrderInfoDTO;
import org.jeecg.modules.app.form.CreateOrderForm;
import org.jeecg.modules.app.form.InsureOrderInfoForm;
import org.jeecg.modules.app.form.UserPayForm;
import org.jeecg.modules.app.service.IOrderService;
import org.jeecg.modules.app.vo.AppGameScheduleVO;
import org.jeecg.modules.app.vo.OrderVO;
import org.jeecg.modules.app.vo.QueryOrderVerifyRecordsVO;
import org.jeecg.modules.system.app.entity.*;
import org.jeecg.modules.system.app.mapper.*;
import org.jeecg.modules.system.mapper.SysDepartMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

@Service
@Log4j2
public class OrderServiceImpl implements IOrderService {
    @Resource
    private AppSitePlaceMapper appSitePlaceMapper;
    @Resource
    private AppSitePriceRulesMapper appSitePriceRulesMapper;
    @Resource
    private AppCoursesMapper appCoursesMapper;
    @Resource
    private AppOrderMapper appOrderMapper;
    @Resource
    private SysDepartMapper sysDepartMapper;
    @Resource
    private AppOrderProductMapper appOrderProductMapper;
    @Resource
    private AppSiteMapper appSiteMapper;
    @Resource
    private AppIsinMapper appIsinMapper;
    @Resource
    private FamilyMembersMapper familyMembersMapper;
    @Resource
    private AppTeachingTimeMapper appTeachingTimeMapper;
    @Resource
    private InsureOrderInfoMapper insureOrderInfoMapper;
    @Resource
    private AppInsureMapper appInsureMapper;
    @Resource
    private AppOrderProInfoMapper appOrderProInfoMapper;
    @Resource
    private AppContractInfoMapper appContractInfoMapper;
    @Resource
    private AppGamePriceRulesMapper appGamePriceRulesMapper;
    @Resource
    private AppGameMapper appGameMapper;
    @Resource
    private AppGameScheduleMapper appGameScheduleMapper;
    @Resource
    private InsurePriceMapper insurePriceMapper;
    @Resource
    private AppCoursesPriceRulesMapper appCoursesPriceRulesMapper;
    @Resource
    private AppCoursesVerificationRecordMapper appCoursesVerificationRecordMapper;
    @Resource
    private AppContractSignMapper appContractSignMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderVO.createOrderPlaceSchool createOrderPlaceSchool(String rulesId, String userIds) {
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        List<String> list = Arrays.asList(rulesId.split(","));
        AppOrder order = createOrder(list, 0, user.getId(), userIds);
        if (null == order) throw new JeecgBootException("创建订单失败!");
        AppSitePriceRules appSitePriceRules = appSitePriceRulesMapper.selectById(list.get(0));
        AppSitePlace appSitePlace = appSitePlaceMapper.selectById(appSitePriceRules.getSitePlaceId());
        AppSite appSite = appSiteMapper.selectById(appSitePlace.getSiteId());
        OrderVO.createOrderPlaceSchool result = new OrderVO.createOrderPlaceSchool();
        List<OrderVO.couponNumberInformation> couponNumberInformation = new ArrayList<>();
        List<AppIsin> appIsins = appIsinMapper.selectList(Wrappers.<AppIsin>lambdaQuery().eq(AppIsin::getOrderId, order.getId()));
        appIsins.forEach(appIsin -> {
            OrderVO.couponNumberInformation information = new OrderVO.couponNumberInformation();
            information.setId(appIsin.getId())
                    .setCouponCode(appIsin.getTicketNo())
                    .setCouponStatus(appIsin.getIsinStatus())
                    .setExpireTime(appIsin.getExpireTime())
                    .setUserName(familyMembersMapper.selectById(appIsin.getFamilyId()).getFullName());
            couponNumberInformation.add(information);
        });
        result.setId(order.getId())
                .setOrderStatus(order.getOrderStatus())
                .setPlaceName(appSitePlace.getName())
                .setDate(appSitePriceRules.getDateOfSale())
                .setUserName(user.getRealname())
                .setAddress(appSite.getAddress())
                .setLongitude(appSite.getLongitude())
                .setLatitude(appSite.getLatitude())
                .setReminder(appSitePlace.getReminder())
                .setOrderCode(order.getOrderCode())
                .setMobile(user.getPhone())
                .setCreateTime(order.getCreateTime())
                .setPayTime(order.getPayTime())
                .setCouponNumberInformation(couponNumberInformation);
        return result;
    }

    @Override
    public boolean checkCourseLimitNum(String courseId, int limitNum) {
        return appCoursesMapper.selectById(courseId).getLimitNum() >= limitNum;
    }

    private List<OrderVO.TimeSlotData> parseTimeSlotData(String timeSlot) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode teachingDays = objectMapper.readTree(timeSlot);
            List<OrderVO.TimeSlotData> teachingList = new ArrayList<>();
            for (JsonNode node : teachingDays.get("data")) {
                OrderVO.TimeSlotData data = objectMapper.treeToValue(node, OrderVO.TimeSlotData.class);
                teachingList.add(data);
            }
            return teachingList;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public OrderVO.PreviewOrderPlaceSchool previewOrderPlaceSchool(String placeId, Date startTime) {
        LocalDate localDate = startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        Date dateOnly = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
        OrderVO.PreviewOrderPlaceSchool previewOrderPlaceSchool = new OrderVO.PreviewOrderPlaceSchool();
        AppSite appSite = appSiteMapper.selectOne(Wrappers.<AppSite>lambdaQuery().eq(AppSite::getId, appSitePlaceMapper.selectById(placeId).getSiteId()));
        List<OrderVO.PreviewOrderPlaceSchoolChild> timeSlot = appSitePriceRulesMapper.timeSlot(placeId, dateOnly);
        // 解析教学日和非教学日数据
        List<OrderVO.TimeSlotData> teachingList = parseTimeSlotData(appSite.getTeachingDay());
        List<OrderVO.TimeSlotData> nonTeachingList = parseTimeSlotData(appSite.getNoTeachingDay());

        timeSlot.forEach(a -> {
            LocalTime slotStart = LocalTime.parse(DateUtil.format(a.getStartTime(), "HH:mm"));
            LocalTime slotEnd = LocalTime.parse(DateUtil.format(a.getEndTime(), "HH:mm"));
            boolean isTeaching = a.getIsTeaching() == 0;

            List<OrderVO.TimeSlotData> targetList = isTeaching ? teachingList : nonTeachingList;

            Optional<OrderVO.TimeSlotData> matchedSlot = targetList.stream()
                    .filter(t -> {
                        LocalTime invStart = LocalTime.parse(t.getStartTime());
                        LocalTime invEnd = LocalTime.parse(t.getEndTime());
                        return !slotStart.isAfter(invEnd) && !slotEnd.isBefore(invStart);
                    })
                    .findFirst();

            matchedSlot.ifPresent(timeSlotData -> {
                int totalInventory = Integer.parseInt(timeSlotData.getTicketNum());
                int bookedCount = appOrderMapper.queryBookedCount(
                        placeId,
                        DateUtil.format(startTime, "yyyy-MM-dd"),
                        timeSlotData.getStartTime(),
                        timeSlotData.getEndTime()
                );
                int availableInventory = totalInventory - bookedCount;
                a.setInventory(availableInventory);
            });
        });
        AppSitePlace appSitePlace = appSitePlaceMapper.selectById(placeId);
        previewOrderPlaceSchool.setName(appSitePlace.getName())
                .setId(appSitePlace.getId())
                .setTimeSlot(timeSlot);
        if (StringUtils.isNotEmpty(appSitePlace.getInsureIds())) {
            List<String> aptitudesList = new ArrayList<>();
            if (appSitePlace.getInsureIds().indexOf(",") > 0) {
                aptitudesList = Arrays.asList(appSitePlace.getInsureIds().split(","));
            } else {
                aptitudesList.add(appSitePlace.getInsureIds());
            }
            LambdaQueryWrapper<AppInsure> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(AppInsure::getId, aptitudesList)
                    .eq(AppInsure::getStatus, 0)
                    .eq(AppInsure::getDelFlag, 0);  // 方法引用 + 集合
            List<AppInsure> appInsureList = appInsureMapper.selectList(wrapper);
            DictAnnotationUtil.translateDictList(appInsureList);
            for (AppInsure appInsure : appInsureList) {
                List<InsurePrice> insurePrices = insurePriceMapper.selectList(new QueryWrapper<InsurePrice>().lambda().eq(InsurePrice::getInsureId, appInsure.getId()).eq(InsurePrice::getDelFlag, 0));
                appInsure.setPriceDataList(insurePrices);
            }
            previewOrderPlaceSchool.setInsureIdList(appInsureList);
        }
        return previewOrderPlaceSchool;
    }

    @Override
    public OrderVO.PreviewOrderCourse previewOrderCourse(String courseId) {
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        OrderVO.PreviewOrderCourse previousOrderCourse = new OrderVO.PreviewOrderCourse();
        AppCourses appCourses = appCoursesMapper.selectById(courseId);
        if (appCourses == null || StringUtils.isEmpty(appCourses.getCover())) {
            throw new JeecgBootException("未查询到课程数据");
        }
        List<String> list = Arrays.asList(appCourses.getCover().split(","));
        boolean checkCourseDiscount = checkCourseDiscount(appCourses.getCategoryId(), user.getId());
        previousOrderCourse.setId(appCourses.getId())
                .setCover(list.get(0).split(",")[0])
                .setName(appCourses.getName())
                .setSellingPrice(appCourses.getSellingPrice())
                .setReminder(appCourses.getReminder())
                .setHasDiscount(checkCourseDiscount);
        if (checkCourseDiscount) {
            previousOrderCourse.setDiscountPrice(appCourses.getSellingPrice());
            previousOrderCourse.setTotalDiscount(appCourses.getSellingPrice());
            previousOrderCourse.setSubtotal(appCourses.getSellingPrice().subtract(appCourses.getSellingPrice()));
            previousOrderCourse.setTotalPrice(appCourses.getSellingPrice().subtract(appCourses.getSellingPrice()));
        } else {
            previousOrderCourse.setDiscountPrice(BigDecimal.ZERO);
            previousOrderCourse.setTotalDiscount(BigDecimal.ZERO);
            previousOrderCourse.setSubtotal(appCourses.getSellingPrice());
            previousOrderCourse.setTotalPrice(appCourses.getSellingPrice());
        }

        if (StringUtils.isNotEmpty(appCourses.getInsureIds())) {
            List<String> aptitudesList = new ArrayList<>();
            if (appCourses.getInsureIds().indexOf(",") > 0) {
                aptitudesList = Arrays.asList(appCourses.getInsureIds().split(","));
            } else {
                aptitudesList.add(appCourses.getInsureIds());
            }
            LambdaQueryWrapper<AppInsure> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(AppInsure::getId, aptitudesList)
                    .eq(AppInsure::getStatus, 0)
                    .eq(AppInsure::getDelFlag, 0);  // 方法引用 + 集合
            List<AppInsure> appInsureList = appInsureMapper.selectList(wrapper);
            DictAnnotationUtil.translateDictList(appInsureList);
            for (AppInsure appInsure : appInsureList) {
                List<InsurePrice> insurePrices = insurePriceMapper.selectList(new QueryWrapper<InsurePrice>().lambda().eq(InsurePrice::getInsureId, appInsure.getId()).eq(InsurePrice::getDelFlag, 0));
                appInsure.setPriceDataList(insurePrices);
            }
            previousOrderCourse.setInsureIdList(appInsureList);
        }
        return previousOrderCourse;
    }

    @Override
    public OrderVO.PreviewOrderPlaceGymnasiumChartered previewOrderPlaceGymnasiumChartered(String rulesId) {
        List<String> list = Arrays.asList(rulesId.split(","));
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        OrderVO.PreviewOrderPlaceGymnasiumChartered result = new OrderVO.PreviewOrderPlaceGymnasiumChartered();
        List<AppSitePriceRules> priceRules = new ArrayList<>();
        list.forEach(priceRule -> {
            AppSitePriceRules appSitePriceRule = appSitePriceRulesMapper.selectById(priceRule);
            priceRules.add(appSitePriceRule);
        });
        BigDecimal totalPrice = priceRules.stream()
                .map(AppSitePriceRules::getSellingPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // 格式化 totalPrice 和 subtotal 为两位小数
        totalPrice = totalPrice.setScale(2, BigDecimal.ROUND_HALF_UP);
        String formattedTotalPrice = totalPrice.toString(); // 直接使用 toString() 保留两位小数
        String formattedSubtotal = totalPrice.toString();   // 小计与总价相同
        result.setTotalPrice(new BigDecimal(formattedTotalPrice)); // 设置格式化后的 totalPrice
        result.setSubtotal(new BigDecimal(formattedSubtotal));
        if (priceRules.isEmpty()) {
            throw new IllegalArgumentException("未找到对应的价格规则");
        }
        AppSitePlace sitePlace = appSitePlaceMapper.selectById(priceRules.get(0).getSitePlaceId());
        if (sitePlace == null) {
            throw new IllegalStateException("关联场地不存在");
        }
        List<OrderVO.PreviewOrderTimePeriod> timePeriod = appSitePriceRulesMapper.previewOrderPlaceGymnasiumChartered(list);
        AppSite appSite = appSiteMapper.selectOne(Wrappers.<AppSite>lambdaQuery()
                .eq(AppSite::getOrgCode, sitePlace.getOrgCode()));
        return result.setTimePeriod(timePeriod)
                .setEarlyRefundTime(sitePlace.getEarlyRefundTime())
                .setPlaceId(sitePlace.getId())
                .setPlaceName(sitePlace.getName())
                .setReminder(sitePlace.getReminder())
                .setRefundRule(sitePlace.getEarlyRefundTime())
                .setMobile(user.getPhone())
                .setTotalPrice(totalPrice)  // 总价即为所有价格之和
                .setSubtotal(totalPrice)    // 小计与总价相同
                .setStoreName(appSite != null ? appSite.getName() : "未知门店");
    }

    @Override
    public List<OrderVO.PreviewOrderPlaceSchoolTime> previewOrderPlaceSchoolTime(String placeId) {
        List<OrderVO.PreviewOrderPlaceSchoolTime> previewOrderPlaceSchoolTimes = appTeachingTimeMapper.previewOrderPlaceSchoolTime(appSitePlaceMapper.selectById(placeId).getOrgCode());
        AppSite appSite = appSiteMapper.selectOne(Wrappers.<AppSite>lambdaQuery().eq(AppSite::getId, appSitePlaceMapper.selectById(placeId).getSiteId()));
        // 解析教学日和非教学日数据
        List<OrderVO.TimeSlotData> teachingList = parseTimeSlotData(appSite.getTeachingDay());
        List<OrderVO.TimeSlotData> nonTeachingList = parseTimeSlotData(appSite.getNoTeachingDay());
        previewOrderPlaceSchoolTimes.forEach(previewOrderPlaceSchoolTime -> {
            boolean isTeaching = previewOrderPlaceSchoolTime.getIsTeaching() == 0;
            List<OrderVO.TimeSlotData> targetList = isTeaching ? teachingList : nonTeachingList;
            if (!targetList.isEmpty()) {
                // 找到最早开始时间
                Optional<OrderVO.TimeSlotData> earliest = targetList.stream()
                        .min(Comparator.comparing(t -> LocalTime.parse(t.getStartTime(), DateTimeFormatter.ofPattern("HH:mm"))));

                // 找到最晚结束时间
                Optional<OrderVO.TimeSlotData> latest = targetList.stream()
                        .max(Comparator.comparing(t -> LocalTime.parse(t.getEndTime(), DateTimeFormatter.ofPattern("HH:mm"))));

                String earliestStart = earliest.map(OrderVO.TimeSlotData::getStartTime).orElse("未知");
                String latestEnd = latest.map(OrderVO.TimeSlotData::getEndTime).orElse("未知");

                int bookedCount = appOrderMapper.queryBookedCount(
                        placeId,
                        DateUtil.format(previewOrderPlaceSchoolTime.getDay(), "yyyy-MM-dd"),
                        earliestStart,
                        latestEnd
                );
                int totalTicketNum = targetList.stream()
                        .mapToInt(t -> {
                            try {
                                return Integer.parseInt(t.getTicketNum());
                            } catch (NumberFormatException e) {
                                return 0; // 默认值，或抛出异常
                            }
                        })
                        .sum();
                previewOrderPlaceSchoolTime.setInventory(totalTicketNum - bookedCount);
            }

        });

        return previewOrderPlaceSchoolTimes;
    }

    /**
     * 创建订单
     *
     * @param createOrderForm
     * @return 支付订单对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserPayForm createOrder(CreateOrderForm createOrderForm) {
        //获取登录用户
        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        String orderCode = generateOrderNumber(0);

        //创建订单
        AppOrder appOrder = new AppOrder();
        appOrder
                .setOrderType(createOrderForm.getOrderType())
                .setOrderCode(orderCode)
                .setUserId(user.getId())
                .setUserPhone(user.getPhone())
                .setOrderStatus(0)
                .setProductIds(createOrderForm.getProductIds())
                .setAmount(createOrderForm.getAmount())
        ;
        BigDecimal totalPrice = BigDecimal.ZERO;

        List<AppOrderProInfo> proInfoList = new ArrayList<>();

        List<InsureOrderInfo> insureOrderInfoList = new ArrayList<>();

        List<AppCoursesVerificationRecord> appCoursesVerificationRecordList = new ArrayList<>();

        //订单内容
        switch (createOrderForm.getType()) {
            //场地(学校，包场，无固定场)
            case 0:
                //学校
                if (createOrderForm.getOrderType() == 0) {
                    AppSitePriceRules priceRule = appSitePriceRulesMapper.selectById(createOrderForm.getProductIds());
                    AppSitePlace appSitePlace = appSitePlaceMapper.selectById(priceRule.getSitePlaceId());
                    AppSite appSite = appSiteMapper.selectById(appSitePlace.getSiteId());
                    appOrder
                            .setPayType(3)
                            .setOrderStatus(2)
                            .setOrgCode(appSite.getOrgCode())
                            .setTenantId(appSite.getTenantId())
                            .setType(CommonConstant.ORDER_TYPE_0)
                            //使用人IDs
                            .setFamilyIds(createOrderForm.getFamilyIds())
                            .setOriginalPrice(priceRule.getSellingPrice())
                            .setPrice(totalPrice)
                            .setCreateTime(new Date())
                            .setUpdateTime(new Date())
                            .setCreateBy(user.getId())
                            .setUpdateBy(user.getId())
                            .setStatus(CommonConstant.STATUS_NORMAL)
                            .setDelFlag(CommonConstant.DEL_FLAG_0);
                    //使用人
                    List<String> ids = Arrays.stream(createOrderForm.getFamilyIds().split(",")).collect(Collectors.toList());
                    for (String id : ids) {
                        FamilyMembers familyMembers = familyMembersMapper.selectById(id);

                        String date = DateUtil.format(priceRule.getDateOfSale(), "yyyy-MM-dd");
                        String startTime = DateUtil.format(priceRule.getEndTime(), "HH:mm:ss");
                        String endTime = DateUtil.format(priceRule.getEndTime(), "HH:mm:ss");
                        String expireTime = date + " " + endTime;

                        AppOrderProInfo appOrderProInfo = new AppOrderProInfo();
                        appOrderProInfo
                                .setProductId(priceRule.getId())
                                .setProductName("学校场地预约")
                                .setType(CommonConstant.ORDER_PRO_INFO_TYPE_1)
                                .setUseDateStr(date)
                                .setFrameTimeStr(startTime + "-" + endTime)
                                .setExpireTime(expireTime)
                                .setOriginalPrice(priceRule.getOriginalPrice())
                                .setPrice(priceRule.getSellingPrice())
                                .setOrderStatus(0)
                                .setQuantity(1)
                                .setFamilyUserId(id)
                                .setUserName(familyMembers.getFullName())
                                .setUserPhone(familyMembers.getPhone())
                                .setStatus(CommonConstant.STATUS_0_INT)
                                .setDelFlag(CommonConstant.DEL_FLAG_0);

                        proInfoList.add(appOrderProInfo);
                    }
                }

                //包场
                if (createOrderForm.getOrderType() == 1) {

                    List<String> list = Arrays.stream(createOrderForm.getProductIds().split(",")).collect(Collectors.toList());

                    //订单总价（商品的售价总和）
                    BigDecimal sumPrice = new BigDecimal(0);

                    for (String id : list) {
                        AppSitePriceRules priceRule = appSitePriceRulesMapper.selectById(list.get(0));
                        AppSitePlace appSitePlace = appSitePlaceMapper.selectById(priceRule.getSitePlaceId());
                        AppSite appSite = appSiteMapper.selectById(appSitePlace.getSiteId());

                        String date = DateUtil.format(priceRule.getDateOfSale(), "yyyy-MM-dd");
                        String startTime = DateUtil.format(priceRule.getStartTime(), "HH:mm:ss");
                        String endTime = DateUtil.format(priceRule.getEndTime(), "HH:mm:ss");
                        String expireTime = date + " " + endTime;

                        AppOrderProInfo appOrderProInfo = new AppOrderProInfo();
                        appOrderProInfo.setProductId(id);
                        appOrderProInfo.setProductName(date + " " + startTime + "-" + endTime + "|" + appSitePlace.getName());
                        appOrderProInfo.setExpireTime(expireTime);
                        appOrderProInfo.setAddress(appSite.getAddress());
                        appOrderProInfo.setType(CommonConstant.ORDER_PRO_INFO_TYPE_2);
                        appOrderProInfo.setOriginalPrice(priceRule.getOriginalPrice());
                        appOrderProInfo.setPrice(priceRule.getSellingPrice());
                        appOrderProInfo.setOrderStatus(0);
                        appOrderProInfo.setQuantity(1);
                        appOrderProInfo.setStatus(CommonConstant.STATUS_0_INT);
                        appOrderProInfo.setDelFlag(CommonConstant.DEL_FLAG_0);

                        proInfoList.add(appOrderProInfo);
                        appOrder.setOrgCode(appSitePlace.getOrgCode())
                                .setTenantId(appSitePlace.getTenantId());

                        sumPrice = sumPrice.add(priceRule.getSellingPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);
                    }

                    //计算订单总价
                    totalPrice = totalPrice.add(sumPrice).setScale(2, BigDecimal.ROUND_HALF_UP);

                    appOrder
                            .setType(CommonConstant.ORDER_TYPE_0)
                            .setOriginalPrice(sumPrice)
                            .setCreateTime(new Date())
                            .setUpdateTime(new Date())
                            .setCreateBy(user.getId())
                            .setUpdateBy(user.getId())
                            .setStatus(CommonConstant.STATUS_NORMAL)
                            .setDelFlag(CommonConstant.DEL_FLAG_0);
                }

                //无固定场
                if (createOrderForm.getOrderType() == 2) {
                    AppSitePriceRules priceRule = appSitePriceRulesMapper.selectById(createOrderForm.getProductIds());
                    AppSitePlace appSitePlace = appSitePlaceMapper.selectById(priceRule.getSitePlaceId());
                    AppSite appSite = appSiteMapper.selectById(appSitePlace.getSiteId());

                    //订单总价（商品的售价总和）
                    BigDecimal sumPrice = new BigDecimal(0);
                    //团购优惠
                    BigDecimal tDiscounts = new BigDecimal(0);

                    for (int i = 1; i <= createOrderForm.getAmount(); i++) {

                        String date = DateUtil.format(priceRule.getDateOfSale(), "yyyy-MM-dd");
                        String startTime = DateUtil.format(priceRule.getStartTime(), "HH:mm:ss");
                        String endTime = DateUtil.format(priceRule.getEndTime(), "HH:mm:ss");
                        String expireTime = date + " " + endTime;

                        AppOrderProInfo appOrderProInfo = new AppOrderProInfo();
                        appOrderProInfo.setProductId(createOrderForm.getProductIds());
                        appOrderProInfo.setProductName(appSitePlace.getName());
                        appOrderProInfo.setProductImage(appSitePlace.getCover());
                        appOrderProInfo.setAddress(appSite.getAddress());
                        appOrderProInfo.setType(CommonConstant.ORDER_PRO_INFO_TYPE_3);
                        appOrderProInfo.setFrameTimeStr(startTime + "-" + endTime);
                        appOrderProInfo.setExpireTime(expireTime);
                        appOrderProInfo.setOriginalPrice(priceRule.getOriginalPrice());
                        appOrderProInfo.setPrice(priceRule.getSellingPrice());
                        appOrderProInfo.setOrderStatus(0);
                        appOrderProInfo.setQuantity(1);
                        appOrderProInfo.setStatus(CommonConstant.STATUS_0_INT);
                        appOrderProInfo.setDelFlag(CommonConstant.DEL_FLAG_0);

                        proInfoList.add(appOrderProInfo);
                        tDiscounts = tDiscounts.add(priceRule.getOriginalPrice().subtract(priceRule.getSellingPrice())).setScale(2, BigDecimal.ROUND_HALF_UP);
                        sumPrice = sumPrice.add(priceRule.getSellingPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);
                    }

                    //计算订单总价
                    totalPrice = totalPrice.add(sumPrice).setScale(2, BigDecimal.ROUND_HALF_UP);

                    appOrder
                            .setOrgCode(appSite.getOrgCode())
                            .setTenantId(appSite.getTenantId())
                            .setType(CommonConstant.ORDER_TYPE_0)
                            .setTDiscounts(tDiscounts)
                            .setOriginalPrice(sumPrice)
                            .setCreateTime(new Date())
                            .setUpdateTime(new Date())
                            .setCreateBy(user.getId())
                            .setUpdateBy(user.getId())
                            .setStatus(CommonConstant.STATUS_NORMAL)
                            .setDelFlag(CommonConstant.DEL_FLAG_0);
                }
                break;
            //赛事
            case 1:
                //个人赛
                AppGamePriceRules appGamePriceRules = appGamePriceRulesMapper.selectById(createOrderForm.getProductIds());
                AppGame appGame = appGameMapper.selectById(appGamePriceRules.getGameId());
                AppGameSchedule appGameSchedule = appGameScheduleMapper.selectOne(Wrappers.<AppGameSchedule>lambdaQuery().eq(AppGameSchedule::getGameId, appGame.getId()).last("limit 1"));


                appOrder.setOrgCode(appGamePriceRules.getOrgCode());
                appOrder.setTenantId(appGamePriceRules.getTenantId());

                //订单总价（商品的售价总和）
                BigDecimal sumPrice = new BigDecimal(0);

                for (int i = 1; i <= createOrderForm.getAmount(); i++) {


                    String familyUserId = createOrderForm.getFamilyIds().split(",")[i - 1];
                    FamilyMembers familyMembers = familyMembersMapper.selectById(familyUserId);
                    AppOrderProInfo appOrderProInfo = new AppOrderProInfo();
                    appOrderProInfo.setProductId(createOrderForm.getProductIds());
                    appOrderProInfo.setProductName(appGame.getName());
                    appOrderProInfo.setAddress(appGame.getAddress());
                    if (createOrderForm.getOrderType() == 3) {
                        appOrderProInfo.setType(CommonConstant.ORDER_PRO_INFO_TYPE_4);
                    }
                    if (createOrderForm.getOrderType() == 4) {
                        appOrderProInfo.setType(CommonConstant.ORDER_PRO_INFO_TYPE_5);
                    }
                    appOrderProInfo.setFrameTimeStr(appGame.getStartTime() + "-" + appGame.getEndTime());
                    appOrderProInfo.setExpireTime(DateUtil.format(appGameSchedule.getEndTime(), "yyyy-MM-dd HH:mm:ss"));
                    appOrderProInfo.setOriginalPrice(appGamePriceRules.getSellingPrice());
                    appOrderProInfo.setPrice(appGamePriceRules.getSellingPrice());
                    appOrderProInfo.setOrderStatus(0);
                    appOrderProInfo.setQuantity(1);
                    appOrderProInfo.setFamilyUserId(familyUserId);
                    appOrderProInfo.setUserName(familyMembers.getFullName());
                    appOrderProInfo.setUserPhone(familyMembers.getPhone());
                    appOrderProInfo.setStatus(CommonConstant.STATUS_0_INT);
                    appOrderProInfo.setDelFlag(CommonConstant.DEL_FLAG_0);

                    proInfoList.add(appOrderProInfo);

                    sumPrice = sumPrice.add(appGamePriceRules.getSellingPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);
                }
                //计算订单总价
                totalPrice = totalPrice.add(sumPrice).setScale(2, BigDecimal.ROUND_HALF_UP);

                appOrder
                        .setType(CommonConstant.ORDER_TYPE_1)
                        .setOriginalPrice(sumPrice)
                        .setCreateTime(new Date())
                        .setUpdateTime(new Date())
                        .setCreateBy(user.getId())
                        .setUpdateBy(user.getId())
                        .setStatus(CommonConstant.STATUS_NORMAL)
                        .setDelFlag(CommonConstant.DEL_FLAG_0);
                if (StrUtil.isNotBlank(createOrderForm.getGameCertificationForm())) {
                    appOrder.setGameCertification(createOrderForm.getGameCertificationForm());
                }
                break;
            //课程
            case 2:
                //课程
                AppCourses appCourse = appCoursesMapper.selectById(appOrder.getProductIds());
                List<AppCoursesPriceRules> priceRulesList = appCoursesPriceRulesMapper.selectList(Wrappers.<AppCoursesPriceRules>lambdaQuery().eq(AppCoursesPriceRules::getCoursesId, appCourse.getId()));
                AppSite appSite = appSiteMapper.selectById(appCourse.getAddressSiteId());

                appOrder.setType(CommonConstant.ORDER_TYPE_2);
                appOrder.setOrgCode(appCourse.getOrgCode());
                appOrder.setTenantId(appCourse.getTenantId());

                //合同编号
                AppContractInfo appContractInfo = appContractInfoMapper.selectOne(Wrappers.<AppContractInfo>lambdaQuery()
                        .eq(AppContractInfo::getOrgCode, appOrder.getOrgCode()).eq(AppContractInfo::getDelFlag,0));
                if (ObjectUtil.isNotEmpty(appContractInfo)) {
                    appOrder.setContractNo(appContractInfo.getId());
                }

                //订单总价（商品的售价总和）
                BigDecimal sumCoursePrice = new BigDecimal(0);

                //优惠金额，如果当前课程商品类目是第一次购买，触发免费政策
                BigDecimal sDiscounts = new BigDecimal(0);
                BigDecimal tDiscounts = new BigDecimal(0);

                for (int i = 1; i <= createOrderForm.getAmount(); i++) {

                    String familyUserId = createOrderForm.getFamilyIds().split(",")[i - 1];
                    FamilyMembers familyMembers = familyMembersMapper.selectById(familyUserId);
                    AppOrderProInfo appOrderProInfo = new AppOrderProInfo();
                    appOrderProInfo.setProductId(createOrderForm.getProductIds());
                    appOrderProInfo.setProductName(appCourse.getName());
                    appOrderProInfo.setAddress(appSite.getAddress());
                    appOrderProInfo.setType(CommonConstant.ORDER_PRO_INFO_TYPE_6);
                    appOrderProInfo.setFrameTimeStr(DateUtil.format(appCourse.getStartTime(), "yyyy-MM-dd") + "-" + DateUtil.format(appCourse.getEndTime(), "yyyy-MM-dd"));
                    appOrderProInfo.setExpireTime(DateUtil.format(appCourse.getEndTime(), "yyyy-MM-dd"));
                    appOrderProInfo.setOriginalPrice(appCourse.getOriginalPrice());
                    appOrderProInfo.setPrice(appCourse.getSellingPrice());
                    appOrderProInfo.setOrderStatus(0);
                    appOrderProInfo.setQuantity(1);
                    appOrderProInfo.setFamilyUserId(familyUserId);
                    appOrderProInfo.setUserName(familyMembers.getFullName());
                    appOrderProInfo.setUserPhone(familyMembers.getPhone());
                    appOrderProInfo.setStatus(CommonConstant.STATUS_0_INT);
                    appOrderProInfo.setDelFlag(CommonConstant.DEL_FLAG_0);

                    //创建核销记录
                    if (CollUtil.isNotEmpty(priceRulesList)) {
                        for (AppCoursesPriceRules appCoursesPriceRules : priceRulesList) {
                            AppCoursesVerificationRecord appCoursesVerificationRecord = new AppCoursesVerificationRecord();
                            appCoursesVerificationRecord.setCoursesId(appCourse.getId());
                            appCoursesVerificationRecord.setCoursesPriceRuleId(appCoursesPriceRules.getId());
                            appCoursesVerificationRecord.setCoursesName(appCoursesPriceRules.getName());
                            appCoursesVerificationRecord.setCoursesStartTime(appCoursesPriceRules.getStartTime());
                            appCoursesVerificationRecord.setCoursesEndTime(appCoursesPriceRules.getEndTime());
                            appCoursesVerificationRecord.setUseUserId(familyUserId);
                            appCoursesVerificationRecord.setUseUserName(familyMembers.getFullName());
                            appCoursesVerificationRecord.setVerifyStatus(0);
                            appCoursesVerificationRecord.setOrPostpone(0);
                            appCoursesVerificationRecord.setCoursesType(0);
                            appCoursesVerificationRecordList.add(appCoursesVerificationRecord);
                        }
                    }

                    if (createOrderForm.getOrFreeOrder() == 1) {
                        Boolean flag = checkOrderOrFree(user.getId(), appCourse.getCategoryId());
                        if (!flag && i == 1) {
                            //订单中的多个商品中的第一个商品触发免费，将金额设置为优惠金额
                            sDiscounts = sDiscounts.add(appCourse.getSellingPrice());
                            appOrderProInfo.setOrFreePro(CommonConstant.STATUS_1_INT);
                            appOrder.setContractNo(null);
                            //试听优惠
                            appOrder.setSDiscounts(sDiscounts);
                        }
                    }

                    proInfoList.add(appOrderProInfo);

                    tDiscounts = tDiscounts.add(appCourse.getOriginalPrice().subtract(appCourse.getSellingPrice())).setScale(2, BigDecimal.ROUND_HALF_UP);
                    sumCoursePrice = sumCoursePrice.add(appCourse.getSellingPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);
                }

                //计算订单总价
                totalPrice = totalPrice.add(sumCoursePrice).setScale(2, BigDecimal.ROUND_HALF_UP);

                //团购优惠
                appOrder.setTDiscounts(tDiscounts);
                //原订单总价
                appOrder.setOriginalPrice(sumCoursePrice);
                //使用人IDs
                appOrder.setFamilyIds(createOrderForm.getFamilyIds());
                break;
        }

        //构建保单内容
        InsureOrderInfoForm insureOrderInfoForm = createOrderForm.getInsureOrderInfoForm();
        if (ObjectUtils.isNotEmpty(insureOrderInfoForm)) {
            List<String> ids = Arrays.stream(insureOrderInfoForm.getFamilyMembersIds().split(",")).collect(Collectors.toList());
            AppInsure appInsure = appInsureMapper.selectById(insureOrderInfoForm.getInsureId());
            DictAnnotationUtil.translateDict(appInsure);
            //保单总价
            BigDecimal sumPrice = new BigDecimal(0);
            for (String id : ids) {

                //查询保单价格
                InsurePrice insurePrice = insurePriceMapper.selectById(insureOrderInfoForm.getInsurePriceId());

                //创建保单
                InsureOrderInfo insureOrderInfo = new InsureOrderInfo();
                insureOrderInfo
                        .setOrderId(appOrder.getId())
                        .setBdOrderNo(generateOrderNumber(2))
                        .setInsureName(appInsure.getName())
                        .setInsureCompany(appInsure.getInsuranceName_dictText())
                        .setInsureId(appInsure.getId())
                        .setMoney(insurePrice.getInsurePrice())
                        .setFamilyMembersId(id)
                        .setAssertStartTime(insureOrderInfoForm.getAssertStartTime())
                        .setAssertEndTime(insureOrderInfoForm.getAssertEndTime())
                        .setIsEnterSystem(CommonConstant.STATUS_0_INT)
                ;
                insureOrderInfoList.add(insureOrderInfo);

                sumPrice = sumPrice.add(insurePrice.getInsurePrice()).setScale(2, BigDecimal.ROUND_HALF_UP);

                AppOrderProInfo appOrderProInfo = new AppOrderProInfo();
                appOrderProInfo.setProductId(insureOrderInfo.getId());
                appOrderProInfo.setProductName(insureOrderInfo.getInsureName());
                appOrderProInfo.setType(CommonConstant.ORDER_PRO_INFO_TYPE_7);

                appOrderProInfo.setPrice(insureOrderInfo.getMoney());
                appOrderProInfo.setQuantity(1);
                FamilyMembers familyMembers = familyMembersMapper.selectById(id);
                appOrderProInfo.setFamilyUserId(id);
                appOrderProInfo.setUserName(familyMembers.getFullName());
                appOrderProInfo.setUserPhone(familyMembers.getPhone());
                appOrderProInfo.setStatus(CommonConstant.STATUS_0_INT);
                appOrderProInfo.setDelFlag(CommonConstant.DEL_FLAG_0);
            }
            //计算总价 = 订单金额 + 保单金额
            totalPrice = totalPrice.add(sumPrice);
        }
        appOrder.setPrice(totalPrice);
        appOrderMapper.insert(appOrder);
        saveSignFlowRecord(appOrder);
        //todo 优化异步执行 -> 保存订单商品信息
        for (AppOrderProInfo appOrderProInfo : proInfoList) {
            appOrderProInfo
                    .setOrderId(appOrder.getId())
                    .setOrderCode(appOrder.getOrderCode())
                    //生成10位随机券号
                    .setTicketNo(RandomUtil.randomNumbers(10))
            ;
            appOrderProInfoMapper.insert(appOrderProInfo);
            //订单券号记录
            AppIsin appIsin = new AppIsin();
            appIsin
                    .setOrderId(appOrder.getId())
                    .setOrderCode(appOrder.getOrderCode())
                    .setOrderProInfoId(appOrderProInfo.getId())
                    .setFamilyId(appOrderProInfo.getFamilyUserId())
                    .setFamilyUserName(appOrderProInfo.getUserName())
                    .setUserPhone(appOrderProInfo.getUserPhone())
                    .setUseAddress(StrUtil.isBlank(appOrderProInfo.getAddress()) ? null : appOrderProInfo.getAddress())
                    //过期时间
                    .setExpireTime(appOrderProInfo.getExpireTime())
                    //生成10位随机券号
                    .setTicketNo(appOrderProInfo.getTicketNo())
                    .setIsinStatus(CommonConstant.ISIN_STATUS_1);
            appIsinMapper.insert(appIsin);
        }

        //保存保险
        for (InsureOrderInfo insureOrderInfo : insureOrderInfoList) {
            insureOrderInfo.setOrderId(appOrder.getId());
            insureOrderInfoMapper.insert(insureOrderInfo);
        }

        //保存核销记录
        for (AppCoursesVerificationRecord appCoursesVerificationRecord : appCoursesVerificationRecordList) {
            appCoursesVerificationRecord.setOrderId(appOrder.getId());
            appCoursesVerificationRecord.setOrderCode(appOrder.getOrderCode());
            appCoursesVerificationRecordMapper.insert(appCoursesVerificationRecord);
        }

        //构建支付表单返回给前端支撑支付调用
        UserPayForm payForm = new UserPayForm();
        payForm
                .setOrderId(appOrder.getId())
                .setOrderCode(orderCode)
        ;
        return payForm;
    }

    /**
     * 保存签署流程记录
     */
    private void saveSignFlowRecord(AppOrder appOrder) {
        if (appOrder.getFamilyIds() != null && !appOrder.getFamilyIds().isEmpty()){
            List.of(appOrder.getFamilyIds().split(",")).forEach(a->{
                String id = UUID.randomUUID().toString().replace("-", "");
                AppContractSign record = new AppContractSign()
                        .setId(id)
                        .setOrderId(appOrder.getId())
                        .setFamilyId(a)
                        .setOrgCode(appOrder.getOrgCode())
                        .setCreateTime(new Date())
                        .setUpdateTime(new Date());
                appContractSignMapper.insert(record);
            });
        }
    }

    @Override
    public OrderVO.PreviewOrderPlaceGymnasiumNoFixation previewOrderPlaceGymnasiumNoFixation(String placeId) {
        return appSitePlaceMapper.previewOrderPlaceGymnasiumNoFixation(placeId);
    }

    @Override
    public AppOrderInfoDTO queryOrderInfo(String orderId) {

        AppOrderInfoDTO appOrderInfoDTO = new AppOrderInfoDTO();

        AppOrder appOrder = appOrderMapper.selectById(orderId);
        appOrderInfoDTO.setId(appOrder.getId());
        appOrderInfoDTO.setOrderCode(appOrder.getOrderCode());
        appOrderInfoDTO.setOrderStatus(appOrder.getOrderStatus());
        appOrderInfoDTO.setType(appOrder.getType());
        appOrderInfoDTO.setCreateTime(appOrder.getCreateTime());
        appOrderInfoDTO.setPayTime(appOrder.getPayTime());
        appOrderInfoDTO.setPhoneNumber(appOrder.getUserPhone());
        appOrderInfoDTO.setTotalPrice(appOrder.getOriginalPrice());
        appOrderInfoDTO.setPrice(appOrder.getPrice());
        if (appOrder.getType().equals(CommonConstant.ORDER_TYPE_2)) {
            appOrderInfoDTO.setSDiscounts(appOrder.getSDiscounts());
            appOrderInfoDTO.setTDiscounts(appOrder.getTDiscounts());
        }

        //子订单
        List<AppOrderProInfo> proInfoList = appOrderProInfoMapper.selectList(Wrappers.<AppOrderProInfo>lambdaQuery().eq(AppOrderProInfo::getOrderId, orderId));
        appOrderInfoDTO.setProInfoList(proInfoList);

        //学校
        if(appOrder.getType().equals(CommonConstant.ORDER_TYPE_0)){
            if (appOrder.getOrderType() == 0) {
                //商品信息
                String productIds = appOrder.getProductIds();
                AppSitePriceRules appSitePriceRules = appSitePriceRulesMapper.selectById(productIds);
                AppSitePlace appSitePlace = appSitePlaceMapper.selectById(appSitePriceRules.getSitePlaceId());
                //使用须知
                if (ObjectUtils.isNotEmpty(appSitePlace.getReminder())) {
                    appOrderInfoDTO.setReminder(appSitePlace.getReminder());
                }
                //门店信息
                AppSite site = appSiteMapper.selectById(appSitePlace.getSiteId());
                appOrderInfoDTO.setSiteName(site.getName());
                appOrderInfoDTO.setRunStatus(site.getRunStatus());
                //预定信息
                appOrderInfoDTO.setDateOfSale(appSitePriceRules.getDateOfSale());
                appOrderInfoDTO.setStartTime(appSitePriceRules.getStartTime());
                appOrderInfoDTO.setEndTime(appSitePriceRules.getEndTime());
                StringBuilder userNames = new StringBuilder();
                for (AppOrderProInfo appOrderProInfo : proInfoList) {
                    userNames.append(appOrderProInfo.getUserName()).append(" ");
                }
                appOrderInfoDTO.setUserNames(String.valueOf(userNames));
                //地址信息
                appOrderInfoDTO.setSchoolAddress(site.getAddress());
                appOrderInfoDTO.setLatitude(site.getLatitude());
                appOrderInfoDTO.setLongitude(site.getLongitude());
                appOrderInfoDTO.setPhone(site.getPhone());
                appOrderInfoDTO.setAddressSiteId(site.getId());
            }
            //包场
            if (appOrder.getOrderType() == 1) {
                //商品信息
                String productIds = appOrder.getProductIds();
                AppSitePriceRules appSitePriceRules = appSitePriceRulesMapper.selectById(productIds);
                AppSitePlace appSitePlace = appSitePlaceMapper.selectById(appSitePriceRules.getSitePlaceId());
                //使用须知
                if (ObjectUtils.isNotEmpty(appSitePlace.getReminder())) {
                    appOrderInfoDTO.setReminder(appSitePlace.getReminder());
                }
                //场馆
                AppSite site = appSiteMapper.selectById(appSitePlace.getSiteId());
                appOrderInfoDTO.setSiteName(site.getName());
                appOrderInfoDTO.setRunStatus(site.getRunStatus());
                //退改规则、温馨提示
                appOrderInfoDTO.setReminder(appSitePlace.getReminder());
                appOrderInfoDTO.setAdvanceTime(appSitePlace.getAdvanceTime());

                //地址信息
                appOrderInfoDTO.setSchoolAddress(site.getAddress());
                appOrderInfoDTO.setLatitude(site.getLatitude());
                appOrderInfoDTO.setLongitude(site.getLongitude());
                appOrderInfoDTO.setPhone(site.getPhone());
                appOrderInfoDTO.setAddressSiteId(site.getId());
            }
            //无固定场
            if (appOrder.getOrderType() == 2) {
                //商品信息
                String productIds = appOrder.getProductIds();
                AppSitePriceRules appSitePriceRules = appSitePriceRulesMapper.selectById(productIds);
                AppSitePlace appSitePlace = appSitePlaceMapper.selectById(appSitePriceRules.getSitePlaceId());
                //使用须知
                if (ObjectUtils.isNotEmpty(appSitePlace.getReminder())) {
                    appOrderInfoDTO.setReminder(appSitePlace.getReminder());
                }
                //门店信息
                AppSite site = appSiteMapper.selectById(appSitePlace.getSiteId());
                appOrderInfoDTO.setSiteName(site.getName());
                appOrderInfoDTO.setRunStatus(site.getRunStatus());
                //预定信息
                appOrderInfoDTO.setStartTime(appSitePriceRules.getStartTime());
                appOrderInfoDTO.setEndTime(appSitePriceRules.getEndTime());
                appOrderInfoDTO.setRefundType(appSitePlace.getRefundType());
                //地址信息
                appOrderInfoDTO.setSchoolAddress(site.getAddress());
                appOrderInfoDTO.setLatitude(site.getLatitude());
                appOrderInfoDTO.setLongitude(site.getLongitude());
                appOrderInfoDTO.setPhone(site.getPhone());
                appOrderInfoDTO.setAddressSiteId(site.getId());
            }
        }

        //赛事
        if(appOrder.getType().equals(CommonConstant.ORDER_TYPE_1)){
            //商品信息
            String productIds = appOrder.getProductIds();
            AppGamePriceRules appGamePriceRules = appGamePriceRulesMapper.selectById(productIds);
            AppGame appGame = appGameMapper.selectById(appGamePriceRules.getGameId());

            //门店信息
            AppSite site = appSiteMapper.selectById(appGame.getSiteId());
            //退改规则、
            appOrderInfoDTO.setReminder(appGame.getReminder());
            //开始时间
            appOrderInfoDTO.setStartTime(appGame.getStartTime());
            //赛程安排
            List<AppGameScheduleVO> appGameScheduleVOList = appGameScheduleMapper.getListVo(appGame.getId());
            appOrderInfoDTO.setAppGameScheduleVOList(appGameScheduleVOList);
            //赛程数
            appOrderInfoDTO.setGameScheduleNum(appGameScheduleVOList.size());
            //地址信息
            appOrderInfoDTO.setSchoolAddress(site.getAddress());
            appOrderInfoDTO.setLatitude(site.getLatitude());
            appOrderInfoDTO.setLongitude(site.getLongitude());
            appOrderInfoDTO.setPhone(site.getPhone());
            appOrderInfoDTO.setAddressSiteId(site.getId());
        }

        //课程
        if(appOrder.getType().equals(CommonConstant.ORDER_TYPE_2)){
            //商品信息
            String productIds = appOrder.getProductIds();
            AppCourses appCourses = appCoursesMapper.selectById(productIds);
            appOrderInfoDTO.setAppCourses(appCourses);
            //使用须知
            if (ObjectUtils.isNotEmpty(appCourses.getReminder())) {
                appOrderInfoDTO.setReminder(appCourses.getReminder());
            }
            //门店信息
            AppSite site = appSiteMapper.selectById(appCourses.getSiteId());
            appOrderInfoDTO.setSiteName(site.getName());
            appOrderInfoDTO.setRunStatus(site.getRunStatus());
            //上课地点（经纬度）
            AppSite courseSite = appSiteMapper.selectById(appCourses.getAddressSiteId());
            appOrderInfoDTO.setCourseSiteAddress(courseSite.getAddress());
            appOrderInfoDTO.setLatitude(courseSite.getLatitude());
            appOrderInfoDTO.setLongitude(courseSite.getLongitude());
            appOrderInfoDTO.setPhone(courseSite.getPhone());
            appOrderInfoDTO.setAddressSiteId(courseSite.getId());
        }

        return appOrderInfoDTO;
    }

    @Override
    public List<QueryOrderVerifyRecordsVO> queryOrderVerifyRecords(String orderId, String ticketNo) {

        List<QueryOrderVerifyRecordsVO> list = new ArrayList<>();

        AppOrderProInfo proInfo = appOrderProInfoMapper.selectOne(Wrappers.<AppOrderProInfo>lambdaQuery().eq(AppOrderProInfo::getOrderId, orderId).eq(AppOrderProInfo::getTicketNo, ticketNo));

        String familyUserId = proInfo.getFamilyUserId();
        String appCourseId = proInfo.getProductId();

        List<AppCoursesVerificationRecord> verificationRecordList = appCoursesVerificationRecordMapper.selectList(Wrappers.<AppCoursesVerificationRecord>lambdaQuery()
                .eq(AppCoursesVerificationRecord::getOrderId, orderId)
                .eq(AppCoursesVerificationRecord::getCoursesId, appCourseId)
                .eq(AppCoursesVerificationRecord::getUseUserId, familyUserId));

        Map<Integer, List<AppCoursesVerificationRecord>> map = verificationRecordList.stream().collect(Collectors.groupingBy(AppCoursesVerificationRecord::getCoursesType));

        map.keySet().forEach(key -> {
            QueryOrderVerifyRecordsVO queryOrderVerifyRecordsVO = new QueryOrderVerifyRecordsVO();
            List<AppCoursesVerificationRecord> records = map.get(key);
            queryOrderVerifyRecordsVO.setCoursesType(key);
            queryOrderVerifyRecordsVO.setCoursesTotal(records.size());
            long verifyNum = records.stream().filter(e -> e.getVerifyStatus() == 1).count();
            queryOrderVerifyRecordsVO.setVerifyNum((int) verifyNum);
            long unVerifyNum = records.stream().filter(e -> e.getVerifyStatus() == 0).count();
            queryOrderVerifyRecordsVO.setUnVerifyNum((int) unVerifyNum);
            queryOrderVerifyRecordsVO.setRecordList(map.get(key));

            list.add(queryOrderVerifyRecordsVO);
        });

        return list;
    }

    /**
     * @return boolean
     * @Author SheepHy
     * @Description 查询用户对该类型课程是否有试听资格
     * @Date 16:45 2025/7/14
     * @Param courseId userId
     **/
    private boolean checkCourseDiscount(String categoryId, String userId) {
        boolean success = Boolean.TRUE;
        List<AppOrder> appOrders = appOrderMapper.selectList(Wrappers.<AppOrder>lambdaQuery()
                .eq(AppOrder::getUserId, userId)
                .ne(AppOrder::getOrderStatus, 6)
                .ne(AppOrder::getOrderStatus, 5)
                .eq(AppOrder::getStatus, 0)
                .eq(AppOrder::getDelFlag, 0)
                .eq(AppOrder::getType, 2));
        if (appOrders.isEmpty()) return true;
        for (AppOrder appOrder : appOrders) {
            if (!appOrder.getProductIds().contains(categoryId)) {
                success = false;
                break;
            }
        }
        return success;
    }

    /**
     * @return
     * @Author SheepHy
     * @Description 根据不同的类型生成订单及订单明细
     * @Date 15:09 2025/7/15
     * @Param id type userId
     **/
    @Transactional
    public AppOrder createOrder(List<String> id, int type, String userId, String userIds) {
        //todo 保险 闸机待接入
        //订单类型；0场地1赛事2课程
        AppOrder appOrder = new AppOrder();
        switch (type) {
            case 0:
                List<AppSitePriceRules> priceRules = appSitePriceRulesMapper.selectList(Wrappers.<AppSitePriceRules>lambdaQuery()
                        .in(AppSitePriceRules::getId, id));
                BigDecimal totalPrice = priceRules.stream()
                        .map(AppSitePriceRules::getSellingPrice)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                if (priceRules.get(0).getType() == 0) {
                    if (totalPrice.compareTo(BigDecimal.ZERO) == 0) {
                        appOrder.setPayType(3)
                                .setOrderStatus(2)
                                .setPayTime(new Date());
                    } else {
                        appOrder.setPayType(2)
                                .setOrderStatus(1);
                    }
                    String s = generateOrderNumber(0);
                    appOrder.setOrderCode(s)
                            .setOrderCode(priceRules.get(0).getOrgCode())
                            .setProductIds(priceRules.get(0).getSitePlaceId())
                            .setType(0)
                            .setUserId(userId)
                            .setOriginalPrice(totalPrice)
                            .setPrice(totalPrice)
                            .setCreateTime(new Date())
                            .setUpdateTime(new Date())
                            .setCreateBy(userId)
                            .setUpdateBy(userId);
                    createOrderCoupon(s, userIds);
                    appOrderMapper.insert(appOrder);
                    createOrderProduct(appOrder, id);
                }
                break;
            case 1:

                break;
            case 2:

                break;
        }
        return appOrder;
    }

    /**
     * @return String 订单号
     * @Author SheepHy
     * @Description 订单编号生成逻辑
     * @Date 17:18 2025/7/15
     * @params 类型：0-（D:订单） 1-（T:退单） 2-（B:保单）
     **/
    private String generateOrderNumber(int type) {
        String format = DateUtil.format(new Date(), "yyyyMMddHHmmss");
        int nextInt = ThreadLocalRandom.current().nextInt(1000, 10000);

        if (type == 0) {
            return "D" + format + nextInt;
        } else {
            return "T" + format + nextInt;
        }
    }

    /**
     * @return
     * @Author SheepHy
     * @Description 根据订单及购买人数生成对应券码
     * @Date 10:20 2025/7/16
     * @Param
     **/
    private void createOrderCoupon(String orderId, String userIds) {
        String lastFourDigits = orderId.substring(orderId.length() - 4);
        int nextInt = ThreadLocalRandom.current().nextInt(1000, 10000);
        Arrays.asList(userIds.split(",")).forEach(userId -> {
            String substring = userId.substring(orderId.length() - 2);
            AppIsin appIsin = new AppIsin();
            appIsin.setOrderId(orderId)
                    .setFamilyId(userId)
                    .setTicketNo(lastFourDigits + nextInt + substring)
                    .setIsinStatus(1)
                    .setCreateTime(new Date())
                    .setUpdateTime(new Date());
        });
    }

    /**
     * @Author SheepHy
     * @Description 生成订单明细
     * @Date 11:57 2025/7/16
     * @Param appOrder id
     **/
    private void createOrderProduct(AppOrder appOrder, List<String> id) {
        id.forEach(productId -> {
            AppOrderProduct appOrderProduct = new AppOrderProduct();
            appOrderProduct.setOrderId(appOrder.getId())
                    .setProductId(appOrder.getProductIds())
                    .setRuleId(productId)
                    .setCreateBy(appOrder.getCreateBy())
                    .setUpdateBy(appOrder.getUpdateBy())
                    .setCreateTime(new Date())
                    .setUpdateTime(new Date());
            appOrderProductMapper.insert(appOrderProduct);
        });
    }

    /**
     * 校验是否为第一次购买当前类目的课程
     *
     * @param userId
     * @param categoryId
     * @return
     */
    private Boolean checkOrderOrFree(String userId, String categoryId) {
        //查询当前用户的所有课程订单
        List<AppOrder> appOrders = appOrderMapper.selectList(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getUserId, userId).eq(AppOrder::getType, CommonConstant.ORDER_TYPE_2));
        for (AppOrder appOrder : appOrders) {
            AppCourses appCours = appCoursesMapper.selectById(appOrder.getProductIds());
            if (appCours.getCategoryId().equals(categoryId)) {
                return Boolean.TRUE;
            }
        }
        return Boolean.FALSE;
    }
}
