package com.mosquito.project.job;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mosquito.project.domain.Activity;
import com.mosquito.project.persistence.entity.ActivityEntity;
import com.mosquito.project.persistence.entity.RewardJobEntity;
import com.mosquito.project.persistence.entity.ShortLinkEntity;
import com.mosquito.project.persistence.entity.UserRewardEntity;
import com.mosquito.project.persistence.repository.ActivityRepository;
import com.mosquito.project.persistence.repository.RewardJobRepository;
import com.mosquito.project.persistence.repository.ShortLinkRepository;
import com.mosquito.project.persistence.repository.UserRewardRepository;
import com.mosquito.project.service.CouponRewardService;
import com.mosquito.project.service.RewardService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Map;

/**
 * 奖励任务消费处理器
 * 定时处理奖励队列中的待发放任务
 * 使用tracking_id进行精确归因
 * 按活动规则计算奖励值
 */
@Component
public class RewardJobProcessor {

    private static final Logger log = LoggerFactory.getLogger(RewardJobProcessor.class);
    private static final int MAX_RETRY_COUNT = 3;

    private final RewardJobRepository rewardJobRepository;
    private final ShortLinkRepository shortLinkRepository;
    private final UserRewardRepository userRewardRepository;
    private final ActivityRepository activityRepository;
    private final ObjectMapper objectMapper;
    private final RewardDistributor rewardDistributor;
    private final CouponRewardService couponRewardService;

    public RewardJobProcessor(RewardJobRepository rewardJobRepository,
                              ShortLinkRepository shortLinkRepository,
                              UserRewardRepository userRewardRepository,
                              ActivityRepository activityRepository,
                              ObjectMapper objectMapper,
                              RewardDistributor rewardDistributor,
                              CouponRewardService couponRewardService) {
        this.rewardJobRepository = rewardJobRepository;
        this.shortLinkRepository = shortLinkRepository;
        this.userRewardRepository = userRewardRepository;
        this.activityRepository = activityRepository;
        this.objectMapper = objectMapper;
        this.rewardDistributor = rewardDistributor;
        this.couponRewardService = couponRewardService;
    }

    @Scheduled(fixedDelay = 5000) // 每5秒执行一次
    @Transactional
    public void processRewardJobs() {
        OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
        List<RewardJobEntity> pendingJobs = rewardJobRepository
            .findTop10ByStatusAndNextRunAtLessThanEqualOrderByCreatedAtAsc("pending", now);

        if (pendingJobs.isEmpty()) {
            return;
        }

        log.info("开始处理 {} 个奖励任务", pendingJobs.size());

        for (RewardJobEntity job : pendingJobs) {
            try {
                processRewardJob(job);
            } catch (Exception e) {
                log.error("处理奖励任务 {} 失败: {}", job.getId(), e.getMessage());
                handleJobFailure(job);
            }
        }

        log.info("奖励任务处理完成");
    }

