package com.red.circle.other.app.command.task;

import com.fasterxml.jackson.core.type.TypeReference;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.other.app.dto.cmd.task.RoomDailyTaskProgressUpdateCmd;
import com.red.circle.other.infra.database.rds.entity.task.RoomDailyTaskConfig;
import com.red.circle.other.infra.database.rds.entity.task.RoomDailyTaskProgress;
import com.red.circle.other.infra.database.rds.entity.task.RoomDailyTaskTier;
import com.red.circle.other.infra.database.rds.service.RoomDailyTaskDatabaseService;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 更新每日任务进度
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RoomDailyTaskProgressUpdateExe {

    private static final String CACHE_KEY_CONFIG = "room:daily:task:config";
    private static final String CACHE_KEY_TIERS  = "room:daily:task:tiers";
    private static final long   CACHE_TTL_HOURS  = 24;

    private final RoomDailyTaskDatabaseService taskDatabaseService;
    private final RedisService redisService;

    @Transactional(rollbackFor = Exception.class)
    public void execute(RoomDailyTaskProgressUpdateCmd cmd) {
        Long userId = cmd.getUserId();
        String taskCode = cmd.getTaskCode();
        Integer progressValue = cmd.getProgressValue();

        RoomDailyTaskConfig config = getConfigFromCache(taskCode);
        if (config == null) {
            log.warn("任务配置不存在或已下线, taskCode={}", taskCode);
            return;
        }

        List<RoomDailyTaskTier> tiers = getTiersFromCache(taskCode);
        if (tiers.isEmpty()) {
            log.warn("任务档位未配置, taskCode={}", taskCode);
            return;
        }

        LocalDate today = ZonedDateTimeAsiaRiyadhUtils.now().toLocalDate();
        RoomDailyTaskProgress progress = taskDatabaseService.getProgress(userId, taskCode, today);

        if (progress == null) {
            progress = new RoomDailyTaskProgress();
            progress.setUserId(userId);
            progress.setTaskId(config.getId());
            progress.setTaskCode(taskCode);
            progress.setTaskCategory(config.getTaskCategory());
            progress.setCycleDate(today);
            progress.setCurrentValue(0);
            progress.setMaxTierCompleted(0);
            progress.setMaxTierClaimed(0);
            progress.setCreateTime(LocalDateTime.now());
        }

        if (progress.getMaxTierClaimed() >= tiers.size()) {
            log.info("所有档位已领取，无需更新进度, userId={}, taskCode={}", userId, taskCode);
            return;
        }

        // 用最高档位 targetValue 截断，防止溢出
        int maxProgress = tiers.get(tiers.size() - 1).getTargetValue();
        if (progressValue > maxProgress) {
            progressValue = maxProgress;
        }

        if (progressValue <= progress.getCurrentValue()) {
            return;
        }

        progress.setCurrentValue(progressValue);

        int maxTierCompleted = 0;
        for (RoomDailyTaskTier tier : tiers) {
            if (progressValue >= tier.getTargetValue()) {
                maxTierCompleted = tier.getTierIndex();
            }
        }
        progress.setMaxTierCompleted(maxTierCompleted);
        progress.setUpdateTime(LocalDateTime.now());

        taskDatabaseService.saveOrUpdateProgress(progress);

        log.info("任务进度更新成功, userId={}, taskCode={}, progressValue={}, maxTierCompleted={}", userId, taskCode, progressValue, maxTierCompleted);
    }

    private RoomDailyTaskConfig getConfigFromCache(String taskCode) {
        RoomDailyTaskConfig config = redisService.hashGet(CACHE_KEY_CONFIG, taskCode, RoomDailyTaskConfig.class);
        if (config != null) {
            return config;
        }
        config = taskDatabaseService.getConfigByCode(taskCode);
        if (config != null) {
            redisService.hashPut(CACHE_KEY_CONFIG, taskCode, config, CACHE_TTL_HOURS, TimeUnit.HOURS);
        }
        return config;
    }

    private List<RoomDailyTaskTier> getTiersFromCache(String taskCode) {
        List<RoomDailyTaskTier> tiers = redisService.hashGet(CACHE_KEY_TIERS, taskCode, new TypeReference<>() {});
        if (tiers != null) {
            return tiers;
        }
        tiers = taskDatabaseService.listTiersByTaskCodes(Collections.singletonList(taskCode));
        if (!tiers.isEmpty()) {
            redisService.hashPut(CACHE_KEY_TIERS, taskCode, tiers, CACHE_TTL_HOURS, TimeUnit.HOURS);
        }
        return tiers;
    }
}
