package com.gxwebsoft.glt.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gxwebsoft.glt.entity.GltUserTicket;
import com.gxwebsoft.glt.entity.GltUserTicketLog;
import com.gxwebsoft.glt.entity.GltUserTicketRelease;
import com.gxwebsoft.glt.mapper.GltUserTicketLogMapper;
import com.gxwebsoft.glt.mapper.GltUserTicketMapper;
import com.gxwebsoft.glt.mapper.GltUserTicketReleaseMapper;
import com.gxwebsoft.glt.service.GltUserTicketAutoReleaseService;
import com.gxwebsoft.glt.service.GltUserTicketLogService;
import com.gxwebsoft.glt.service.GltUserTicketReleaseService;
import com.gxwebsoft.glt.service.GltUserTicketService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 冻结水票自动释放实现：
 * - 读取到期且待释放的 release 记录（FOR UPDATE 加锁，防止重复处理）
 * - 释放成功：更新 user_ticket 数量 & 将 release.status 置为 1，并写入流水
 * - 释放失败：将 release.status 置为 2（数据异常/冻结不足等）
 */
@Slf4j
@Service
@AllArgsConstructor
public class GltUserTicketAutoReleaseServiceImpl implements GltUserTicketAutoReleaseService {

    /**
     * 变更类型：冻结释放
     * <p>
     * 现有发放类型为 10（见 GltTicketIssueService.CHANGE_TYPE_ISSUE），这里取 11。
     */
    private static final int CHANGE_TYPE_RELEASE = 11;

    /** release.status：待释放 */
    private static final int RELEASE_STATUS_PENDING = 0;
    /** release.status：已释放 */
    private static final int RELEASE_STATUS_DONE = 1;
    /** release.status：释放失败（数据异常/冻结不足等，需人工处理） */
    private static final int RELEASE_STATUS_FAILED = 2;

    private final GltUserTicketReleaseMapper releaseMapper;
    private final GltUserTicketMapper userTicketMapper;
    private final GltUserTicketLogMapper userTicketLogMapper;

    private GltUserTicketReleaseService gltUserTicketReleaseService;

    private GltUserTicketService gltUserTicketService;

    private GltUserTicketLogService gltUserTicketLogService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public int releaseDue(LocalDateTime now, int batchSize) {
        int limit = Math.max(batchSize, 1);
        List<GltUserTicketRelease> dueList = releaseMapper.selectDueForUpdate(now, limit);
        if (dueList == null || dueList.isEmpty()) {
            return 0;
        }

        int success = 0;
        for (GltUserTicketRelease rel : dueList) {
            if (rel.getId() == null || rel.getStatus() == null || rel.getStatus() != RELEASE_STATUS_PENDING) {
                continue;
            }

            Integer qtyObj = rel.getReleaseQty();
            if (qtyObj == null || qtyObj <= 0) {
                markFailed(rel.getId(), now, "releaseQty无效");
                continue;
            }
            int qty = qtyObj;

            if (rel.getUserTicketId() == null || rel.getUserId() == null || rel.getTenantId() == null) {
                markFailed(rel.getId(), now, "缺少userTicketId/userId/tenantId");
                continue;
            }

            Integer userTicketId = rel.getUserTicketId();

            // 先释放冻结数量（条件更新，确保 frozen_qty >= qty）
            int updated = userTicketMapper.releaseFrozenQty(
                userTicketId,
                rel.getUserId(),
                rel.getTenantId(),
                qty,
                now
            );
            if (updated <= 0) {
                markFailed(rel.getId(), now, "冻结不足/水票不存在/状态不符");
                continue;
            }

            // 写入流水（可用 +qty，冻结 -qty）
            GltUserTicket ticket = userTicketMapper.selectById(userTicketId);
            GltUserTicketLog logRow = new GltUserTicketLog();
            logRow.setUserTicketId(userTicketId);
            logRow.setChangeType(CHANGE_TYPE_RELEASE);
            logRow.setChangeAvailable(qty);
            logRow.setChangeFrozen(-qty);
            logRow.setChangeUsed(0);
            if (ticket != null) {
                logRow.setAvailableAfter(ticket.getAvailableQty());
                logRow.setFrozenAfter(ticket.getFrozenQty());
                logRow.setUsedAfter(ticket.getUsedQty());
            }
            logRow.setOrderId(null);
            logRow.setOrderNo(null);
            logRow.setUserId(rel.getUserId());
            logRow.setSortNumber(0);
            logRow.setComments("冻结水票到期释放");
            logRow.setStatus(0);
            logRow.setDeleted(0);
            logRow.setTenantId(rel.getTenantId());
            logRow.setCreateTime(now);
            logRow.setUpdateTime(now);
            userTicketLogMapper.insert(logRow);

            // 标记释放记录已完成（放在最后：若流水失败则回滚）
            releaseMapper.updateStatus(rel.getId(), RELEASE_STATUS_DONE, now);

            success++;
        }

        return success;
    }

