package com.zhentao.service.impl;

import com.zhentao.entity.CheckinRecord;
import com.zhentao.mapper.CheckinRecordMapper;
import com.zhentao.service.CheckinService;
import com.zhentao.service.VipService;
import com.zhentao.vo.CheckinInfoVO;
import com.zhentao.vo.CheckinRewardVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * 签到服务实现类
 * 使用Redis的Bitmap实现签到功能
 */
@Service
public class CheckinServiceImpl implements CheckinService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private CheckinRecordMapper checkinRecordMapper;
    
    @Autowired
    private VipService vipService;
    
    private static final String CHECKIN_KEY_PREFIX = "checkin:";
    
    /**
     * 生成Redis Key: checkin:userId:yyyyMM
     */
    private String getCheckinKey(Long userId, LocalDate date) {
        String yearMonth = date.format(DateTimeFormatter.ofPattern("yyyyMM"));
        return CHECKIN_KEY_PREFIX + userId + ":" + yearMonth;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CheckinInfoVO checkin(Long userId) {
        LocalDate today = LocalDate.now();
        
        // 检查今天是否已签到（从数据库查询，更准确）
        CheckinRecord existRecord = checkinRecordMapper.selectByUserIdAndDate(userId, today);
        if (existRecord != null) {
            throw new RuntimeException("今日已签到");
        }
        
        // 使用Redis Bitmap记录签到
        String key = getCheckinKey(userId, today);
        int dayOfMonth = today.getDayOfMonth();
        redisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
        
        // 计算连续签到天数
        Integer continuousDays = calculateContinuousDays(userId);
        
        // 计算累计签到天数
        Integer totalDays = calculateTotalDays(userId);
        
        // 判断是否获得奖励
        Integer rewardType = getRewardType(continuousDays);
        Integer rewardReceived = rewardType > 0 ? 1 : 0;
        
        // 保存签到记录到数据库
        CheckinRecord record = new CheckinRecord();
        record.setUserId(userId);
        record.setCheckinDate(today);
        record.setContinuousDays(continuousDays);
        record.setTotalDays(totalDays);
        record.setRewardReceived(rewardReceived);
        record.setRewardType(rewardType);
        record.setCreateTime(LocalDateTime.now());
        checkinRecordMapper.insert(record);
        
        // 如果获得VIP奖励，自动发放
        if (rewardType > 0) {
            Integer vipDays = getVipDays(rewardType);
            if (vipDays > 0) {
                vipService.grantVip(userId, vipDays, "签到奖励-连续" + continuousDays + "天");
            }
        }
        
        // 返回签到信息
        return getCheckinInfo(userId);
    }
    
    @Override
    public CheckinInfoVO getCheckinInfo(Long userId) {
        LocalDate today = LocalDate.now();
        
        CheckinInfoVO vo = new CheckinInfoVO();
        
        // 计算连续签到天数
        Integer continuousDays = calculateContinuousDays(userId);
        vo.setContinuousDays(continuousDays);
        
        // 计算累计签到天数
        Integer totalDays = calculateTotalDays(userId);
        vo.setTotalDays(totalDays);
        
        // 检查今天是否已签到（从数据库查询）
        CheckinRecord todayRecord = checkinRecordMapper.selectByUserIdAndDate(userId, today);
        vo.setTodayChecked(todayRecord != null);
        
        // 获取本月已签到日期
        List<String> checkedDates = getMonthCheckedDates(userId, today);
        vo.setCheckedDates(checkedDates);
        
        // 设置奖励信息
        List<CheckinRewardVO> rewards = buildRewards(continuousDays);
        vo.setRewards(rewards);
        
        return vo;
    }
    
    /**
     * 计算连续签到天数（从数据库查询）
     */
    private Integer calculateContinuousDays(Long userId) {
        LocalDate today = LocalDate.now();
        int continuousDays = 0;
        LocalDate checkDate = today;
        
        // 从今天往前推，检查连续签到
        for (int i = 0; i < 365; i++) {
            CheckinRecord record = checkinRecordMapper.selectByUserIdAndDate(userId, checkDate);
            if (record != null) {
                continuousDays++;
                checkDate = checkDate.minusDays(1);
            } else {
                break;
            }
        }
        
        return continuousDays;
    }
    
    /**
     * 计算累计签到天数
     */
    private Integer calculateTotalDays(Long userId) {
        // 从数据库查询累计天数（更准确）
        Integer totalDays = checkinRecordMapper.countTotalDays(userId);
        return totalDays == null ? 0 : totalDays;
    }
    
    /**
     * 获取本月已签到的日期列表（从数据库查询，确保数据一致性）
     */
    private List<String> getMonthCheckedDates(Long userId, LocalDate date) {
        List<String> dates = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        
        // 从数据库查询本月的签到记录
        List<LocalDate> checkinDates = checkinRecordMapper.selectMonthCheckinDates(
            userId, 
            date.getYear(), 
            date.getMonthValue()
        );
        
        if (checkinDates != null && !checkinDates.isEmpty()) {
            for (LocalDate checkinDate : checkinDates) {
                dates.add(checkinDate.format(formatter));
            }
        }
        
        return dates;
    }
    
    /**
     * 根据连续签到天数判断奖励类型
     * 0: 无奖励, 1: 1天VIP, 2: 3天VIP, 3: 7天VIP
     */
    private Integer getRewardType(Integer continuousDays) {
        if (continuousDays == 7) {
            return 1;
        } else if (continuousDays == 14) {
            return 2;
        } else if (continuousDays == 30) {
            return 3;
        }
        return 0;
    }
    
    /**
     * 根据奖励类型获取VIP天数
     */
    private Integer getVipDays(Integer rewardType) {
        switch (rewardType) {
            case 1: return 1;
            case 2: return 3;
            case 3: return 7;
            default: return 0;
        }
    }
    
    /**
     * 构建奖励列表
     */
    private List<CheckinRewardVO> buildRewards(Integer continuousDays) {
        List<CheckinRewardVO> rewards = new ArrayList<>();
        
        // 7天VIP奖励
        boolean received7 = continuousDays >= 7;
        boolean isCurrent7 = continuousDays < 7;
        rewards.add(new CheckinRewardVO(7, "👑", "VIP+1天", received7, isCurrent7));
        
        // 14天VIP奖励
        boolean received14 = continuousDays >= 14;
        boolean isCurrent14 = continuousDays >= 7 && continuousDays < 14;
        rewards.add(new CheckinRewardVO(14, "💎", "VIP+3天", received14, isCurrent14));
        
        // 30天VIP奖励
        boolean received30 = continuousDays >= 30;
        boolean isCurrent30 = continuousDays >= 14 && continuousDays < 30;
        rewards.add(new CheckinRewardVO(30, "🏆", "VIP+7天", received30, isCurrent30));
        
        return rewards;
    }
}

