package com.red.circle.other.app.scheduler;

import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.component.redis.annotation.TaskCacheLock;
import com.red.circle.other.domain.gateway.RoomRedPacketGateway;
import com.red.circle.other.domain.redpacket.RoomRedPacket;
import com.red.circle.other.domain.redpacket.RoomRedPacketRefundStatus;
import com.red.circle.other.domain.redpacket.RoomRedPacketSourceType;
import com.red.circle.other.domain.redpacket.RoomRedPacketStatus;
import com.red.circle.other.infra.database.cache.service.other.RoomRedPacketCacheService;
import com.red.circle.tool.core.tuple.PennyAmount;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 房间红包过期退款定时任务
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RoomRedPacketExpireTask {

    private final RoomRedPacketGateway roomRedPacketGateway;
    private final RoomRedPacketCacheService roomRedPacketCacheService;
    private final WalletGoldClient walletGoldClient;

    /**
     * 每30秒执行一次
     */
    @Scheduled(cron = "0/30 * * * * ?")
    @TaskCacheLock(key = "ROOM_RED_PACKET_TASK", expireSecond = 20)
    public void refundExpiredPackets() {
        try {
            LocalDateTime now = LocalDateTime.now();
            
            // 1. 查询过期且未退款的红包
            List<RoomRedPacket> expiredPackets = roomRedPacketGateway.findExpiredAndNotRefunded(now);
            
            if (expiredPackets.isEmpty()) {
                return;
            }
            
            log.info("开始处理过期红包退款 数量={}", expiredPackets.size());
            
            int successCount = 0;
            int failCount = 0;
            
            for (RoomRedPacket packet : expiredPackets) {
                try {
                    refundSinglePacket(packet);
                    successCount++;
                } catch (Exception e) {
                    log.error("红包退款失败 packetId={}", packet.getPacketId(), e);
                    failCount++;
                }
            }
            
            log.info("过期红包退款定时任务执行完成 总数={} 成功={} 失败={}", 
                expiredPackets.size(), successCount, failCount);
            
        } catch (Exception e) {
            log.error("过期红包退款定时任务执行失败", e);
        }
    }

    /**
     * 退款单个红包
     */
    @Transactional(rollbackFor = Exception.class)
    public void refundSinglePacket(RoomRedPacket packet) {
        String packetId = packet.getPacketId();
        
        // 1. 检查退款状态（防止重复）
        if (!RoomRedPacketRefundStatus.NOT_REFUNDED.getCode().equals(packet.getRefundStatus())) {
            log.warn("红包已退款或无需退款 packetId={} refundStatus={}", 
                packetId, packet.getRefundStatus());
            return;
        }
        
        // 2. 检查是否有剩余金额
        Long remainAmount = packet.getRemainAmount();
        if (remainAmount <= 0) {
            // 已抢完，无需退款，只更新状态
            roomRedPacketGateway.updateStatus(packetId, RoomRedPacketStatus.FINISHED);
            roomRedPacketGateway.updateRefundStatus(packetId, RoomRedPacketRefundStatus.NO_NEED_REFUND.getCode());
            log.info("红包已抢完无需退款 packetId={}", packetId);
            return;
        }
        
        // 3. 判断红包来源类型
        if (RoomRedPacketSourceType.USER.getCode().equals(packet.getSourceType())) {
            // 用户红包：退款
            refundToUser(packet);
            roomRedPacketGateway.updateRefundStatus(packetId, RoomRedPacketRefundStatus.REFUNDED.getCode());
        } else if (RoomRedPacketSourceType.PLATFORM.getCode().equals(packet.getSourceType())) {
            // 平台红包：不退款，金币作废
            roomRedPacketGateway.updateRefundStatus(packetId, RoomRedPacketRefundStatus.NO_NEED_REFUND.getCode());
            log.info("平台红包过期不退款 packetId={} remainAmount={}", packetId, remainAmount);
        }
        
        // 4. 更新红包状态为已过期
        roomRedPacketGateway.updateStatus(packetId, RoomRedPacketStatus.EXPIRED);
        
        // 5. 删除Redis缓存
        roomRedPacketCacheService.deleteRedPacket(packetId);
        
        log.info("红包过期处理完成 packetId={} sourceType={} remainAmount={}", 
            packetId, packet.getSourceType(), remainAmount);
    }

    /**
     * 退款给用户
     */
    private void refundToUser(RoomRedPacket packet) {
        Long remainAmount = packet.getRemainAmount();
        Long userId = packet.getUserId();
        String packetId = packet.getPacketId();

        GoldReceiptCmd build = GoldReceiptCmd.builder()
                .appIncome()
                .userId(userId)
                .amount(PennyAmount.ofDollar(remainAmount))
                .eventId(packetId + "_refund")
                .sysOrigin(SysOriginPlatformEnum.LIKEI)
                .origin(GoldOrigin.ROOM_RED_PACKET)
                .build();
        
        try {
            walletGoldClient.changeBalance(build);
            log.info("红包退款成功 packetId={} userId={} amount={}", 
                packetId, userId, remainAmount);
        } catch (Exception e) {
            log.error("红包退款失败 packetId={} userId={} amount={}", 
                packetId, userId, remainAmount, e);
            throw new RuntimeException("红包退款失败", e);
        }
    }
}