    private void markFailed(Long releaseId, LocalDateTime now, String reason) {
        releaseMapper.updateStatus(releaseId, RELEASE_STATUS_FAILED, now);
        log.warn("冻结水票释放标记失败 - releaseId={}, reason={}", releaseId, reason);
    }

    @Transactional
    public void releaseTask() {
        LocalDateTime now = LocalDateTime.now();
        log.info("***执行水票释放任务***-执行时间：{}", now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        long start = System.currentTimeMillis();
        List<GltUserTicketRelease> releaseList = releaseMapper.getThisMonthReleaseList(1000);
        if(CollectionUtils.isEmpty(releaseList)){
            log.info("***本轮任务无待释放水票数据***");
            return;
        }

        //查询用户水票信息
        List<Integer> userTickIdList = releaseList.stream().map(GltUserTicketRelease::getUserTicketId).distinct().collect(Collectors.toList());
        LambdaQueryWrapper<GltUserTicket> userTicketLambdaQueryWrapper = new LambdaQueryWrapper<GltUserTicket>().select(GltUserTicket::getId, GltUserTicket::getAvailableQty,
                        GltUserTicket::getFrozenQty, GltUserTicket::getReleasedQty).in(GltUserTicket::getId, userTickIdList);
        List<GltUserTicket> userTicketList = userTicketMapper.selectList(userTicketLambdaQueryWrapper);

        //创建修改用户水票集合、水票释放计划记录集合
        List<GltUserTicket> updateUserTicketList = new ArrayList<>();
        List<GltUserTicketLog> userTicketLogList = new ArrayList<>();

        //遍历水票释放数据执行释放任务
        releaseList.forEach(release ->{
            //1.缺少水票ID、用户ID、租户ID记录错误记录
            if(release.getUserTicketId() == null || release.getUserId() == null || release.getTenantId() == null){
                release.setRemark("缺少userTicketId/userId/tenantId");
                release.setStatus(2);
                release.setUpdateTime(now);
            }

            GltUserTicket userTicket = userTicketList.stream().filter(gltUserTicket -> release.getUserTicketId().equals(gltUserTicket.getId())).findFirst().orElse(null);
            if(userTicket != null){
                Integer releaseQty = release.getReleaseQty();
                if(userTicket.getFrozenQty() > releaseQty){
                    //更改用户水票可用数量、冻结数量、已释放数量
                    userTicket.setAvailableQty(userTicket.getAvailableQty() + releaseQty);
                    userTicket.setFrozenQty(userTicket.getFrozenQty() - releaseQty);
                    userTicket.setReleasedQty(userTicket.getReleasedQty() + releaseQty);
                    userTicket.setUpdateTime(now);
                    updateUserTicketList.add(userTicket);

                    //记录水票释放计划为成功释放状态
                    release.setStatus(1);
                    release.setRemark("success");
                    release.setUpdateTime(now);

                    //生成水票释放记录
                    GltUserTicketLog ticketLog = new GltUserTicketLog();
                    ticketLog.setUserTicketId(release.getUserTicketId());
                    ticketLog.setChangeType(CHANGE_TYPE_RELEASE);
                    ticketLog.setChangeAvailable(releaseQty);
                    ticketLog.setChangeFrozen(-releaseQty);
                    ticketLog.setChangeUsed(0);
                    ticketLog.setAvailableAfter(userTicket.getAvailableQty());
                    ticketLog.setFrozenAfter(userTicket.getFrozenQty());
                    ticketLog.setUsedAfter(userTicket.getUsedQty());
                    ticketLog.setOrderId(Integer.valueOf(String.valueOf(release.getId())));
                    ticketLog.setUserId(release.getUserId());
                    ticketLog.setComments("冻结水票到期释放");
                    ticketLog.setTenantId(release.getTenantId());
                    ticketLog.setCreateTime(now);
                    ticketLog.setUpdateTime(now);
                    userTicketLogList.add(ticketLog);
                }else {
                    release.setRemark("释放数量大于冻结数量,释放:" + releaseQty + "，冻结:" + userTicket.getFrozenQty());
                    release.setStatus(2);
                    release.setUpdateTime(LocalDateTime.now());
                }
            }else {
                release.setRemark("查询不到水票数据");
                release.setStatus(2);
                release.setUpdateTime(LocalDateTime.now());
            }
        });

        if(CollectionUtils.isNotEmpty(releaseList)){
            gltUserTicketReleaseService.updateBatchById(releaseList);
        }

        if(CollectionUtils.isNotEmpty(updateUserTicketList)){
            gltUserTicketService.updateBatchById(updateUserTicketList);
        }

        if(CollectionUtils.isNotEmpty(userTicketLogList)){
            gltUserTicketLogService.saveBatch(userTicketLogList);
        }

        long end = System.currentTimeMillis();
        long costMs = end - start;
        log.info("***执行水票释放任务完成*** 执行耗时：{} ms", costMs);
    }
}
