package com.fs.course.service.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.fs.common.core.domain.R;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.StringUtils;
import com.fs.company.domain.Company;
import com.fs.company.domain.CompanyMoneyLogs;
import com.fs.company.mapper.CompanyMapper;
import com.fs.company.mapper.CompanyMoneyLogsMapper;
import com.fs.course.config.CourseConfig;
import com.fs.course.config.RedPacketConfig;
import com.fs.course.domain.FsCourseWatchLog;
import com.fs.course.mapper.FsCourseWatchLogMapper;
import com.fs.course.param.FsCourseRedPacketLogParam;
import com.fs.course.vo.FsCourseRedPacketLogListPVO;
import com.fs.his.domain.FsUser;
import com.fs.his.mapper.FsUserMapper;
import com.fs.his.param.WxSendRedPacketParam;
import com.fs.his.service.IFsStorePaymentService;
import com.fs.system.service.ISysConfigService;
import com.github.binarywang.wxpay.bean.transfer.TransferBillsGetResult;
import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.TransferService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fs.course.mapper.FsCourseRedPacketLogMapper;
import com.fs.course.domain.FsCourseRedPacketLog;
import com.fs.course.service.IFsCourseRedPacketLogService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 短链课程看课记录Service业务层处理
 *
 * @author fs
 * @date 2024-10-24
 */
@Service
public class FsCourseRedPacketLogServiceImpl implements IFsCourseRedPacketLogService
{
    private static final Logger logger = LoggerFactory.getLogger(FsCourseRedPacketLogServiceImpl.class);
    @Autowired
    private FsCourseRedPacketLogMapper fsCourseRedPacketLogMapper;
    @Autowired
    private CompanyMapper companyMapper;

    @Autowired
    private ISysConfigService configService;
    /**
     * 查询短链课程看课记录
     *
     * @param logId 短链课程看课记录主键
     * @return 短链课程看课记录
     */
    @Override
    public FsCourseRedPacketLog selectFsCourseRedPacketLogByLogId(Long logId)
    {
        return fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogByLogId(logId);
    }

    /**
     * 查询短链课程看课记录列表
     *
     * @param fsCourseRedPacketLog 短链课程看课记录
     * @return 短链课程看课记录
     */
    @Override
    public List<FsCourseRedPacketLog> selectFsCourseRedPacketLogList(FsCourseRedPacketLog fsCourseRedPacketLog)
    {
        return fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogList(fsCourseRedPacketLog);
    }

    /**
     * 新增短链课程看课记录
     *
     * @param fsCourseRedPacketLog 短链课程看课记录
     * @return 结果
     */
    @Override
    public int insertFsCourseRedPacketLog(FsCourseRedPacketLog fsCourseRedPacketLog)
    {
        fsCourseRedPacketLog.setCreateTime(DateUtils.getNowDate());
        return fsCourseRedPacketLogMapper.insertFsCourseRedPacketLog(fsCourseRedPacketLog);
    }

    /**
     * 修改短链课程看课记录
     *
     * @param fsCourseRedPacketLog 短链课程看课记录
     * @return 结果
     */
    @Override
    public int updateFsCourseRedPacketLog(FsCourseRedPacketLog fsCourseRedPacketLog)
    {
        return fsCourseRedPacketLogMapper.updateFsCourseRedPacketLog(fsCourseRedPacketLog);
    }

    /**
     * 批量删除短链课程看课记录
     *
     * @param logIds 需要删除的短链课程看课记录主键
     * @return 结果
     */
    @Override
    public int deleteFsCourseRedPacketLogByLogIds(Long[] logIds)
    {
        return fsCourseRedPacketLogMapper.deleteFsCourseRedPacketLogByLogIds(logIds);
    }

    /**
     * 删除短链课程看课记录信息
     *
     * @param logId 短链课程看课记录主键
     * @return 结果
     */
    @Override
    public int deleteFsCourseRedPacketLogByLogId(Long logId)
    {
        return fsCourseRedPacketLogMapper.deleteFsCourseRedPacketLogByLogId(logId);
    }

//    @Override
//    public R syncRedPacket(String outBatchNo) {
//        FsCourseRedPacketLog log = fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogByBatchNo(outBatchNo);
//        if (log!=null){
//            log.setStatus(1);
//            log.setUpdateTime(new Date());
//            fsCourseRedPacketLogMapper.updateFsCourseRedPacketLog(log);
//            return R.ok();
//        }
//        return R.error("批次不存在");
//    }

