package com.fs.app.controller.live;

import com.fs.app.controller.AppBaseController;
import com.fs.app.vo.ReceivePointsVO;
import com.fs.app.vo.RemainingTimeVO;
import com.fs.app.vo.UpdateWatchDurationVO;
import com.fs.common.annotation.RepeatSubmit;
import com.fs.common.core.domain.R;
import com.fs.common.exception.base.BaseException;
import com.fs.his.domain.FsUser;
import com.fs.his.domain.FsUserIntegralLogs;
import com.fs.his.service.IFsUserIntegralLogsService;
import com.fs.his.service.IFsUserService;
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 org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 直播完课积分Controller
 */
@RestController
@RequestMapping("/app/live/completion")
public class LiveCompletionPointsController extends AppBaseController {

    private static final Logger logger = LoggerFactory.getLogger(LiveCompletionPointsController.class);

    @Autowired
    private ILiveCompletionPointsRecordService completionPointsRecordService;

    @Autowired
    private IFsUserService fsUserService;

    @Autowired
    private ILiveService liveService;

    @Autowired
    private IFsUserIntegralLogsService fsUserIntegralLogsService;

    @Autowired
    private LiveCompletionPointsRecordMapper completionPointsRecordMapper;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 领取完课积分
     */
    @PostMapping("/receive")
    @RepeatSubmit
    public R receive(@RequestParam Long recordId) {
        Long userId = Long.parseLong(getUserId());
        LiveCompletionPointsRecord record = completionPointsRecordService.receiveCompletionPoints(recordId, userId);
        return R.ok().put("data", record);
    }

    /**
     * 获取用户未领取的积分列表
     */
    @GetMapping("/unreceived")
    public R getUnreceived(@RequestParam Long liveId) {
        Long userId = Long.parseLong(getUserId());
        List<LiveCompletionPointsRecord> records = completionPointsRecordService.getUserUnreceivedRecords(liveId, userId);
        return R.ok().put("data", records);
    }

    /**
     * 查询用户积分领取记录
     */
    @GetMapping("/records")
    public R getRecords(@RequestParam Long liveId) {
        Long userId = Long.parseLong(getUserId());
        List<LiveCompletionPointsRecord> records = completionPointsRecordService.getUserRecords(liveId, userId);
        return R.ok().put("data", records);
    }

    /**
     * 查询用户积分余额和看直播信息统计
     */
    @GetMapping("/info")
    public R getInfo(@RequestParam Long liveId) {
        Long userId = Long.parseLong(getUserId());

        // 1. 获取用户积分余额
        FsUser user = fsUserService.selectFsUserByUserId(userId);
        Long integral = user != null && user.getIntegral() != null ? user.getIntegral() : 0L;


        Live live = liveService.selectLiveByLiveId(liveId);

        // 2. 获取完课记录列表(包含已领取和未领取)
        List<LiveCompletionPointsRecord> records = completionPointsRecordService.getUserRecords(liveId, userId);

        // 3. 统计信息
        long totalPoints = records.stream()
                .filter(r -> r.getReceiveStatus() == 1)
                .mapToLong(LiveCompletionPointsRecord::getPointsAwarded)
                .sum();

        long unreceivedCount = records.stream()
                .filter(r -> r.getReceiveStatus() == 0)
                .count();

        Map<String, Object> result = new HashMap<>();
        result.put("integral", integral);  // 当前积分余额
        result.put("totalPoints", totalPoints);  // 本直播间累计获得积分
        result.put("totalDays", records.size());  // 累计看直播天数
        result.put("unreceivedCount", unreceivedCount);  // 未领取记录数
        result.put("records", records);  // 完课记录列表

        // 5. 添加直播状态和时间信息
        if (live != null) {
            result.put("status", live.getStatus());  // 直播状态
            result.put("startTime", live.getStartTime());  // 预告时间
            result.put("duration", live.getDuration());  // 直播总时长(秒)

            // 当status=2作为真开开始hide时间
            if (live.getStatus() != null && live.getStatus() == 2) {
                LocalDateTime now = LocalDateTime.now();

                result.put("serverTime", now);
                result.put("totalDuration", live.getDuration());  // 直播总时长(秒)
            }
        }

        return R.ok().put("data", result);
    }