    /**
     * 处理单个奖励任务
     * 通过tracking_id精确定位邀请关系并发奖
     * PRD要求：去掉"按externalUserId查最近邀请记录"的隐式归因
     */
    private void processRewardJob(RewardJobEntity job) {
        String trackingId = job.getTrackingId();

        if (trackingId == null || trackingId.isEmpty()) {
            log.warn("奖励任务 {} 缺少tracking_id", job.getId());
            job.setStatus("failed");
            job.setUpdatedAt(OffsetDateTime.now(ZoneOffset.UTC));
            rewardJobRepository.save(job);
            return;
        }

        // 通过tracking_id精确查找对应的短链接记录（包含邀请关系）
        var shortLinkOpt = shortLinkRepository.findByTrackingId(trackingId);

        if (shortLinkOpt.isEmpty()) {
            log.warn("找不到tracking_id {} 对应的邀请记录", trackingId);
            job.setStatus("failed");
            job.setUpdatedAt(OffsetDateTime.now(ZoneOffset.UTC));
            rewardJobRepository.save(job);
            return;
        }

        ShortLinkEntity shortLink = shortLinkOpt.get();
        Long inviterUserId = shortLink.getInviterUserId();
        Long activityId = shortLink.getActivityId();

        if (inviterUserId == null) {
            log.warn("tracking_id {} 对应的邀请记录没有邀请人", trackingId);
            job.setStatus("failed");
            job.setUpdatedAt(OffsetDateTime.now(ZoneOffset.UTC));
            rewardJobRepository.save(job);
            return;
        }

        // 根据活动配置计算奖励值和奖励类型
        int points = calculateRewardPoints(activityId);
        String rewardType = calculateRewardType(activityId); // 从活动配置获取奖励类型

        // 处理优惠券奖励
        if ("COUPON".equals(rewardType)) {
            // 优惠券奖励处理：先创建积分记录（状态为APPROVED），再调用优惠券服务发放
            processCouponReward(job, shortLink, inviterUserId, activityId, trackingId, points);
            return;
        }

        // 调用外部发放适配器进行奖励发放
        try {
            boolean success = rewardDistributor.distribute(inviterUserId, activityId, trackingId, points, rewardType);
            if (!success) {
                log.warn("奖励发放失败: userId={}, activityId={}, trackingId={}", inviterUserId, activityId, trackingId);
                handleJobFailure(job);
                return;
            }
        } catch (Exception e) {
            log.error("奖励发放异常: {}", e.getMessage());
            handleJobFailure(job);
            return;
        }

        // 创建用户奖励记录
        UserRewardEntity reward = new UserRewardEntity();
        reward.setUserId(inviterUserId);
        reward.setActivityId(activityId);
        reward.setPoints(points);
        reward.setType(rewardType);
        reward.setStatus(RewardService.STATUS_GRANTED);
        reward.setCreatedAt(OffsetDateTime.now(ZoneOffset.UTC));
        reward.setTrackingId(trackingId); // 记录归因的tracking_id

        // 从活动获取部门ID，用于数据权限过滤
        var activityOpt = activityRepository.findById(activityId);
        if (activityOpt.isPresent()) {
            reward.setDepartmentId(activityOpt.get().getDepartmentId());
            log.debug("设置奖励departmentId={} from activityId={}", activityOpt.get().getDepartmentId(), activityId);
        }

        userRewardRepository.save(reward);

        // 更新任务状态为已完成
        job.setStatus("completed");
        job.setUpdatedAt(OffsetDateTime.now(ZoneOffset.UTC));
        rewardJobRepository.save(job);

        log.info("成功处理奖励任务 {}，通过tracking_id {} 为用户 {} 发放 {} 积分", job.getId(), trackingId, inviterUserId, points);
    }

    /**
     * 根据活动配置计算奖励积分
     */
    private int calculateRewardPoints(Long activityId) {
        // 默认奖励值
        int defaultPoints = 10;

        try {
            var activityOpt = activityRepository.findById(activityId);
            if (activityOpt.isEmpty()) {
                log.warn("找不到活动 {} 的配置，使用默认奖励", activityId);
                return defaultPoints;
            }

            ActivityEntity activity = activityOpt.get();
            String calculationMode = activity.getRewardCalculationMode();

            // 如果有阶梯奖励配置，按阶梯计算
            if (activity.getRewardTiersConfig() != null && !activity.getRewardTiersConfig().isEmpty()) {
                return calculateTieredReward(activity.getRewardTiersConfig());
            }

            // 根据计算模式返回奖励
            if ("FIXED".equals(calculationMode)) {
                return defaultPoints;
            }

            // 默认返回固定奖励
            return defaultPoints;

        } catch (Exception e) {
            log.error("计算奖励失败: {}", e.getMessage());
            return defaultPoints;
        }
    }

    /**
     * 计算阶梯奖励
     */
    private int calculateTieredReward(String tiersConfig) {
        try {
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> tiers = objectMapper.readValue(tiersConfig, List.class);
            if (tiers == null || tiers.isEmpty()) {
                return 10;
            }
            // 取第一个阶梯的奖励值
            Map<String, Object> firstTier = tiers.get(0);
            Object points = firstTier.get("points");
            if (points instanceof Number) {
                return ((Number) points).intValue();
            }
            return 10;
        } catch (JsonProcessingException e) {
            log.error("解析阶梯奖励配置失败: {}", e.getMessage());
            return 10;
        }
    }

    /**
     * 从活动配置中获取奖励类型
     */
    private String calculateRewardType(Long activityId) {
        try {
            var activityOpt = activityRepository.findById(activityId);
            if (activityOpt.isEmpty()) {
                return "POINTS"; // 默认积分奖励
            }
            ActivityEntity activity = activityOpt.get();
            // 从活动配置的 rewardTiersConfig 中获取奖励类型
            if (activity.getRewardTiersConfig() != null && !activity.getRewardTiersConfig().isEmpty()) {
                @SuppressWarnings("unchecked")
                List<Map<String, Object>> tiers = objectMapper.readValue(activity.getRewardTiersConfig(), List.class);
                if (tiers != null && !tiers.isEmpty()) {
                    Map<String, Object> firstTier = tiers.get(0);
                    Object type = firstTier.get("type");
                    if (type != null) {
                        return type.toString();
                    }
                }
            }
            return "POINTS"; // 默认积分奖励
        } catch (Exception e) {
            log.error("获取奖励类型失败: {}", e.getMessage());
            return "POINTS";
        }
    }