    @Override
    public R syncRedPacket(String outBatchNo, String batchId) {
        FsCourseRedPacketLog log = fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogByBatchNo(outBatchNo);
        if (log!=null){
            log.setStatus(1);
            log.setUpdateTime(new Date());
            log.setBatchId(batchId);
            fsCourseRedPacketLogMapper.updateFsCourseRedPacketLog(log);
            return R.ok();
        }
        return R.error("批次不存在");
    }

    @Override
    public List<FsCourseRedPacketLogListPVO> selectFsCourseRedPacketLogListVO(FsCourseRedPacketLogParam fsCourseRedPacketLog) {
        return fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogListVO(fsCourseRedPacketLog);
    }

    @Override
    public List<FsCourseRedPacketLogListPVO> selectFsCourseRedPacketLogListVONew(FsCourseRedPacketLogParam fsCourseRedPacketLog) {
        return fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogListVONew(fsCourseRedPacketLog);
    }

    /**
     * 查询红包金额数
     * @param companyUserId 销售ID
     * @return amount
     */
    @Override
    public BigDecimal getSumByCompanyUserIdId(Long companyUserId) {
        return fsCourseRedPacketLogMapper.getSumByCompanyUserIdId(companyUserId);
    }

    @Override
    public int getCountByCompanyUserIdId(Long companyUserId) {
        return fsCourseRedPacketLogMapper.getCountByCompanyUserIdId(companyUserId);
    }

    /**
     * 查询新用户红包金额总和
     * @param companyUserId 销售ID
     * @return amount
     */
    @Override
    public BigDecimal getNewVipRedPackAmountByCompanyUserIdId(Long companyUserId) {
        return fsCourseRedPacketLogMapper.getNewVipRedPackAmountByCompanyUserIdId(companyUserId);
    }
    @Autowired
    private IFsStorePaymentService paymentService;
    @Autowired
    private FsUserMapper fsUserMapper;
    @Autowired
    private FsCourseWatchLogMapper courseWatchLogMapper;
    @Autowired
    private CompanyMoneyLogsMapper moneyLogsMapper;
    @Override
    @Transactional
    public R retryCourseRedPacketLog(Long[] logIds) {
        int suc=0;
        int err=0;
        for (int i = 0; i < logIds.length; i++) {
            Long id = logIds[i];
            FsCourseRedPacketLog param = fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogByLogId(id);


            if (param!=null&&param.getStatus()==2){
                Company company = companyMapper.selectCompanyByIdForUpdate(param.getCompanyId());
                BigDecimal amount = param.getAmount();
                BigDecimal money = company.getMoney();
                BigDecimal subtract = money.subtract(amount);
                if (subtract.compareTo(BigDecimal.ZERO)<0){
                    err++;
                }
                WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
                FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
                packetParam.setOpenId(user.getMaOpenId());
                packetParam.setOpenId(user.getCourseMaOpenId());
                packetParam.setAmount(param.getAmount());
                packetParam.setSource(2);
                packetParam.setRedPacketMode(1);
                packetParam.setCompanyId(param.getCompanyId());
                packetParam.setUser(user);
                R sendRedPacket = paymentService.sendRedPacket(packetParam);
                if (sendRedPacket.get("code").equals(200)) {
                    FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
                    TransferBillsResult transferBillsResult;
                    if (sendRedPacket.get("isNew").equals(1)){
                        transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
                        redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
                        redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
                    }else {
                        redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
                    }
                    FsCourseWatchLog log = new FsCourseWatchLog();
                    log.setLogId(param.getWatchLogId());
                    log.setRewardType(1);
                    courseWatchLogMapper.updateFsCourseWatchLog(log);
                    // 添加红包记录
                    redPacketLog.setLogId(param.getLogId());
                    redPacketLog.setStatus(0);
                    fsCourseRedPacketLogMapper.updateFsCourseRedPacketLog(redPacketLog);
                    // 更新观看记录的奖励类型
                    company.setMoney(subtract);
                    companyMapper.updateCompany(company);
                    CompanyMoneyLogs logs=new CompanyMoneyLogs();
                    logs.setCompanyId(company.getCompanyId());
                    logs.setRemark("扣除红包金额");
                    logs.setMoney(amount.multiply(new BigDecimal(-1)));
                    logs.setLogsType(15);
                    logs.setBalance(company.getMoney());
                    logs.setCreateTime(new Date());
                    moneyLogsMapper.insertCompanyMoneyLogs(logs);
                    suc++;
                }else {
                    err++;
                }
            }else {
                err++;
            }

        }
        return R.ok("成功："+suc+" 失败："+err);
    }