    /**
     * 用于测试和调试
     */
    @PostMapping("/test/create")
    public R testCreateRecord(@RequestParam Long liveId, @RequestParam(required = false) Long watchDuration) {
        Long userId = Long.parseLong(getUserId());

        try {
            // 调用完课记录创建方法（watchDuration为null时会自动从数据库累计）
            completionPointsRecordService.checkAndCreateCompletionRecord(liveId, userId, watchDuration);
            return R.ok("完课记录创建成功，请查看records接口查看结果");
        } catch (Exception e) {
            return R.error("创建失败: " + e.getMessage());
        }
    }

    /**
     * 第一个接口：查询当前用户当前直播间领取积分的剩余时长
     * GET请求，传入直播间id
     * 查询当前用户和当前直播间的积分记录（不限制日期），如果不存在就生成看课记录
     */
    @GetMapping("/remaining-time")
    public R getRemainingTime(@RequestParam Long liveId) {
        Long userId = Long.parseLong(getUserId());

        try {
            // 1. 获取直播间信息
            Live live = liveService.selectLiveByLiveId(liveId);
            if (live == null) {
                return R.error("直播间不存在");
            }

            // 2. 查询当前用户和当前直播间的最近一次完课记录（不限制日期）
            LiveCompletionPointsRecord record = completionPointsRecordMapper.selectLatestByUserAndLiveId(liveId, userId);

            // 3. 如果没有记录，查询直播间配置并生成记录
            if (record == null) {
                record = completionPointsRecordService.createCompletionRecord(liveId, userId);
            }

            // 4. 计算剩余时长
            RemainingTimeVO vo = new RemainingTimeVO();
            Long videoDuration = live.getDuration() != null ? live.getDuration() : 0L;
            Long watchDuration = record != null && record.getWatchDuration() != null
                    ? record.getWatchDuration() : 0L;

            vo.setVideoDuration(videoDuration);
            if (record != null) {
                vo.setCompletionRate(record.getCompletionRate());
            }
            vo.setWatchDuration(watchDuration);
            vo.setRemainingTime(Math.max(0, videoDuration - watchDuration));
            vo.setHasReceived(record != null && record.getReceiveStatus() != null && record.getReceiveStatus() == 1);

            return R.ok().put("data", vo);
        } catch (Exception e) {
            return R.error("查询失败: " + e.getMessage());
        }
    }