    /**
     * 处理优惠券奖励发放
     */
    private void processCouponReward(RewardJobEntity job, ShortLinkEntity shortLink,
                                    Long inviterUserId, Long activityId, String trackingId, int points) {
        try {
            // 1. 先创建用户奖励记录（状态为APPROVED待发放）
            UserRewardEntity reward = new UserRewardEntity();
            reward.setUserId(inviterUserId);
            reward.setActivityId(activityId);
            reward.setPoints(points);
            reward.setType("COUPON");
            reward.setStatus("APPROVED"); // 待发放状态
            reward.setCreatedAt(OffsetDateTime.now(ZoneOffset.UTC));
            reward.setTrackingId(trackingId);

            // 从活动获取部门ID和优惠券批次ID
            var activityOpt = activityRepository.findById(activityId);
            if (activityOpt.isPresent()) {
                ActivityEntity activity = activityOpt.get();
                reward.setDepartmentId(activity.getDepartmentId());
                // 从活动配置中获取优惠券批次ID
                if (activity.getRewardTiersConfig() != null) {
                    try {
                        @SuppressWarnings("unchecked")
                        List<Map<String, Object>> tiers = objectMapper.readValue(activity.getRewardTiersConfig(), List.class);
                        if (tiers != null && !tiers.isEmpty()) {
                            Object couponBatchId = tiers.get(0).get("couponBatchId");
                            if (couponBatchId != null) {
                                reward.setCouponBatchId(couponBatchId.toString());
                            }
                        }
                    } catch (Exception e) {
                        log.warn("解析优惠券批次ID失败: {}", e.getMessage());
                    }
                }
            }

            UserRewardEntity savedReward = userRewardRepository.save(reward);

            // 2. 调用优惠券服务发放优惠券
            if (savedReward.getCouponBatchId() != null) {
                CouponRewardService.CouponGrantResult result = couponRewardService.grantCoupon(
                    savedReward.getId(),
                    savedReward.getCouponBatchId(),
                    inviterUserId
                );

                if (result.isSuccess()) {
                    log.info("优惠券发放成功: rewardId={}, couponCode={}", savedReward.getId(), result.getCouponCode());
                } else {
                    log.warn("优惠券发放失败: rewardId={}, reason={}", savedReward.getId(), result.getMessage());
                    // 优惠券发放失败不算任务失败，因为奖励记录已创建
                }
            }

            // 3. 更新任务状态为已完成
            job.setStatus("completed");
            job.setUpdatedAt(OffsetDateTime.now(ZoneOffset.UTC));
            rewardJobRepository.save(job);

            log.info("成功处理优惠券奖励任务 {}，通过tracking_id {} 为用户 {} 发放优惠券", job.getId(), trackingId, inviterUserId);

        } catch (Exception e) {
            log.error("处理优惠券奖励任务 {} 失败: {}", job.getId(), e.getMessage());
            handleJobFailure(job);
        }
    }

    /**
     * 处理任务失败，重试或标记为失败
     */
    private void handleJobFailure(RewardJobEntity job) {
        int retryCount = job.getRetryCount() != null ? job.getRetryCount() : 0;

        if (retryCount >= MAX_RETRY_COUNT) {
            // 超过最大重试次数，标记为失败
            job.setStatus("failed");
            log.warn("奖励任务 {} 超过最大重试次数，标记为失败", job.getId());
        } else {
            // 增加重试次数，安排下次执行
            job.setRetryCount(retryCount + 1);
            job.setNextRunAt(OffsetDateTime.now(ZoneOffset.UTC).plusMinutes((long) Math.pow(2, retryCount)));
            job.setStatus("pending");
            log.info("奖励任务 {} 重试次数 {}, 下次执行时间: {}", job.getId(), retryCount + 1, job.getNextRunAt());
        }

        job.setUpdatedAt(OffsetDateTime.now(ZoneOffset.UTC));
        rewardJobRepository.save(job);
    }

    /**
     * 奖励发放接口（适配器模式）
     */
    public interface RewardDistributor {
        /**
         * 发放奖励
         * @param userId 用户ID
         * @param activityId 活动ID
         * @param trackingId 追踪ID
         * @param points 积分数量
         * @param rewardType 奖励类型
         * @return 是否发放成功
         */
        boolean distribute(Long userId, Long activityId, String trackingId, int points, String rewardType);
    }
}
