package com.fs.live.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fs.common.exception.base.BaseException;
import com.fs.his.domain.FsUser;
import com.fs.his.domain.FsUserIntegralLogs;
import com.fs.his.mapper.FsUserIntegralLogsMapper;
import com.fs.his.mapper.FsUserMapper;
import com.fs.live.domain.Live;
import com.fs.live.domain.LiveCompletionPointsRecord;
import com.fs.live.mapper.LiveCompletionPointsRecordMapper;
import com.fs.live.service.ILiveCompletionPointsRecordService;
import com.fs.live.service.ILiveService;
import com.fs.live.service.ILiveWatchUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;

/**
 * 直播完课积分记录Service业务层处理
 */
@Slf4j
@Service
public class LiveCompletionPointsRecordServiceImpl implements ILiveCompletionPointsRecordService {

    @Autowired
    private LiveCompletionPointsRecordMapper recordMapper;

    @Autowired
    private ILiveService liveService;

    @Autowired
    private FsUserMapper fsUserMapper;

    @Autowired
    private FsUserIntegralLogsMapper fsUserIntegralLogsMapper;

    @Autowired
    private ILiveWatchUserService liveWatchUserService;


    /**
     * 检查并创建完课记录(由定时任务调用)
     * @param liveId 直播间ID
     * @param userId 用户ID
     * @param watchDuration 观看时长（可为null，为null时从数据库自动累计直播+回放时长）
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkAndCreateCompletionRecord(Long liveId, Long userId, Long watchDuration) {
        try {
            // 1. 获取直播信息和配置
            Live live = liveService.selectLiveByLiveId(liveId);
            if (live == null) {

                return;
            }

            // 2. 从数据库获取完课积分配置
            CompletionPointsConfig config = getCompletionPointsConfig(live);

            // 检查是否开启完课积分功能
            if (!config.isEnabled()) {

                return;
            }

            // 检查配置完整性
            Integer completionRate = config.getCompletionRate();
            int[] pointsConfig = config.getPointsConfig();

            if (completionRate == null || pointsConfig == null || pointsConfig.length == 0) {

                return;
            }

            // 3. 获取观看时长（如果为null，则从数据库累计直播+回放时长）
            Long actualWatchDuration = watchDuration;
            if (actualWatchDuration == null) {
                // 自动累加直播和回放的观看时长
                actualWatchDuration = liveWatchUserService.getTotalWatchDuration(liveId, userId);

            }

            if (actualWatchDuration == null || actualWatchDuration <= 0) {

                return;
            }

            // 4. 获取视频总时长(秒)
            Long videoDuration = live.getDuration();
            if (videoDuration == null || videoDuration <= 0) {

                return;
            }

            // 5. 计算完课比例
            BigDecimal watchRate = BigDecimal.valueOf(actualWatchDuration)
                    .multiply(BigDecimal.valueOf(100))
                    .divide(BigDecimal.valueOf(videoDuration), 2, RoundingMode.HALF_UP);

            // 限制完课比例最大值为100.00%（防止数据库字段溢出）
            if (watchRate.compareTo(BigDecimal.valueOf(100)) > 0) {
                watchRate = BigDecimal.valueOf(100);
            }

            // 6. 判断是否达到完课标准
            if (watchRate.compareTo(BigDecimal.valueOf(completionRate)) < 0) {

                return;
            }

            // 7. 检查今天是否已有完课记录
            LocalDate today = LocalDate.now();
            Date currentDate = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant());

            LiveCompletionPointsRecord todayRecord = recordMapper.selectByUserAndDate(liveId, userId, currentDate);
            if (todayRecord != null) {

                return;
            }

            // 7. 查询最近一次完课记录（不限直播间）,计算连续天数
            LiveCompletionPointsRecord latestRecord = recordMapper.selectLatestByUser(userId);
            int continuousDays = 1;

            if (latestRecord != null) {
                LocalDate lastDate = latestRecord.getCurrentCompletionDate()
                        .toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

                long daysBetween = ChronoUnit.DAYS.between(lastDate, today);

                if (daysBetween == 0) {
                    continuousDays = latestRecord.getContinuousDays();

                } else if (daysBetween == 1) {
                    // 昨天完课了,连续天数+1
                    continuousDays = latestRecord.getContinuousDays() + 1;
                } else {
                    // 中断了,重新开始
                    continuousDays = 1;
                }
            }

            // 8. 计算积分
            int points = calculatePoints(continuousDays, pointsConfig);

            // 9. 创建完课记录
            LiveCompletionPointsRecord record = new LiveCompletionPointsRecord();
            record.setLiveId(liveId);
            record.setUserId(userId);
            record.setWatchDuration(actualWatchDuration);
            record.setVideoDuration(videoDuration);
            record.setCompletionRate(watchRate);
            record.setContinuousDays(continuousDays);
            record.setPointsAwarded(points);
            record.setCurrentCompletionDate(currentDate);
            record.setReceiveStatus(0); // 未领取

            if (latestRecord != null) {
                record.setLastCompletionDate(latestRecord.getCurrentCompletionDate());
            }

            recordMapper.insertRecord(record);



        } catch (Exception e) {
            log.error("检查并创建完课记录失败, liveId={}, userId={}", liveId, userId, e);
            throw e;
        }
    }

    /**
     * 用户领取完课积分
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public LiveCompletionPointsRecord receiveCompletionPoints(Long recordId, Long userId) {
        // 1. 查询完课记录
        LiveCompletionPointsRecord record = recordMapper.selectById(recordId);
        if (record == null) {
            throw new BaseException("完课记录不存在");
        }

        // 2. 校验用户
        if (!record.getUserId().equals(userId)) {
            throw new BaseException("无权领取该完课积分");
        }

        // 3. 校验领取状态
        if (record.getReceiveStatus() == 1) {
            throw new BaseException("该完课积分已领取");
        }

        // 4. 更新用户积分
        FsUser user = fsUserMapper.selectFsUserByUserId(userId);
        if (user == null) {
            throw new BaseException("用户不存在");
        }

        Long currentIntegral = user.getIntegral() != null ? user.getIntegral() : 0L;
        Long newIntegral = currentIntegral + record.getPointsAwarded();

        FsUser updateUser = new FsUser();
        updateUser.setUserId(userId);
        updateUser.setIntegral(newIntegral);
        fsUserMapper.updateFsUser(updateUser);

        // 5. 记录积分变动日志
        FsUserIntegralLogs integralLog = new FsUserIntegralLogs();
        integralLog.setUserId(userId);
        integralLog.setIntegral(Long.valueOf(record.getPointsAwarded()));
        integralLog.setBalance(newIntegral);
        integralLog.setLogType(25); // 5-直播完课积分
        integralLog.setBusinessId("live_completion_" + recordId); // 业务ID:直播完课记录ID
        integralLog.setBusinessType(25); // 5-直播完课
        integralLog.setStatus(1);
        integralLog.setCreateTime(new Date());
        fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLog);

        // 6. 更新完课记录状态
        LiveCompletionPointsRecord updateRecord = new LiveCompletionPointsRecord();
        updateRecord.setId(recordId);
        updateRecord.setReceiveStatus(1);
        updateRecord.setReceiveTime(new Date());
        recordMapper.updateRecord(updateRecord);

        // 7. 返回更新后的记录
        record.setReceiveStatus(1);
        record.setReceiveTime(new Date());

        log.info("用户领取完课积分成功, userId={}, recordId={}, points={}", userId, recordId, record.getPointsAwarded());

        return record;
    }

    /**
     * 获取用户未领取的完课记录
     */
    @Override
    public List<LiveCompletionPointsRecord> getUserUnreceivedRecords(Long liveId, Long userId) {
        return recordMapper.selectUnreceivedByUser(liveId, userId);
    }