    /**
     * 第二个接口：更新用户的看课时长
     * POST请求，传入直播间id和看课时长
     * 更新用户看课completionPointsRecordService看课记录里面的时长
     */
    @PostMapping("/update-watch-duration")
    @Transactional
    public R updateWatchDuration(@RequestParam Long liveId, @RequestParam Long watchDuration) {
        Long userId = Long.parseLong(getUserId());

        try {
            // 1. 获取直播间信息
            Live live = liveService.selectLiveByLiveId(liveId);
            if (live == null) {
                return R.error("直播间不存在");
            }

            // 2. 判断当前时间是否在直播期间（状态为2，直播中）
            boolean isLiveInProgress = false;
            LocalDateTime now = LocalDateTime.now();

            if (live.getStatus() != null && live.getStatus() == 2) {
                // status=2 表示直播中
                isLiveInProgress = true;
            } else if (live.getStartTime() != null && live.getFinishTime() != null) {
                // 判断当前时间是否在开播时间和结束时间之间
                isLiveInProgress = (now.isAfter(live.getStartTime()) || now.isEqual(live.getStartTime()))
                        && (now.isBefore(live.getFinishTime()) || now.isEqual(live.getFinishTime()));
            }

            if (!isLiveInProgress) {
                return R.error("当前不在直播期间，无法更新看课时长");
            }

            // 3. 查询当前直播间的完课记录（不限制日期）
            LiveCompletionPointsRecord record = completionPointsRecordMapper.selectLatestByUserAndLiveId(liveId, userId);

            // 4. 计算看课时长
            Date updateTime = null;
            if (record != null && record.getUpdateTime() != null) {
                updateTime = record.getUpdateTime();
            }

            // 判断更新时间与直播间开始时间的关系
            Date startTime = live.getStartTime() != null
                    ? java.sql.Timestamp.valueOf(live.getStartTime()) : null;

            Date currentTime = new Date();
            long timeDiff = 0L;

            if (updateTime != null && startTime != null) {
                if (updateTime.before(startTime)) {
                    // 更新时间小于直播间开始时间，使用直播间开始时间进行计算
                    timeDiff = (currentTime.getTime() - startTime.getTime()) / 1000; // 转换为秒
                } else {
                    // 更新时间大于等于开播时间，按照更新时间进行计算
                    timeDiff = (currentTime.getTime() - updateTime.getTime()) / 1000; // 转换为秒
                }
            } else if (startTime != null) {
                // 没有更新记录，使用直播间开始时间计算
                timeDiff = (currentTime.getTime() - startTime.getTime()) / 1000; // 转换为秒
            }

            // 5. 如果请求传入的时间大于这个时间差，就使用计算出的看课时长，否则使用请求传入的时长
            Long finalWatchDuration;
            if (watchDuration > timeDiff) {
                // 请求传入的时间大于时间差，使用计算出的看课时长
                finalWatchDuration = timeDiff;
            } else {
                // 否则使用请求传入的时长
                finalWatchDuration = watchDuration;
            }

            // 6. 更新完课记录中的看课时长
            if (record == null) {
                // 如果没有记录，先创建记录
                record = completionPointsRecordService.createCompletionRecord(liveId, userId);
                record.setWatchDuration(finalWatchDuration);
                completionPointsRecordMapper.updateRecord(record);
            } else {
                // 更新现有记录的看课时长
                Long currentWatchDuration = record.getWatchDuration() != null
                        ? record.getWatchDuration() : 0L;
                record.setWatchDuration(currentWatchDuration + finalWatchDuration);

                // 重新计算完课比例
                Long videoDuration = live.getDuration();
                if (videoDuration != null && videoDuration > 0) {
                    BigDecimal completionRate = BigDecimal.valueOf(record.getWatchDuration())
                            .multiply(BigDecimal.valueOf(100))
                            .divide(BigDecimal.valueOf(videoDuration), 2, java.math.RoundingMode.HALF_UP);
                    if (completionRate.compareTo(BigDecimal.valueOf(100)) > 0) {
                        completionRate = BigDecimal.valueOf(100);
                    }
                    record.setCompletionRate(completionRate);
                }

                int updateResult = completionPointsRecordMapper.updateRecord(record);
                if (updateResult <= 0) {
                    return R.error("更新看课时间失败");
                }
            }

            UpdateWatchDurationVO vo = new UpdateWatchDurationVO();
            vo.setWatchDuration(finalWatchDuration);
            vo.setTotalWatchDuration(record != null && record.getWatchDuration() != null
                    ? record.getWatchDuration() : finalWatchDuration);

            return R.ok().put("data", vo);
        } catch (Exception e) {
            return R.error("更新失败: " + e.getMessage());
        }
    }

