package shop.alien.storeplatform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import shop.alien.entity.result.R;
import shop.alien.entity.store.StoreCashOutRecord;
import shop.alien.entity.store.StoreIncomeDetailsRecord;
import shop.alien.entity.store.StoreInfo;
import shop.alien.entity.store.StoreUser;
import shop.alien.entity.store.vo.StoreCashOutRecordVo;
import shop.alien.entity.store.vo.StoreIncomeDetailsRecordVo;
import shop.alien.mapper.StoreCashOutRecordMapper;
import shop.alien.mapper.StoreIncomeDetailsRecordMapper;
import shop.alien.mapper.StoreInfoMapper;
import shop.alien.mapper.StoreUserMapper;
import shop.alien.storeplatform.service.IncomeManageService;
import shop.alien.storeplatform.util.LoginUserUtil;
import shop.alien.util.common.ListToPage;
import shop.alien.util.common.constant.CouponTypeEnum;
import shop.alien.util.date.DateUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * web端商户收入管理服务实现
 *
 * @author ssk
 * @since 2025-11-14
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class IncomeManageServiceImpl extends ServiceImpl<StoreIncomeDetailsRecordMapper, StoreIncomeDetailsRecord> implements IncomeManageService {

    private final StoreIncomeDetailsRecordMapper storeIncomeDetailsRecordMapper;
    private final StoreInfoMapper storeInfoMapper;
    private final StoreUserMapper storeUserMapper;
    private final StoreCashOutRecordMapper storeCashOutRecordMapper;

    @Override
    public com.alibaba.fastjson2.JSONObject getPaymentCycle(Integer storeId, Integer incomeType, Integer paymentType,
                                      String startTime, String endTime, int page, int size) {
        log.info("IncomeManageServiceImpl.getPaymentCycle - 开始查询账期: storeId={}, incomeType={}, paymentType={}, startTime={}, endTime={}, page={}, size={}",
                storeId, incomeType, paymentType, startTime, endTime, page, size);

        QueryWrapper<StoreIncomeDetailsRecord> wrapper = new QueryWrapper<>();
        com.alibaba.fastjson2.JSONObject jsonObject = new com.alibaba.fastjson2.JSONObject();
        Date now = new Date();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");

        // 1. 根据账期类型设置查询条件
        if (paymentType != null && paymentType == 0) {
            // 未到账期: 未绑定提现记录 & 当前时间-3天大于创建时间
            wrapper.isNull("sidr.cash_out_id");
            wrapper.gt("sidr.created_time", DateUtils.calcDays(new Date(), -3));
            Date startDate = DateUtils.calcDays(now, -3);
            jsonObject.put("date", df.format(startDate) + " ~ " + df.format(now));
            log.debug("IncomeManageServiceImpl.getPaymentCycle - 未到账期: date={}", jsonObject.get("date"));
        } else if (paymentType != null && paymentType == 1) {
            // 已到账期: 已绑定提现记录 & 当前时间-4~27天大于创建时间
//            wrapper.isNotNull("sidr.cash_out_id");
            wrapper.between("sidr.created_time", DateUtils.calcDays(new Date(), -27), DateUtils.calcDays(new Date(), -4));
            Date startDate = DateUtils.calcDays(now, -27);
            Date endDate = DateUtils.calcDays(now, -4);
            jsonObject.put("date", df.format(startDate) + " ~ " + df.format(endDate));
            log.debug("IncomeManageServiceImpl.getPaymentCycle - 已到账期: date={}", jsonObject.get("date"));
        }

        // 2. 门店ID条件
        if (storeId != null) {
            wrapper.eq("sidr.store_id", storeId);
        }

        // 3. 时间范围条件（用户选择的时间范围）
        if (StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime)) {
            LocalDate startDate = LocalDate.parse(startTime);
            LocalDate endDate = LocalDate.parse(endTime);
            LocalDateTime startOfDay = startDate.atStartOfDay();
            LocalDateTime endOfDay = endDate.atTime(LocalTime.MAX);
            wrapper.between("sidr.created_time", startOfDay, endOfDay)
                    .orderByDesc("sidr.created_time");
        }

        // 4. 收入类型条件
        if (null != incomeType) {
            if (0 == incomeType) {
                // 主页: 包含优惠券和代金券
                wrapper.in("sidr.income_type", CouponTypeEnum.COUPON.getCode(), CouponTypeEnum.GROUP_BUY.getCode());
                log.debug("IncomeManageServiceImpl.getPaymentCycle - 收入类型: 主页（优惠券+代金券）");
            } else {
                wrapper.eq("sidr.income_type", incomeType);
                log.debug("IncomeManageServiceImpl.getPaymentCycle - 收入类型: {}", incomeType);
            }
        }

        // 5. 查询收入明细记录列表
        List<StoreIncomeDetailsRecordVo> list = storeIncomeDetailsRecordMapper.selectRecordList(wrapper);
        log.info("IncomeManageServiceImpl.getPaymentCycle - 查询到收入记录数: {}", list.size());

        // 6. 查询门店信息（用于获取抽成比例）
        StoreInfo storeInfo = storeInfoMapper.selectById(storeId);
        if (storeInfo == null) {
            log.warn("IncomeManageServiceImpl.getPaymentCycle - 门店不存在: storeId={}", storeId);
            throw new RuntimeException("门店不存在");
        }

        // 7. 处理列表数据：格式化金额、日期
        for (StoreIncomeDetailsRecordVo storeIncomeDetailsRecord : list) {
            if (storeIncomeDetailsRecord == null) {
                continue;
            }
            
            StoreIncomeDetailsRecordVo vo = new StoreIncomeDetailsRecordVo();
            BeanUtils.copyProperties(storeIncomeDetailsRecord, vo);
            
            // 将金额从分转换为元（保留2位小数）
            storeIncomeDetailsRecord.setMoneyStr(
                    new BigDecimal(vo.getMoney())
                            .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                            .toString()
            );
            
            // 格式化日期
            String format = df.format(storeIncomeDetailsRecord.getCreatedTime());
            storeIncomeDetailsRecord.setDate(format);
            
            // 设置抽成比例
            vo.setCommissionRate(storeInfo.getCommissionRate());
        }

        // 8. 手动分页
        jsonObject.put("data", ListToPage.setPage(list, page, size));

        // 9. 计算总金额（元）
        int totalMoney = list.stream().mapToInt(StoreIncomeDetailsRecord::getMoney).sum();
        jsonObject.put("money",
                new BigDecimal(totalMoney)
                        .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                        .toString()
        );

        log.info("IncomeManageServiceImpl.getPaymentCycle - 查询完成: 总记录数={}, 总金额={}元",
                list.size(), jsonObject.get("money"));

        return jsonObject;
    }

    @Override
    public Map<String, Object> getAccountBalance(Integer storeId) {
        log.info("IncomeManageServiceImpl.getAccountBalance - 开始查询账户余额: storeId={}", storeId);

        Map<String, Object> map = new HashMap<>();

        // 1. 查询店铺用户信息，获取账户总余额
        LambdaQueryWrapper<StoreUser> storeUserWrapper = new LambdaQueryWrapper<>();
        storeUserWrapper.eq(StoreUser::getStoreId, storeId);
        StoreUser storeUser = storeUserMapper.selectOne(storeUserWrapper);

        if (storeUser == null) {
            log.warn("IncomeManageServiceImpl.getAccountBalance - 店铺用户不存在: storeId={}", storeId);
            throw new RuntimeException("店铺用户不存在");
        }

        // 2. 账户总余额（单位：元，保留2位小数）
        String balance = new BigDecimal(storeUser.getMoney())
                .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                .toString();
        map.put("balance", balance);
        log.debug("IncomeManageServiceImpl.getAccountBalance - 账户总余额: {}元", balance);

        // 3. 查询可提现金额（4~27天内的收入，且未绑定提现记录）
        LambdaQueryWrapper<StoreIncomeDetailsRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.between(StoreIncomeDetailsRecord::getCreatedTime,
                        DateUtils.calcDays(new Date(), -27),
                        DateUtils.calcDays(new Date(), -4))
                .isNull(StoreIncomeDetailsRecord::getCashOutId)  // 未绑定提现记录
                .eq(StoreIncomeDetailsRecord::getStoreId, storeId)
                .eq(StoreIncomeDetailsRecord::getIncomeType, CouponTypeEnum.COUPON.getCode());

        List<StoreIncomeDetailsRecord> incomeList = storeIncomeDetailsRecordMapper.selectList(wrapper);
        
        // 计算可提现收入总额（分）
        int cashOutMoney = incomeList.stream()
                .mapToInt(StoreIncomeDetailsRecord::getMoney)
                .sum();
        
        log.debug("IncomeManageServiceImpl.getAccountBalance - 4~27天内收入总额: {}分", cashOutMoney);

        // 4. 查询已提现和待审核的金额（需要扣除）
        // payment_status: 1-待审核, 3-已提现
        QueryWrapper<StoreCashOutRecord> cashOutWrapper = new QueryWrapper<>();
        cashOutWrapper.eq("store_id", storeId)
                .in("payment_status", "1", "3")
                .eq("delete_flag", "0");
        
        List<StoreCashOutRecord> storeCashOutRecords = storeCashOutRecordMapper.selectList(cashOutWrapper);
        
        // 计算已提现和待审核的总金额（分）
        int totalCashOutAmount = storeCashOutRecords.stream()
                .collect(Collectors.summingInt(StoreCashOutRecord::getMoney));
        
        log.debug("IncomeManageServiceImpl.getAccountBalance - 已提现+待审核金额: {}分", totalCashOutAmount);

        // 5. 计算最终可提现金额 = 可提现收入 - （已提现 + 待审核）
        BigDecimal finalCashOutMoney = new BigDecimal(cashOutMoney)
                .subtract(BigDecimal.valueOf(totalCashOutAmount))
                .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        
        map.put("cashOutMoney", finalCashOutMoney.toString());

        log.info("IncomeManageServiceImpl.getAccountBalance - 查询完成: 总余额={}元, 可提现金额={}元",
                balance, finalCashOutMoney);

        return map;
    }

    /**
     * 提现申请
     * 
     * @param storeId         门店ID
     * @param payPassword     支付密码
     * @param withdrawalMoney 提现金额（单位：分）
     * @return 提现结果
     */
    @Transactional
    @Override
    public R<?> cashOut(Integer storeId, String payPassword, Integer withdrawalMoney) {
        log.info("IncomeManageServiceImpl.cashOut - 开始处理提现: storeId={}, withdrawalMoney={}分",
                storeId, withdrawalMoney);

        // 1. 验证支付密码并查询用户信息
        LambdaQueryWrapper<StoreUser> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.eq(StoreUser::getStoreId, storeId)
                .eq(StoreUser::getPayPassword, payPassword);
        StoreUser storeUser = storeUserMapper.selectOne(userWrapper);

        if (storeUser == null) {
            log.warn("IncomeManageServiceImpl.cashOut - 支付密码错误: storeId={}", storeId);
            return R.fail("支付密码错误");
        }

        // 2. 验证账户余额是否充足
        if (storeUser.getMoney() < withdrawalMoney) {
            log.warn("IncomeManageServiceImpl.cashOut - 余额不足: 账户余额={}分, 提现金额={}分",
                    storeUser.getMoney(), withdrawalMoney);
            return R.fail("余额不足");
        }

        // 3. 验证提现金额是否满足最低要求（0.1元 = 10分）
        BigDecimal amountInYuan = new BigDecimal(withdrawalMoney)
                .divide(new BigDecimal(100), 2, RoundingMode.DOWN);
        if (amountInYuan.compareTo(new BigDecimal("0.1")) < 0) {
            log.warn("IncomeManageServiceImpl.cashOut - 提现金额过小: {}元", amountInYuan);
            return R.fail("金额不能小于0.1元");
        }

        log.info("IncomeManageServiceImpl.cashOut - 验证通过: 账户余额={}分, 提现金额={}元",
                storeUser.getMoney(), amountInYuan);

        // 4. 调用支付宝转账
        // 注意：这里需要集成支付宝API，目前先创建提现申请记录
        // 实际生产环境需要调用 AliApi.pay() 或 AliApi.payAccount()
        
        try {
            // TODO: 调用支付宝转账API
            // StoreAliPayLog pay;
            // if (StringUtils.isNotBlank(storeUser.getAlipayAccount())) {
            //     pay = aliApi.pay(storeUser.getName(), storeUser.getIdCard(), 
            //                      storeUser.getAlipayAccount(), amountInYuan.toString());
            // } else {
            //     pay = aliApi.payAccount(storeUser.getName(), storeUser.getIdCard(), 
            //                            null, amountInYuan.toString(), storeUser.getPhone());
            // }
            
            // 5. 创建提现记录（待审核状态）
            //增加提现申请记录
            StoreCashOutRecord storeCashOutRecord = new StoreCashOutRecord();
            storeCashOutRecord.setStoreId(storeId);
            storeCashOutRecord.setMoney(withdrawalMoney);
//            storeCashOutRecord.setCommission(commission);
            storeCashOutRecord.setCashOutType(0);
            storeCashOutRecord.setPaymentStatus(3);
            storeCashOutRecord.setDeleteFlag(0);
            storeCashOutRecord.setIncomeStartTime(new Date());
            storeCashOutRecord.setIncomeEndTime(new Date());
            storeCashOutRecord.setStoreUserId(storeUser.getId());

            // 插入提现记录
            int insertResult = storeCashOutRecordMapper.insert(storeCashOutRecord);
            if (insertResult <= 0) {
                log.error("IncomeManageServiceImpl.cashOut - 创建提现记录失败");
                throw new RuntimeException("创建提现记录失败");
            }

            // 6. 扣减账户余额
//            StoreUser updateUser = new StoreUser();
//            updateUser.setId(storeUser.getId());
//            updateUser.setMoney(storeUser.getMoney() - withdrawalMoney);
//            int updateResult = storeUserMapper.updateById(updateUser);
//            if (updateResult <= 0) {
//                log.error("IncomeManageServiceImpl.cashOut - 更新账户余额失败");
//                throw new RuntimeException("更新账户余额失败");
//            }

            log.info("IncomeManageServiceImpl.cashOut - 提现申请成功: 提现记录ID={}, 提现金额={}元",
                    storeCashOutRecord.getId(), amountInYuan);

            // 7. 返回结果
            Map<String, Object> result = new HashMap<>();
            result.put("cashOutRecordId", storeCashOutRecord.getId());
            result.put("withdrawalMoney", amountInYuan.toString());
            result.put("status", "pending");  // pending-待审核
            result.put("message", "提现申请已提交，等待审核");
            
            return R.data(result);

        } catch (Exception e) {
            log.error("IncomeManageServiceImpl.cashOut - 提现失败: {}", e.getMessage(), e);
            
            // 如果是已知的运行时异常，直接抛出让事务回滚
            if (e instanceof RuntimeException) {
                throw (RuntimeException) e;
            }
            
            // 其他异常也需要回滚
            throw new RuntimeException("提现失败：" + e.getMessage(), e);
        }
    }

    /**
     * 提现记录查询
     *
     * @param storeId          门店ID
     * @param cashOutStartTime 开始时间
     * @param cashOutEndTime   结束时间
     * @param paymentStatus    提现状态
     * @param page             页码
     * @param size             每页条数
     * @return 提现记录列表
     */
    @Override
    public Object getCashOutRecordList(Integer storeId, String cashOutStartTime, String cashOutEndTime,
                                       String paymentStatus, Integer page, Integer size) {
        log.info("IncomeManageServiceImpl.getCashOutRecordList - 开始查询提现记录: storeId={}, cashOutStartTime={}, cashOutEndTime={}, paymentStatus={}, page={}, size={}",
                storeId, cashOutStartTime, cashOutEndTime, paymentStatus, page, size);

        // 1. 构建查询条件（使用QueryWrapper和表别名scor，以配合selectCashoutRecordList的LEFT JOIN查询）
        QueryWrapper<StoreCashOutRecord> wrapper = new QueryWrapper<>();
        
        // 必填条件：门店ID
        wrapper.eq("scor.store_id", storeId);
        
        // 可选条件：提现状态
        if (StringUtils.isNotBlank(paymentStatus)) {
            wrapper.eq("scor.payment_status", paymentStatus);
            log.debug("IncomeManageServiceImpl.getCashOutRecordList - 筛选提现状态: {}", paymentStatus);
        }
        
        // 可选条件：结束时间
        if (StringUtils.isNotBlank(cashOutEndTime)) {
            wrapper.le("scor.created_time", cashOutEndTime + " 23:59:59");
            log.debug("IncomeManageServiceImpl.getCashOutRecordList - 结束时间: {}", cashOutEndTime);
        }
        
        // 可选条件：开始时间
        if (StringUtils.isNotBlank(cashOutStartTime)) {
            wrapper.ge("scor.created_time", cashOutStartTime + " 00:00:00");
            log.debug("IncomeManageServiceImpl.getCashOutRecordList - 开始时间: {}", cashOutStartTime);
        }
        
        // 删除标识（软删除）
        wrapper.eq("scor.delete_flag", 0);
        
        // 按创建时间倒序排序
        wrapper.orderByDesc("scor.created_time");

        // 2. 查询所有符合条件的记录（LEFT JOIN store_user，获取结算账户信息）
        List<StoreCashOutRecord> recordList = storeCashOutRecordMapper.selectCashoutRecordList(wrapper);
        log.info("IncomeManageServiceImpl.getCashOutRecordList - 查询到提现记录数: {}", recordList.size());

        // 3. 手动分页
        IPage<StoreCashOutRecord> storeCashOutRecordIPage = ListToPage.setPage(recordList, page, size);

        // 4. 构建返回VO
        StoreCashOutRecordVo vo = new StoreCashOutRecordVo();
        
        // 分页后的记录列表
        vo.setCashOutRecordList(storeCashOutRecordIPage.getRecords());
        
        // 提现总金额（仅统计状态为1-待审核的记录）
        int totalMoney = recordList.stream()
                .filter(item -> "1".equals(item.getPaymentStatus().toString()))
                .mapToInt(StoreCashOutRecord::getMoney)
                .sum();
        BigDecimal cashOutAllMoney = new BigDecimal(totalMoney)
                .divide(new BigDecimal(100), 2, RoundingMode.DOWN);
        vo.setCashOutAllMoney(cashOutAllMoney);
        
        // 提现记录总数
        vo.setCashOutNum(recordList.size());

        // 分页信息
        vo.setCurrentPage(storeCashOutRecordIPage.getCurrent());
        vo.setPageSize(storeCashOutRecordIPage.getSize());
        vo.setTotal(storeCashOutRecordIPage.getTotal());
        vo.setTotalPages(storeCashOutRecordIPage.getPages());

        log.info("IncomeManageServiceImpl.getCashOutRecordList - 查询完成: 总记录数={}, 总金额={}元, 当前页={}/{}, 总页数={}",
                recordList.size(), cashOutAllMoney, vo.getCurrentPage(), vo.getPageSize(), vo.getTotalPages());

        return vo;
    }

    /**
     * 提现记录详情查询
     *
     * @param id 提现记录ID
     * @return 提现记录详情
     */
    @Override
    public StoreCashOutRecord getCashOutRecordDetail(Integer id) {
        log.info("IncomeManageServiceImpl.getCashOutRecordDetail - 开始查询提现记录详情: id={}", id);

        // ==================== 1. 参数验证 ====================
        if (id == null) {
            log.warn("IncomeManageServiceImpl.getCashOutRecordDetail - 提现记录ID为空");
            throw new RuntimeException("提现记录ID不能为空");
        }

        // ==================== 2. 查询提现记录 ====================
        StoreCashOutRecord record = storeCashOutRecordMapper.selectById(id);
        if (record == null || record.getDeleteFlag() == 1) {
            log.warn("IncomeManageServiceImpl.getCashOutRecordDetail - 提现记录不存在: id={}", id);
            throw new RuntimeException("提现记录不存在");
        }

        // ==================== 3. 权限校验（只能查看自己店铺的提现记录） ====================
        Integer storeId = LoginUserUtil.getCurrentStoreId();
        if (!record.getStoreId().equals(storeId)) {
            log.warn("IncomeManageServiceImpl.getCashOutRecordDetail - 无权查看他人提现记录: currentStoreId={}, recordStoreId={}",
                    storeId, record.getStoreId());
            throw new RuntimeException("无权查看该提现记录");
        }

        log.info("IncomeManageServiceImpl.getCashOutRecordDetail - 查询完成: id={}, storeId={}, money={}, status={}",
                id, record.getStoreId(), record.getMoney(), record.getPaymentStatus());

        return record;
    }

    /**
     * 今日收益查询
     * <p>
     * 接口迁移来源: App端 /alienStore/storeIncomeDetailsRecord/groupIncome?date=2025-11-11&storeId=103&incomeType=0&page=1&size=10
     * </p>
     *
     * @param storeId    门店ID
     * @param date       日期
     * @param incomeType 收入类型
     * @param page       页码
     * @param size       每页条数
     * @return 今日收益信息
     */
    @Override
    public Object getGroupIncome(Integer storeId, String date, Integer incomeType, Integer page, Integer size) {
        log.info("IncomeManageServiceImpl.getGroupIncome - 开始查询今日收益: storeId={}, date={}, incomeType={}, page={}, size={}",
                storeId, date, incomeType, page, size);

        // 1. 构建查询条件：指定日期内、未绑定提现记录
        LambdaQueryWrapper<StoreIncomeDetailsRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.between(StoreIncomeDetailsRecord::getCreatedTime, date + " 00:00:00", date + " 23:59:59")
                .isNull(StoreIncomeDetailsRecord::getCashOutId)  // 未绑定提现记录
                .eq(StoreIncomeDetailsRecord::getStoreId, storeId);

        // 2. 收入类型筛选
        // 2025-11-17 前端展示逻辑将团购券去掉，仅展示优惠券（前端不传0）
        if (null != incomeType && 0 == incomeType) {
            wrapper.in(StoreIncomeDetailsRecord::getIncomeType,
                    CouponTypeEnum.COUPON.getCode(), CouponTypeEnum.GROUP_BUY.getCode());
            log.debug("IncomeManageServiceImpl.getGroupIncome - 收入类型: 主页（优惠券+团购券）");
        } else if (null != incomeType) {
            wrapper.eq(StoreIncomeDetailsRecord::getIncomeType, incomeType);
            log.debug("IncomeManageServiceImpl.getGroupIncome - 收入类型: {}", incomeType);
        }

        // 3. 查询店铺信息
        StoreInfo storeInfo = storeInfoMapper.selectById(storeId);
        if (storeInfo == null) {
            log.warn("IncomeManageServiceImpl.getGroupIncome - 门店不存在: storeId={}", storeId);
            throw new RuntimeException("门店不存在");
        }

        // 4. 查询收入明细记录
        List<StoreIncomeDetailsRecord> list = this.list(wrapper);
        log.info("IncomeManageServiceImpl.getGroupIncome - 查询到收入记录数: {}", list.size());

        // 5. 计算总收入和手续费
        Integer allIncome = 0;
        Integer commission = 0;
        for (StoreIncomeDetailsRecord storeIncomeDetailsRecord : list) {
            allIncome += storeIncomeDetailsRecord.getMoney();
            commission += storeIncomeDetailsRecord.getCommission();
        }

        // 6. 构建返回VO
        StoreIncomeDetailsRecordVo vo = new StoreIncomeDetailsRecordVo();
        vo.setCommissionRate(storeInfo.getCommissionRate());
        vo.setDate(date);
        vo.setStoreName(storeInfo.getStoreName());
        vo.setStoreId(storeId);

        // 7. 格式化金额信息
        // 售价（收入+手续费）
        vo.setIncomeMoney(
                new BigDecimal(allIncome)
                        .add(new BigDecimal(commission))
                        .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                        .toString()
        );

        // 手续费
        vo.setCommissionStr(
                new BigDecimal(commission)
                        .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                        .toString()
        );

        // 收益（售价-手续费，存入时已经减完了）
        vo.setNoYetPaymentMoney(
                new BigDecimal(allIncome)
                        .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                        .toString()
        );

        // 8. 查询明细记录列表（含退款标识）
        QueryWrapper<StoreIncomeDetailsRecordVo> incomeWrapper = new QueryWrapper<>();
        incomeWrapper.eq("income.delete_flag", 0)
                .eq("income.store_id", storeId)
                .between("income.created_time", date + " 00:00:00", date + " 23:59:59")
                .orderByDesc("income.created_time");

        if (null != incomeType) {
            if (0 == incomeType) {
                incomeWrapper.in("income_type",
                        CouponTypeEnum.COUPON.getCode(), CouponTypeEnum.GROUP_BUY.getCode());
            } else {
                incomeWrapper.eq("income_type", incomeType);
            }
        }

        List<StoreIncomeDetailsRecordVo> incomeDetailsRecordVoList =
                storeIncomeDetailsRecordMapper.getIncomeList(incomeWrapper);

        // 9. 按退款类型分组
        Map<String, List<StoreIncomeDetailsRecordVo>> collect =
                incomeDetailsRecordVoList.stream()
                        .collect(Collectors.groupingBy(x -> x.getRefundType()));

        // 10. 设置明细列表（不含退款）和统计信息
        vo.setIncomeDetailsRecordVoList(new ArrayList<>());
        vo.setRefundMoney(new BigDecimal(0));
        vo.setCouponCount(0);

        // 过滤出正常收入记录（不含退款的记录用于分页）
        List<StoreIncomeDetailsRecordVo> normalRecords = incomeDetailsRecordVoList.stream()
                .filter(x -> !"true".equals(x.getRefundType()))
                .collect(Collectors.toList());

        // 正常收入记录（未退款）- 进行分页
        if (collect.containsKey("false")) {
            // 使用过滤后的正常记录进行分页
            IPage<StoreIncomeDetailsRecordVo> pageResult = ListToPage.setPage(normalRecords, page, size);
            vo.setIncomeDetailsRecordVoList(pageResult.getRecords());
            
            // 设置分页信息
            vo.setTotal(pageResult.getTotal());
            vo.setTotalPages(pageResult.getPages());
            vo.setCurrentPage(pageResult.getCurrent());
            vo.setPageSize(pageResult.getSize());
            
            // 计算券数量（正常订单 - 退款订单）
            vo.setCouponCount(
                    collect.get("false").size() -
                            (collect.containsKey("true") ? collect.get("true").size() : 0)
            );
        } else {
            // 没有正常记录时，也设置分页信息
            vo.setTotal(0L);
            vo.setTotalPages(0L);
            vo.setCurrentPage((long) page);
            vo.setPageSize((long) size);
        }

        // 退款金额统计
        if (collect.containsKey("true")) {
            vo.setRefundMoney(
                    new BigDecimal(
                            collect.get("true").stream()
                                    .mapToInt(StoreIncomeDetailsRecordVo::getMoney)
                                    .sum()
                    ).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
            );
        }

        log.info("IncomeManageServiceImpl.getGroupIncome - 查询完成: 总收入={}元, 手续费={}元, 券数量={}, 记录总数={}, 当前页={}/{}, 总页数={}",
                vo.getNoYetPaymentMoney(), vo.getCommissionStr(), vo.getCouponCount(), 
                vo.getTotal(), vo.getCurrentPage(), vo.getPageSize(), vo.getTotalPages());

        return vo;
    }

    /**
     * 快速提现申请（免审核，直接通过状态）
     * 与app端applyCashOut逻辑保持一致
     *
     * @param storeId         门店ID
     * @param payPassword     支付密码
     * @param withdrawalMoney 提现金额（单位：分）
     * @return 提现结果
     */
    @Transactional
    @Override
    public R<?> applyFastCashOut(Integer storeId, String payPassword, Integer withdrawalMoney) {
        log.info("IncomeManageServiceImpl.applyFastCashOut - 开始处理快速提现: storeId={}, withdrawalMoney={}分",
                storeId, withdrawalMoney);

        // 1. 验证支付密码并查询用户信息
        LambdaQueryWrapper<StoreUser> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.eq(StoreUser::getStoreId, storeId)
                .eq(StoreUser::getPayPassword, payPassword);
        StoreUser storeUser = storeUserMapper.selectOne(userWrapper);

        if (storeUser == null) {
            log.warn("IncomeManageServiceImpl.applyFastCashOut - 支付密码错误: storeId={}", storeId);
            return R.fail("支付密码错误");
        }

        // 2. 验证账户余额是否充足
        if (storeUser.getMoney() <= withdrawalMoney) {
            log.warn("IncomeManageServiceImpl.applyFastCashOut - 余额不足: 账户余额={}分, 提现金额={}分",
                    storeUser.getMoney(), withdrawalMoney);
            return R.fail("余额不足");
        }

        // 3. 验证提现金额是否满足最低要求（0.1元 = 10分）
        BigDecimal amountInYuan = new BigDecimal(withdrawalMoney)
                .divide(new BigDecimal(100), 2, RoundingMode.DOWN);
        if (amountInYuan.compareTo(new BigDecimal("0.1")) < 0) {
            log.warn("IncomeManageServiceImpl.applyFastCashOut - 提现金额过小: {}元", amountInYuan);
            return R.fail("金额不能小于0.1元");
        }

        log.info("IncomeManageServiceImpl.applyFastCashOut - 验证通过: 账户余额={}分, 提现金额={}元",
                storeUser.getMoney(), amountInYuan);

        try {
            // 4. 创建提现记录（已通过状态，与app端保持一致）
            StoreCashOutRecord storeCashOutRecord = new StoreCashOutRecord();
            storeCashOutRecord.setStoreId(storeId);
            storeCashOutRecord.setMoney(withdrawalMoney);
            storeCashOutRecord.setCashOutType(0);  // 0-全部提现
            storeCashOutRecord.setPaymentStatus(3);  // 3-已通过（与app端保持一致）
            storeCashOutRecord.setDeleteFlag(0);
            storeCashOutRecord.setIncomeStartTime(new Date());
            storeCashOutRecord.setIncomeEndTime(new Date());
            storeCashOutRecord.setStoreUserId(storeUser.getId());

            // 5. 插入提现记录
            int insertResult = storeCashOutRecordMapper.insert(storeCashOutRecord);
            if (insertResult <= 0) {
                log.error("IncomeManageServiceImpl.applyFastCashOut - 创建提现记录失败");
                throw new RuntimeException("创建提现记录失败");
            }

            log.info("IncomeManageServiceImpl.applyFastCashOut - 快速提现申请成功: 提现记录ID={}, 提现金额={}元",
                    storeCashOutRecord.getId(), amountInYuan);

            // 6. 返回结果（返回StoreCashOutRecord对象，与app端保持一致）
            return R.data(storeCashOutRecord);

        } catch (Exception e) {
            log.error("IncomeManageServiceImpl.applyFastCashOut - 快速提现失败: {}", e.getMessage(), e);

            // 如果是已知的运行时异常，直接抛出让事务回滚
            if (e instanceof RuntimeException) {
                throw (RuntimeException) e;
            }

            // 其他异常也需要回滚
            throw new RuntimeException("快速提现失败：" + e.getMessage(), e);
        }
    }

    /**
     * 已入账/未入账详情查询
     *
     * @param storeId     门店ID
     * @param incomeType  收入类型, 0:主页, 1:优惠券, 2:代金券, 3:套餐, 4:联名卡
     * @param paymentType 账期类型,0:未入账,1:已入账
     * @param startTime   开始时间
     * @param endTime     结束时间
     * @param page        页数
     * @param size        条数
     * @return 入账详情
     */
    @Override
    public com.alibaba.fastjson2.JSONObject getPaymentDetails(Integer storeId, Integer incomeType, Integer paymentType,
                                                               String startTime, String endTime, int page, int size) {
        log.info("IncomeManageServiceImpl.getPaymentDetails - 查询入账详情: storeId={}, incomeType={}, paymentType={}, startTime={}, endTime={}, page={}, size={}",
                storeId, incomeType, paymentType, startTime, endTime, page, size);

        QueryWrapper<StoreIncomeDetailsRecord> wrapper = new QueryWrapper<>();
        com.alibaba.fastjson2.JSONObject result = new com.alibaba.fastjson2.JSONObject();
        Date now = new Date();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");

        // 根据 paymentType 设置时间范围和条件
        if (paymentType == 0) {
            // 未入账: 当前时间-3天内的记录
            wrapper.isNull("sidr.cash_out_id");
            wrapper.gt("sidr.created_time", DateUtils.calcDays(new Date(), -3));
            Date startDate = DateUtils.calcDays(now, -3);
            result.put("date", df.format(startDate) + " ~ " + df.format(now));
            log.info("IncomeManageServiceImpl.getPaymentDetails - 未入账时间范围: {} ~ {}", df.format(startDate), df.format(now));
        } else {
            // 已入账: 当前时间-4~27天的记录
            wrapper.between("sidr.created_time", DateUtils.calcDays(new Date(), -27), DateUtils.calcDays(new Date(), -4));
            Date startDate = DateUtils.calcDays(now, -27);
            Date endDate = DateUtils.calcDays(now, -4);
            result.put("date", df.format(startDate) + " ~ " + df.format(endDate));
            log.info("IncomeManageServiceImpl.getPaymentDetails - 已入账时间范围: {} ~ {}", df.format(startDate), df.format(endDate));
        }

        // 店铺ID条件
        if (storeId != null) {
            wrapper.eq("sidr.store_id", storeId);
        }

        // 自定义时间范围（用户输入的时间范围）
        LocalDate startDate = LocalDate.parse(startTime);
        LocalDate endDate = LocalDate.parse(endTime);
        LocalDateTime startOfDay = startDate.atStartOfDay();
        LocalDateTime endOfDay = endDate.atTime(LocalTime.MAX);
        wrapper.between("sidr.created_time", startOfDay, endOfDay)
                .orderByDesc("sidr.created_time");

        // 收入类型条件
        if (null != incomeType) {
            if (0 == incomeType) {
                // 主页: 包含优惠券和团购券
                wrapper.in("sidr.income_type", CouponTypeEnum.COUPON.getCode(), CouponTypeEnum.GROUP_BUY.getCode());
            } else {
                wrapper.eq("sidr.income_type", incomeType);
            }
        }

        // 查询收入明细列表
        List<StoreIncomeDetailsRecordVo> list = storeIncomeDetailsRecordMapper.selectRecordList(wrapper);
        log.info("IncomeManageServiceImpl.getPaymentDetails - 查询到记录数: {}", list.size());

        // 查询店铺信息
        StoreInfo storeInfo = storeInfoMapper.selectById(storeId);

        // 处理每条记录的数据格式
        for (StoreIncomeDetailsRecordVo record : list) {
            // 空值检查
            if (record == null) {
                continue;
            }
            
            StoreIncomeDetailsRecordVo vo = new StoreIncomeDetailsRecordVo();
            BeanUtils.copyProperties(record, vo);

            // 转换金额格式（分转元，保留2位小数）
            record.setMoneyStr(new BigDecimal(vo.getMoney())
                    .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());

            // 设置日期
            String format = df.format(record.getCreatedTime());
            record.setDate(format);

            // 设置抽成比例
            record.setCommissionRate(storeInfo.getCommissionRate());

            // 计算售价（收益 + 手续费）
            record.setIncomeMoney(new BigDecimal(vo.getMoney())
                    .add(new BigDecimal(vo.getCommission()))
                    .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());

            // 设置手续费
            record.setCommissionStr(new BigDecimal(vo.getCommission())
                    .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());

            vo.setCommissionRate(storeInfo.getCommissionRate());
        }

        // 分页处理
        result.put("data", ListToPage.setPage(list, page, size));

        // 计算总金额（元）
        BigDecimal totalMoney = new BigDecimal(list.stream()
                .mapToInt(StoreIncomeDetailsRecord::getMoney)
                .sum())
                .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        result.put("money", totalMoney.toString());

        log.info("IncomeManageServiceImpl.getPaymentDetails - 查询完成: 总金额={}元, 记录数={}",
                totalMoney, list.size());

        return result;
    }

    /**
     * 收入汇总统计
     * 整合四项关键数据：可提现金额、今日收益、已入账、未入账
     *
     * @param storeId 门店ID
     * @return 收入汇总统计数据
     */
    @Override
    public Map<String, Object> getIncomeSummary(Integer storeId) {
        log.info("IncomeManageServiceImpl.getIncomeSummary - 开始查询收入汇总: storeId={}", storeId);

        Map<String, Object> result = new HashMap<>();

        try {
            // ==================== 1. 账户余额 & 可提现金额 ====================
            calculateAccountBalance(storeId, result);

            // ==================== 2. 今日收益 ====================
            calculateTodayIncome(storeId, result);

            // ==================== 3. 未入账统计（近3天） ====================
            calculateNotPaidIncome(storeId, result);

            // ==================== 4. 已入账统计（4-27天） ====================
            calculatePaidIncome(storeId, result);

            log.info("IncomeManageServiceImpl.getIncomeSummary - 查询完成: result={}", result);

        } catch (Exception e) {
            log.error("IncomeManageServiceImpl.getIncomeSummary - 查询失败: storeId={}, error={}", 
                    storeId, e.getMessage(), e);
            throw new RuntimeException("查询收入汇总失败：" + e.getMessage(), e);
        }

        return result;
    }

    /**
     * 计算账户余额和可提现金额
     * 
     * 业务逻辑：
     * 1. 账户余额 = 用户账户中的总余额（store_user.money）
     * 2. 可提现金额 = 4-27天内未绑定提现的收入 - 待审核/已通过的提现金额
     * 
     * @param storeId 门店ID
     * @param result  结果集
     */
    private void calculateAccountBalance(Integer storeId, Map<String, Object> result) {
        log.info("IncomeManageServiceImpl.calculateAccountBalance - 开始计算账户余额和可提现金额");

        // ---------- 1.1 查询账户总余额 ----------
        LambdaQueryWrapper<StoreUser> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.eq(StoreUser::getStoreId, storeId);
        StoreUser storeUser = storeUserMapper.selectOne(userWrapper);

        if (storeUser == null) {
            log.warn("IncomeManageServiceImpl.calculateAccountBalance - 未找到店铺用户: storeId={}", storeId);
            result.put("balance", "0.00");
            result.put("cashOutMoney", "0.00");
            return;
        }

        // 账户总余额（分转元）
        String balance = new BigDecimal(storeUser.getMoney())
                .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                .toString();
        result.put("balance", balance);
        log.info("IncomeManageServiceImpl.calculateAccountBalance - 账户余额: {}元", balance);

        // ---------- 1.2 查询4-27天内未绑定提现的收入 ----------
        Date now = new Date();
        Date startDate = DateUtils.calcDays(now, -27);  // 27天前
        Date endDate = DateUtils.calcDays(now, -4);      // 4天前

        LambdaQueryWrapper<StoreIncomeDetailsRecord> incomeWrapper = new LambdaQueryWrapper<>();
        incomeWrapper.between(StoreIncomeDetailsRecord::getCreatedTime, startDate, endDate)
                .isNull(StoreIncomeDetailsRecord::getCashOutId)  // 未绑定提现记录
                .eq(StoreIncomeDetailsRecord::getStoreId, storeId);

        List<StoreIncomeDetailsRecord> incomeList = this.list(incomeWrapper);
        int availableIncome = incomeList.stream()
                .mapToInt(StoreIncomeDetailsRecord::getMoney)
                .sum();

        log.info("IncomeManageServiceImpl.calculateAccountBalance - 4-27天内可提现收入: {}分, 记录数: {}", 
                availableIncome, incomeList.size());

        // ---------- 1.3 查询待审核和已通过的提现金额 ----------
        QueryWrapper<StoreCashOutRecord> cashOutWrapper = new QueryWrapper<>();
        cashOutWrapper.eq("store_id", storeId)
                .in("payment_status", "1", "3")  // 1-待审核, 3-已通过
                .eq("delete_flag", "0");

        List<StoreCashOutRecord> cashOutRecords = storeCashOutRecordMapper.selectList(cashOutWrapper);
        int pendingCashOut = cashOutRecords.stream()
                .collect(Collectors.summingInt(StoreCashOutRecord::getMoney));

        log.info("IncomeManageServiceImpl.calculateAccountBalance - 待审核/已通过提现: {}分, 记录数: {}", 
                pendingCashOut, cashOutRecords.size());

        // ---------- 1.4 计算可提现金额 ----------
        // 可提现金额 = 可提现收入 - 审核中的提现
        int cashOutMoney = availableIncome - pendingCashOut;
        String cashOutMoneyStr = new BigDecimal(Math.max(cashOutMoney, 0))  // 确保不为负数
                .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                .toString();
        result.put("cashOutMoney", cashOutMoneyStr);

        log.info("IncomeManageServiceImpl.calculateAccountBalance - 可提现金额: {}元", cashOutMoneyStr);
    }

    /**
     * 计算今日收益
     * 
     * 业务逻辑：
     * 统计当天00:00:00 ~ 23:59:59所有收入的总和
     * 
     * @param storeId 门店ID
     * @param result  结果集
     */
    private void calculateTodayIncome(Integer storeId, Map<String, Object> result) {
        log.info("IncomeManageServiceImpl.calculateTodayIncome - 开始计算今日收益");

        // ---------- 2.1 获取今天的日期范围 ----------
        Date now = new Date();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String today = df.format(now);
        String startTime = today + " 00:00:00";
        String endTime = today + " 23:59:59";

        // ---------- 2.2 查询今天的收入记录 ----------
        LambdaQueryWrapper<StoreIncomeDetailsRecord> todayWrapper = new LambdaQueryWrapper<>();
        todayWrapper.between(StoreIncomeDetailsRecord::getCreatedTime, startTime, endTime)
                .eq(StoreIncomeDetailsRecord::getStoreId, storeId);

        List<StoreIncomeDetailsRecord> todayList = this.list(todayWrapper);

        // ---------- 2.3 汇总今日收益 ----------
        int todayIncome = todayList.stream()
                .mapToInt(StoreIncomeDetailsRecord::getMoney)
                .sum();

        String todayIncomeStr = new BigDecimal(todayIncome)
                .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                .toString();
        result.put("todayIncome", todayIncomeStr);

        log.info("IncomeManageServiceImpl.calculateTodayIncome - 今日收益: {}元, 记录数: {}", 
                todayIncomeStr, todayList.size());
    }

    /**
     * 计算未入账统计（近3天）
     * 
     * 业务逻辑：
     * 1. 时间范围：当前时间 - 3天 ~ 当前时间
     * 2. 条件：未绑定提现记录（cash_out_id IS NULL）
     * 3. 说明：这部分收入还未到提现账期，不能提现
     * 
     * @param storeId 门店ID
     * @param result  结果集
     */
    private void calculateNotPaidIncome(Integer storeId, Map<String, Object> result) {
        log.info("IncomeManageServiceImpl.calculateNotPaidIncome - 开始计算未入账统计");

        Date now = new Date();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");

        // ---------- 3.1 计算时间范围 ----------
        Date notPaidStartDate = DateUtils.calcDays(now, -3);  // 3天前
        String notPaidDateRange = df.format(notPaidStartDate) + " ~ " + df.format(now);
        result.put("notPaidDateRange", notPaidDateRange);

        log.info("IncomeManageServiceImpl.calculateNotPaidIncome - 未入账时间范围: {}", notPaidDateRange);

        // ---------- 3.2 查询未入账收入（近3天，未绑定提现） ----------
        QueryWrapper<StoreIncomeDetailsRecord> notPaidWrapper = new QueryWrapper<>();
        notPaidWrapper.isNull("sidr.cash_out_id")  // 未绑定提现记录
                .gt("sidr.created_time", notPaidStartDate)  // 大于3天前
                .eq("sidr.store_id", storeId);

        List<StoreIncomeDetailsRecordVo> notPaidList = storeIncomeDetailsRecordMapper.selectRecordList(notPaidWrapper);

        // ---------- 3.3 汇总未入账金额和数量 ----------
        int notPaidMoney = notPaidList.stream()
                .mapToInt(StoreIncomeDetailsRecord::getMoney)
                .sum();

        String notPaidMoneyStr = new BigDecimal(notPaidMoney)
                .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                .toString();

        result.put("notPaidMoney", notPaidMoneyStr);
        result.put("notPaidCount", notPaidList.size());

        log.info("IncomeManageServiceImpl.calculateNotPaidIncome - 未入账: {}元, 记录数: {}", 
                notPaidMoneyStr, notPaidList.size());
    }

    /**
     * 计算已入账统计（4-27天）
     * 
     * 业务逻辑：
     * 1. 时间范围：当前时间 - 27天 ~ 当前时间 - 4天
     * 2. 说明：这部分收入已到提现账期，可以申请提现
     * 
     * @param storeId 门店ID
     * @param result  结果集
     */
    private void calculatePaidIncome(Integer storeId, Map<String, Object> result) {
        log.info("IncomeManageServiceImpl.calculatePaidIncome - 开始计算已入账统计");

        Date now = new Date();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");

        // ---------- 4.1 计算时间范围 ----------
        Date paidStartDate = DateUtils.calcDays(now, -27);  // 27天前
        Date paidEndDate = DateUtils.calcDays(now, -4);      // 4天前
        String paidDateRange = df.format(paidStartDate) + " ~ " + df.format(paidEndDate);
        result.put("paidDateRange", paidDateRange);

        log.info("IncomeManageServiceImpl.calculatePaidIncome - 已入账时间范围: {}", paidDateRange);

        // ---------- 4.2 查询已入账收入（4-27天前） ----------
        QueryWrapper<StoreIncomeDetailsRecord> paidWrapper = new QueryWrapper<>();
        paidWrapper.between("sidr.created_time", paidStartDate, paidEndDate)
                .eq("sidr.store_id", storeId);

        List<StoreIncomeDetailsRecordVo> paidList = storeIncomeDetailsRecordMapper.selectRecordList(paidWrapper);

        // ---------- 4.3 汇总已入账金额和数量 ----------
        int paidMoney = paidList.stream()
                .mapToInt(StoreIncomeDetailsRecord::getMoney)
                .sum();

        String paidMoneyStr = new BigDecimal(paidMoney)
                .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)
                .toString();

        result.put("paidMoney", paidMoneyStr);
        result.put("paidCount", paidList.size());

        log.info("IncomeManageServiceImpl.calculatePaidIncome - 已入账: {}元, 记录数: {}", 
                paidMoneyStr, paidList.size());
    }
}

