package com.gxwebsoft.glt.service.impl;

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 lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

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

    @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;
            }

            long userTicketIdLong = rel.getUserTicketId();
            if (userTicketIdLong > Integer.MAX_VALUE || userTicketIdLong < 1) {
                markFailed(rel.getId(), now, "userTicketId超范围");
                continue;
            }
            Integer userTicketId = (int) userTicketIdLong;

            // 先释放冻结数量（条件更新，确保 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);
    }
}