    /**
     * 第三个接口：用户领取看课积分
     * POST请求，传入直播间id
     * 只查询这个直播间的看课记录（不限制日期），检查是否达到了完课标准
     * 达到了更新了看课记录里面的领取条件，给用户发积分
     * 没达到，返回报错
     */
    @PostMapping("/receive-points")
    public R receivePoints(@RequestParam Long liveId) {
        Long userId = Long.parseLong(getUserId());

        // 创建唯一锁，确保同一个 liveId 和 userId 只能有一个线程在执行
        String lockKey = String.format("receivePoints:liveId:%d:userId:%d", liveId, userId);
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取锁，等待时间0秒，锁持有时间15秒
            boolean locked = lock.tryLock(0, 15, TimeUnit.SECONDS);
            if (!locked) {
                logger.warn("获取领取积分锁失败，liveId: {}, userId: {}", liveId, userId);
                return R.error("系统繁忙，请稍后重试");
            }

            try {
                // 1. 查询当前用户和当前直播间的最近一次完课记录（不限制日期）
                LiveCompletionPointsRecord record = completionPointsRecordMapper.selectLatestByUserAndLiveId(liveId, userId);

                if (record == null) {
                    return R.error("您还没有看课记录，无法领取积分");
                }

                // 2. 获取直播间信息和配置
                Live live = liveService.selectLiveByLiveId(liveId);
                if (live == null) {
                    return R.error("直播间不存在");
                }

                // 3. 检查看课记录里面的时长是否达到完课标准
                Long watchDuration = record.getWatchDuration();
                if (watchDuration == null || watchDuration <= 0) {
                    return R.error("您的看课时长不足，无法领取积分");
                }

                // 4. 检查完课比例是否达到标准
                BigDecimal completionRate = record.getCompletionRate();
                if (completionRate == null) {
                    // 重新计算完课比例
                    Long videoDuration = live.getDuration();
                    if (videoDuration == null || videoDuration <= 0) {
                        return R.error("直播间视频时长配置错误");
                    }
                    completionRate = BigDecimal.valueOf(watchDuration)
                            .multiply(BigDecimal.valueOf(100))
                            .divide(BigDecimal.valueOf(videoDuration), 2, java.math.RoundingMode.HALF_UP);
                    if (completionRate.compareTo(BigDecimal.valueOf(100)) > 0) {
                        completionRate = BigDecimal.valueOf(100);
                    }
                    record.setCompletionRate(completionRate);
                }

                // 5. 从直播间配置获取完课标准
                String configJson = live.getConfigJson();
                Integer requiredCompletionRate = null;
                if (configJson != null && !configJson.isEmpty()) {
                    try {
                        com.alibaba.fastjson.JSONObject jsonConfig = com.alibaba.fastjson.JSON.parseObject(configJson);
                        requiredCompletionRate = jsonConfig.getInteger("completionRate");
                    } catch (Exception e) {
                        // 解析失败，忽略
                    }
                }

                // 6. 判断是否达到完课标准
                if (requiredCompletionRate != null && completionRate.compareTo(BigDecimal.valueOf(requiredCompletionRate)) < 0) {
                    return R.error("您的完课比例未达到标准（" + requiredCompletionRate + "%），当前完课比例：" + completionRate + "%");
                }

                // 7. 检查是否已领取
                if (record.getReceiveStatus() != null && record.getReceiveStatus() == 1) {
                    return R.error("该完课积分已领取");
                }

                // 8. 领取积分（更新看课记录的领取状态，给用户加积分）
                LiveCompletionPointsRecord receivedRecord = completionPointsRecordService.receiveCompletionPoints(record.getId(), userId);

                ReceivePointsVO vo = new ReceivePointsVO();
                vo.setRecord(receivedRecord);
                vo.setPoints(receivedRecord.getPointsAwarded());
                vo.setContinuousDays(receivedRecord.getContinuousDays());

                return R.ok().put("data", vo);
            } catch (BaseException e) {
                return R.error(e.getMessage());
            } catch (Exception e) {
                logger.error("领取积分失败，liveId: {}, userId: {}", liveId, userId, e);
                return R.error("领取失败: " + e.getMessage());
            } finally {
                // 释放锁
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                    logger.debug("领取积分锁已释放，liveId: {}, userId: {}", liveId, userId);
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            logger.error("获取领取积分锁被中断，liveId: {}, userId: {}", liveId, userId, e);
            return R.error("系统繁忙，请稍后重试");
        } catch (Exception e) {
            logger.error("领取积分异常，liveId: {}, userId: {}", liveId, userId, e);
            return R.error("领取失败: " + e.getMessage());
        }
    }

    /**
     * 第四个接口：查询用户自己的积分记录
     * GET请求
     */
    @GetMapping("/integral-logs")
    public R getIntegralLogs(@RequestParam(required = false) Integer type) {
        Long userId = Long.parseLong(getUserId());

        try {
            FsUserIntegralLogs query = new FsUserIntegralLogs();
            query.setUserId(userId);

            List<FsUserIntegralLogs> logs = fsUserIntegralLogsService.selectFsUserIntegralLogsList(query);

            // 如果指定了类型，进行过滤
            if (type != null) {
                if (type == 1) {
                    // 获得积分（积分大于0）
                    logs.removeIf(log -> log.getIntegral() == null || log.getIntegral() <= 0);
                } else if (type == 2) {
                    // 消耗积分（积分小于0）
                    logs.removeIf(log -> log.getIntegral() == null || log.getIntegral() >= 0);
                }
            }

            return R.ok().put("data", logs);
        } catch (Exception e) {
            return R.error("查询失败: " + e.getMessage());
        }
    }
}