    @Override
    public void sendRedPacketBf() {
        try {
            logger.info("【红包发放】开始执行红包发放任务");

            // 初始化查询对象
            FsCourseRedPacketLog query = new FsCourseRedPacketLog();
            query.setStatus(2); // 状态2表示待处理红包

            // 获取红包配置
            String json = configService.selectConfigByKey("course.config");
            CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
            logger.info("【红包发放】当前红包发放模式：{}", config.getRedPacketMode());

            // 获取待处理红包列表
            List<FsCourseRedPacketLog> pendingPackets = fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogList(query);
            if (pendingPackets == null || pendingPackets.isEmpty()) {
                logger.info("【红包发放】没有待处理的红包记录");
                return;
            }

            logger.info("【红包发放】共发现{}条待处理红包记录", pendingPackets.size());

            // 处理每条红包记录
            for (FsCourseRedPacketLog redPacket : pendingPackets) {
                try {
                    logger.info("【红包处理】开始处理红包记录ID：{}，用户ID：{}，金额：{}元",
                            redPacket.getLogId(), redPacket.getUserId(), redPacket.getAmount());

                    processRedPacket(redPacket, config);
                } catch (Exception e) {
                    logger.error("【红包处理】处理红包记录ID：{}时发生异常", redPacket.getLogId(), e);
                    // 即使一条记录失败也继续处理下一条
                }
            }

            logger.info("【红包发放】红包发放任务执行完成");
        } catch (Exception e) {
            logger.error("【红包发放】红包发放任务执行过程中发生未预期异常", e);
        }
    }

    @Override
    public void queryRedPacketResult(String startTime, String endTime) {
        LocalDateTime tenMinutesAgo;
        LocalDateTime twentyMinutesAgo;
        if(StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime)){
            // 获取前十分钟时间 和 前二十分钟时间
            tenMinutesAgo = LocalDateTime.now().minusMinutes(10);
            twentyMinutesAgo = tenMinutesAgo.minusMinutes(10);
        }else {
            tenMinutesAgo = LocalDateTime.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            twentyMinutesAgo = LocalDateTime.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        }