    /**
     * 查询用户积分领取记录
     */
    @Override
    public List<LiveCompletionPointsRecord> getUserRecords(Long liveId, Long userId) {
        return recordMapper.selectRecordsByUser(liveId, userId);
    }

    /**
     * 根据用户和日期查询完课记录
     */
    @Override
    public LiveCompletionPointsRecord selectByUserAndDate(Long liveId, Long userId, Date date) {
        return recordMapper.selectByUserAndDate(liveId, userId, date);
    }

    @Override
    public LiveCompletionPointsRecord createCompletionRecord(Long liveId, Long userId) {
        try {
            // 1. 获取直播信息和配置
            Live live = liveService.selectLiveByLiveId(liveId);
            if (live == null) {

                return null;
            }

            // 2. 从数据库获取完课积分配置
            CompletionPointsConfig config = getCompletionPointsConfig(live);

            // 检查是否开启完课积分功能
            if (!config.isEnabled()) {

                return null;
            }

            // 检查配置完整性
            Integer completionRate = config.getCompletionRate();
            int[] pointsConfig = config.getPointsConfig();

            if (completionRate == null || pointsConfig == null || pointsConfig.length == 0) {

                return null;
            }

            // 3. 获取观看时长（如果为null，则从数据库累计直播+回放时长）
            // 4.这个时间和liveWatchUser分开算
            long actualWatchDuration = 0L;

            // 4. 获取视频总时长(秒)
            Long videoDuration = live.getDuration();
            if (videoDuration == null || videoDuration <= 0) {

                return null;
            }

            // 5. 计算完课比例
            BigDecimal watchRate = BigDecimal.valueOf(actualWatchDuration)
                    .multiply(BigDecimal.valueOf(100))
                    .divide(BigDecimal.valueOf(videoDuration), 2, RoundingMode.HALF_UP);

            // 限制完课比例最大值为100.00%（防止数据库字段溢出）
            if (watchRate.compareTo(BigDecimal.valueOf(100)) > 0) {
                watchRate = BigDecimal.valueOf(100);
            }

//            // 6. 判断是否达到完课标准
//            if (watchRate.compareTo(BigDecimal.valueOf(completionRate)) < 0) {
//
//                return null;
//            }

            // 7. 检查今天是否已有完课记录
            LocalDate today = LocalDate.now();
            Date currentDate = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant());

            LiveCompletionPointsRecord todayRecord = recordMapper.selectByUserAndDate(liveId, userId, currentDate);
            if (todayRecord != null) {

                return todayRecord;
            }

            // 7. 查询最近一次完课记录（不限直播间）,计算连续天数
            LiveCompletionPointsRecord latestRecord = recordMapper.selectLatestByUser(userId);
            int continuousDays = 1;

            if (latestRecord != null) {
                LocalDate lastDate = latestRecord.getCurrentCompletionDate()
                        .toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

                long daysBetween = ChronoUnit.DAYS.between(lastDate, today);

                if (daysBetween == 0) {
                    continuousDays = latestRecord.getContinuousDays();

                } else if (daysBetween == 1) {
                    // 昨天完课了,连续天数+1
                    continuousDays = latestRecord.getContinuousDays() + 1;
                } else {
                    // 中断了,重新开始
                    continuousDays = 1;
                }
            }

            // 8. 计算积分
            int points = calculatePoints(continuousDays, pointsConfig);

            // 9. 创建完课记录
            LiveCompletionPointsRecord record = new LiveCompletionPointsRecord();
            record.setLiveId(liveId);
            record.setUserId(userId);
            record.setWatchDuration(actualWatchDuration);
            record.setVideoDuration(videoDuration);
            record.setCompletionRate(watchRate);
            record.setContinuousDays(continuousDays);
            record.setPointsAwarded(points);
            record.setCurrentCompletionDate(currentDate);
            record.setReceiveStatus(0); // 未领取

            if (latestRecord != null) {
                record.setLastCompletionDate(latestRecord.getCurrentCompletionDate());
            }

            recordMapper.insertRecord(record);
            return record;
        } catch (Exception e) {
            log.error("检查并创建完课记录失败, liveId={}, userId={}", liveId, userId, e);
            throw e;
        }
    }

    /**
     * 从直播配置中获取完课积分配置
     */
    private CompletionPointsConfig getCompletionPointsConfig(Live live) {
        CompletionPointsConfig config = new CompletionPointsConfig();
        config.setEnabled(false);
        config.setCompletionRate(null);
        config.setPointsConfig(null);

        String configJson = live.getConfigJson();
        if (configJson == null || configJson.isEmpty()) {
            return config;
        }

        try {
            JSONObject jsonConfig = JSON.parseObject(configJson);

            config.setEnabled(jsonConfig.getBooleanValue("enabled"));

            Integer rate = jsonConfig.getInteger("completionRate");
            if (rate != null && rate > 0 && rate <= 100) {
                config.setCompletionRate(rate);
            }

            List<Integer> pointsList = jsonConfig.getObject("pointsConfig", List.class);
            if (pointsList != null && !pointsList.isEmpty()) {
                config.setPointsConfig(pointsList.stream().mapToInt(Integer::intValue).toArray());
            }
        } catch (Exception e) {
            log.warn("解析完课积分配置失败, liveId={}, 配置未生效", live.getLiveId(), e);
        }

        return config;
    }

    /**
     * 计算积分
     * 根据连续天数和积分配置计算应得积分
     * @param continuousDays 连续完课天数
     * @param pointsConfig 积分配置数组
     * @return 应得积分
     */
    private int calculatePoints(int continuousDays, int[] pointsConfig) {
        if (continuousDays <= 0) {
            return pointsConfig[0];
        }
        if (continuousDays > pointsConfig.length) {
            // 超过配置天数,使用最后一天的积分
            return pointsConfig[pointsConfig.length - 1];
        }
        return pointsConfig[continuousDays - 1];
    }

    /**
     * 完课积分配置内部类
     */
    private static class CompletionPointsConfig {
        private boolean enabled;
        private Integer completionRate;
        private int[] pointsConfig;

        public boolean isEnabled() {
            return enabled;
        }

        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }

        public Integer getCompletionRate() {
            return completionRate;
        }

        public void setCompletionRate(Integer completionRate) {
            this.completionRate = completionRate;
        }

        public int[] getPointsConfig() {
            return pointsConfig;
        }

        public void setPointsConfig(int[] pointsConfig) {
            this.pointsConfig = pointsConfig;
        }
    }
}