        // 获取前分钟时间
        Map<String, Object> params = new HashMap<>();
        params.put("startTime", twentyMinutesAgo);
        params.put("endTime",tenMinutesAgo);
        // 获取前十分钟红包记录状态为发送中的记录
        List<FsCourseRedPacketLog> redPacketLogs = fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogListBySending(params);
        if(redPacketLogs!=null && !redPacketLogs.isEmpty()){
            String json = configService.selectConfigByKey("redPacket.config");
            RedPacketConfig config = JSONUtil.toBean(json, RedPacketConfig.class);
            //创建微信订单
            WxPayConfig payConfig = new WxPayConfig();
            BeanUtils.copyProperties(config,payConfig);
            WxPayService wxPayService = new WxPayServiceImpl();
            wxPayService.setConfig(payConfig);
            TransferService transferService=wxPayService.getTransferService();
            for(FsCourseRedPacketLog redPacket:redPacketLogs){
                // 获取批次号
                // redPacket.getResult() {"msg":"发送红包成功","code":200,"mchId":"1703311381","data":{"createTime":"2025-06-26T18:00:48+08:00","outBillNo":"fsCourse1938175604536901632","packageInfo":"ABBQO+oYAAABAAAAAABRil0NtaWxBS5JURpdaBAAAADnGpepZahT9IkJjn90+1qgtzWOmCRNZJfek1QMbZ9ktG8idrj37//0xOSt0T67XUFE+PGeXO8qZoNKHYlU3RicIHExIjZr342xE+QjrpjaHIFYoPg=","state":"WAIT_USER_CONFIRM","transferBillNo":"1330007292140242506260028904279364"},"isNew":1}
                // 获取 transferBillNo
                String batchId;
                try {
                    batchId = StringUtils.isNotEmpty(redPacket.getBatchId())?redPacket.getBatchId():JSON.parseObject(redPacket.getResult()).getJSONObject("data").getString("transferBillNo");
                }catch (Exception e){
                    logger.error("【红包处理】获取批次号失败,FsCourseRedPacketLog-log_id:{}",redPacket.getLogId());
                    continue;
                }

                try {
                    TransferBillsGetResult queryRedPacketResult = transferService.getBillsByTransferBillNo(batchId);
                    logger.info("FsCourseRedPacketLog-log_id:{},【红包处理】查询批次结果：{}",redPacket.getLogId(),queryRedPacketResult);
                    if(queryRedPacketResult!=null && "SUCCESS".equals(queryRedPacketResult.getState())){
                        FsCourseRedPacketLog fsCourseRedPacketLog=new FsCourseRedPacketLog();
                        fsCourseRedPacketLog.setLogId(redPacket.getLogId());
                        fsCourseRedPacketLog.setStatus(1); // 已发送
                        fsCourseRedPacketLog.setUpdateTime(new Date());
                        updateFsCourseRedPacketLog(fsCourseRedPacketLog);
                    }
                } catch (WxPayException e) {
                    logger.error(e.getMessage());
                }
            }
        }
    }


    private void processRedPacket(FsCourseRedPacketLog redPacket, CourseConfig config) {
        // 获取用户信息
        FsUser user = fsUserMapper.selectFsUserByUserId(redPacket.getUserId());
        if (user == null || user.getMpOpenId() == null) {
            logger.error("【红包处理】错误：未找到用户ID：{}或用户缺少openId", redPacket.getUserId());
            return;
        }

        logger.info("【红包处理】准备为用户{}发放红包，openId：{}", user.getUserId(), user.getMpOpenId());

        // 准备红包参数
        WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
        packetParam.setOpenId(user.getMpOpenId());
        packetParam.setAmount(redPacket.getAmount());
        packetParam.setSource(2);
        packetParam.setAppId(redPacket.getAppId());
        packetParam.setRedPacketMode(config.getRedPacketMode());
        packetParam.setCompanyId(redPacket.getCompanyId());

        // 处理企业资金（使用悲观锁）
        Company company = companyMapper.selectCompanyByIdForUpdate(redPacket.getCompanyId());
        if (company == null) {
            logger.error("【红包处理】错误：未找到企业ID：{}", redPacket.getCompanyId());
            return;
        }

        BigDecimal remainingBalance = company.getMoney().subtract(redPacket.getAmount());
        if (remainingBalance.compareTo(BigDecimal.ZERO) < 0) {
            logger.warn("【红包处理】企业{}余额不足（当前余额：{}元，需要扣除：{}元）",
                    company.getCompanyId(), company.getMoney(), redPacket.getAmount());
            return;
        }

        logger.info("【红包处理】企业{}当前余额：{}元，发放后余额：{}元",
                company.getCompanyId(), company.getMoney(), remainingBalance);

        // 发送红包
        R sendRedPacketResult = paymentService.sendRedPacket(packetParam);
        if (sendRedPacketResult == null) {
            logger.error("【红包处理】红包接口返回空结果");
            return;
        }

        if (!sendRedPacketResult.get("code").equals(200)) {
            logger.error("【红包处理】红包发放失败，错误码：{}，错误信息：{}",
                    sendRedPacketResult.get("code"), sendRedPacketResult.get("msg"));
            return;
        }

        // 处理成功结果
        logger.info("【红包处理】红包发放成功");

        // 更新红包记录
        if (sendRedPacketResult.get("isNew").equals(1)) {
            TransferBillsResult transferBillsResult = (TransferBillsResult)sendRedPacketResult.get("data");
            redPacket.setResult(JSON.toJSONString(sendRedPacketResult));
            redPacket.setOutBatchNo(transferBillsResult.getOutBillNo());
            logger.info("【红包处理】新批次红包，批次号：{}", transferBillsResult.getOutBillNo());
        } else {
            redPacket.setOutBatchNo(sendRedPacketResult.get("orderCode").toString());
            logger.info("【红包处理】已有批次红包，订单号：{}", redPacket.getOutBatchNo());
        }

        fsCourseRedPacketLogMapper.updateFsCourseRedPacketLog(redPacket);

        // 更新观看记录
        FsCourseWatchLog watchLog = courseWatchLogMapper.selectFsCourseWatchLogByLogId(redPacket.getLogId());
        if (watchLog != null) {
            watchLog.setRewardType(config.getRewardType());
            courseWatchLogMapper.updateFsCourseWatchLog(watchLog);
            logger.info("【红包处理】更新观看记录{}的奖励类型为{}", watchLog.getLogId(), config.getRewardType());
        }

        // 更新企业余额
        company.setMoney(remainingBalance);
        companyMapper.updateCompany(company);

        // 记录资金流水
        CompanyMoneyLogs moneyLog = new CompanyMoneyLogs();
        moneyLog.setCompanyId(company.getCompanyId());
        moneyLog.setRemark("扣除红包金额");
        moneyLog.setMoney(redPacket.getAmount().multiply(new BigDecimal(-1)));
        moneyLog.setLogsType(15);
        moneyLog.setBalance(company.getMoney());
        moneyLog.setCreateTime(new Date());
        moneyLogsMapper.insertCompanyMoneyLogs(moneyLog);

        logger.info("【红包处理】企业资金流水记录成功，企业ID：{}，变动金额：{}元",
                company.getCompanyId(), moneyLog.getMoney());
    }

}
