package com.lesingle.modules.pub.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lesingle.common.enums.ErrorCode;
import com.lesingle.common.enums.Visibility;
import com.lesingle.common.exception.BusinessException;
import com.lesingle.common.result.PageResult;
import com.lesingle.modules.sys.entity.SysUser;
import com.lesingle.modules.sys.mapper.SysUserMapper;
import com.lesingle.modules.ugc.entity.UgcReviewLog;
import com.lesingle.modules.ugc.entity.UgcWork;
import com.lesingle.modules.ugc.enums.WorkPublishStatus;
import com.lesingle.modules.ugc.mapper.UgcReviewLogMapper;
import com.lesingle.modules.ugc.mapper.UgcWorkMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
@RequiredArgsConstructor
public class PublicContentReviewService {

    private final UgcWorkMapper ugcWorkMapper;
    private final UgcReviewLogMapper ugcReviewLogMapper;
    private final SysUserMapper sysUserMapper;

    /**
     * 获取各状态统计（作品审核页：待审核数 + 今日审核维度）
     */
    public Map<String, Long> getStats() {
        Map<String, Long> stats = new LinkedHashMap<>();
        stats.put("pending", countByStatus(WorkPublishStatus.PENDING_REVIEW.getValue()));
        stats.put("pending_review", countByStatus(WorkPublishStatus.PENDING_REVIEW.getValue()));
        stats.put("published", countByStatus(WorkPublishStatus.PUBLISHED.getValue()));
        stats.put("rejected", countByStatus(WorkPublishStatus.REJECTED.getValue()));
        stats.put("taken_down", countByStatus(WorkPublishStatus.UNPUBLISHED.getValue()));
        LocalDateTime dayStart = LocalDate.now().atStartOfDay();
        stats.put("todayReviewed", countTodayReviewLogs(dayStart));
        stats.put("todayApproved", countTodayLogsByAction("approve", dayStart));
        stats.put("todayRejected", countTodayLogsByAction("reject", dayStart));
        return stats;
    }

    /**
     * 获取待审核作品队列
     */
    public PageResult<Map<String, Object>> getWorkQueue(int page, int pageSize, String status,
                                                         String keyword, String startTime, String endTime,
                                                         String reviewStartTime, String reviewEndTime,
                                                         String sortBy, Boolean isRecommended) {
        LambdaQueryWrapper<UgcWork> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UgcWork::getIsDeleted, 0);
        if (StringUtils.hasText(status)) {
            List<String> statusValues = parseStatusFilter(status);
            if (statusValues.isEmpty()) {
                wrapper.eq(UgcWork::getStatus, "__never_match__");
            } else {
                wrapper.in(UgcWork::getStatus, statusValues);
            }
        }
        if (StringUtils.hasText(keyword)) {
            List<Long> userIds = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>()
                            .select(SysUser::getId)
                            .like(SysUser::getNickname, keyword))
                    .stream()
                    .map(SysUser::getId)
                    .collect(Collectors.toList());
            wrapper.and(w -> {
                w.like(UgcWork::getTitle, keyword);
                if (!userIds.isEmpty()) {
                    w.or().in(UgcWork::getUserId, userIds);
                }
            });
        }
        if (StringUtils.hasText(startTime)) {
            wrapper.ge(UgcWork::getCreateTime, LocalDateTime.parse(startTime));
        }
        if (StringUtils.hasText(endTime)) {
            wrapper.le(UgcWork::getCreateTime, LocalDateTime.parse(endTime));
        }
        if (StringUtils.hasText(reviewStartTime)) {
            wrapper.ge(UgcWork::getReviewTime, LocalDateTime.parse(reviewStartTime));
        }
        if (StringUtils.hasText(reviewEndTime)) {
            wrapper.le(UgcWork::getReviewTime, LocalDateTime.parse(reviewEndTime));
        }
        if (isRecommended != null) {
            wrapper.eq(UgcWork::getIsRecommended, isRecommended);
        }

        applyWorkQueueSort(wrapper, sortBy);

        IPage<UgcWork> result = ugcWorkMapper.selectPage(new Page<>(page, pageSize), wrapper);

        List<Map<String, Object>> voList = new ArrayList<>();
        for (UgcWork work : result.getRecords()) {
            Map<String, Object> vo = buildReviewWorkVo(work);
            voList.add(vo);
        }
        return PageResult.from(result, voList);
    }

    /**
     * 获取作品详情（审核用）
     */
    public Map<String, Object> getWorkDetail(Long id) {
        UgcWork work = ugcWorkMapper.selectById(id);
        if (work == null) {
            throw new BusinessException(404, "作品不存在");
        }
        return buildReviewWorkVo(work);
    }

    /**
     * 通过审核
     */
    @Transactional
    public void approve(Long id, String note, Long operatorId) {
        UgcWork work = ugcWorkMapper.selectById(id);
        if (work == null) {
            throw new BusinessException(404, "作品不存在");
        }
        work.setStatus(WorkPublishStatus.PUBLISHED.getValue());
        work.setVisibility(Visibility.PUBLIC.getValue());
        work.setReviewNote(note);
        work.setReviewerId(operatorId);
        work.setReviewTime(LocalDateTime.now());
        work.setPublishTime(LocalDateTime.now());
        work.setModifyTime(LocalDateTime.now());
        ugcWorkMapper.updateById(work);
        createLog(id, "approve", null, note, operatorId);
    }

    /**
     * 驳回
     */
    @Transactional
    public void reject(Long id, String reason, String note, Long operatorId) {
        UgcWork work = ugcWorkMapper.selectById(id);
        if (work == null) {
            throw new BusinessException(404, "作品不存在");
        }
        work.setStatus(WorkPublishStatus.REJECTED.getValue());
        // 前端驳回只传 reason、备注传 note；需写入 review_note 供公众端展示
        StringBuilder reviewText = new StringBuilder();
        if (StringUtils.hasText(reason)) {
            reviewText.append(reason.trim());
        }
        if (StringUtils.hasText(note)) {
            if (reviewText.length() > 0) {
                reviewText.append('；');
            }
            reviewText.append(note.trim());
        }
        work.setReviewNote(reviewText.length() > 0 ? reviewText.toString() : null);
        work.setReviewerId(operatorId);
        work.setReviewTime(LocalDateTime.now());
        work.setModifyTime(LocalDateTime.now());
        ugcWorkMapper.updateById(work);
        createLog(id, "reject", reason, note, operatorId);
    }

    /**
     * 批量通过
     */
    @Transactional
    public void batchApprove(List<Long> ids, Long operatorId) {
        for (Long id : ids) {
            approve(id, null, operatorId);
        }
    }

    /**
     * 批量驳回
     */
    @Transactional
    public void batchReject(List<Long> ids, String reason, Long operatorId) {
        for (Long id : ids) {
            reject(id, reason, null, operatorId);
        }
    }

    /**
     * 撤回审核：已通过/已拒绝 → 待审核，重新进入审核队列（对齐设计文档，与下架 takedown 区分）
     */
    @Transactional
    public void revoke(Long id, Long operatorId) {
        UgcWork work = ugcWorkMapper.selectById(id);
        if (work == null) {
            throw new BusinessException(404, "作品不存在");
        }
        String current = work.getStatus();
        if (!WorkPublishStatus.PUBLISHED.getValue().equals(current)
                && !WorkPublishStatus.REJECTED.getValue().equals(current)) {
            throw BusinessException.of(ErrorCode.BAD_REQUEST, "当前状态不允许撤销审核");
        }
        LambdaUpdateWrapper<UgcWork> uw = new LambdaUpdateWrapper<>();
        uw.eq(UgcWork::getId, id)
                .set(UgcWork::getStatus, WorkPublishStatus.PENDING_REVIEW.getValue())
                .set(UgcWork::getReviewTime, null)
                .set(UgcWork::getReviewerId, null)
                .set(UgcWork::getReviewNote, null)
                .set(UgcWork::getModifyTime, LocalDateTime.now());
        if (WorkPublishStatus.PUBLISHED.getValue().equals(current)) {
            uw.set(UgcWork::getPublishTime, null);
        }
        ugcWorkMapper.update(null, uw);
        createLog(id, "revoke", null, null, operatorId);
    }

    /**
     * 下架
     */
    @Transactional
    public void takedown(Long id, String reason, Long operatorId) {
        UgcWork work = ugcWorkMapper.selectById(id);
        if (work == null) {
            throw new BusinessException(404, "作品不存在");
        }
        work.setStatus(WorkPublishStatus.UNPUBLISHED.getValue());
        work.setModifyTime(LocalDateTime.now());
        ugcWorkMapper.updateById(work);
        createLog(id, "takedown", reason, null, operatorId);
    }

    /**
     * 恢复
     */
    @Transactional
    public void restore(Long id, Long operatorId) {
        UgcWork work = ugcWorkMapper.selectById(id);
        if (work == null) {
            throw new BusinessException(404, "作品不存在");
        }
        work.setStatus(WorkPublishStatus.PUBLISHED.getValue());
        work.setModifyTime(LocalDateTime.now());
        ugcWorkMapper.updateById(work);
        createLog(id, "restore", null, null, operatorId);
    }

    /**
     * 切换推荐状态
     */
    @Transactional
    public Map<String, Object> toggleRecommend(Long id, Long operatorId) {
        UgcWork work = ugcWorkMapper.selectById(id);
        if (work == null) {
            throw new BusinessException(404, "作品不存在");
        }
        boolean newState = !Boolean.TRUE.equals(work.getIsRecommended());
        work.setIsRecommended(newState);
        work.setModifyTime(LocalDateTime.now());
        ugcWorkMapper.updateById(work);
        createLog(id, newState ? "recommend" : "unrecommend", null, null, operatorId);

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("isRecommended", newState);
        return result;
    }

    /**
     * 管理概览统计
     */
    public Map<String, Object> getManagementStats() {
        Map<String, Object> stats = new LinkedHashMap<>();
        stats.put("total", countByStatus(WorkPublishStatus.PUBLISHED.getValue()) + countByStatus(WorkPublishStatus.UNPUBLISHED.getValue()));
        LocalDateTime dayStart = LocalDate.now().atStartOfDay();
        stats.put("todayNew", ugcWorkMapper.selectCount(
                new LambdaQueryWrapper<UgcWork>()
                        .eq(UgcWork::getIsDeleted, 0)
                        .ge(UgcWork::getCreateTime, dayStart)
                        .in(UgcWork::getStatus, WorkPublishStatus.PUBLISHED.getValue(), WorkPublishStatus.UNPUBLISHED.getValue())));
        stats.put("totalViews", sumAllViewCounts());
        stats.put("pendingReview", countByStatus(WorkPublishStatus.PENDING_REVIEW.getValue()));
        stats.put("published", countByStatus(WorkPublishStatus.PUBLISHED.getValue()));
        stats.put("rejected", countByStatus(WorkPublishStatus.REJECTED.getValue()));
        stats.put("takenDown", countByStatus(WorkPublishStatus.UNPUBLISHED.getValue()));
        stats.put("recommended", ugcWorkMapper.selectCount(
                new LambdaQueryWrapper<UgcWork>()
                        .eq(UgcWork::getIsDeleted, 0)
                        .eq(UgcWork::getIsRecommended, true)));
        return stats;
    }

    /**
     * 获取审核日志
     */
    public PageResult<UgcReviewLog> getLogs(int page, int pageSize, Long workId) {
        LambdaQueryWrapper<UgcReviewLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UgcReviewLog::getTargetType, "work");
        if (workId != null) {
            wrapper.eq(UgcReviewLog::getWorkId, workId);
        }
        wrapper.orderByDesc(UgcReviewLog::getCreateTime);

        IPage<UgcReviewLog> result = ugcReviewLogMapper.selectPage(new Page<>(page, pageSize), wrapper);
        return PageResult.from(result);
    }

    private void applyWorkQueueSort(LambdaQueryWrapper<UgcWork> wrapper, String sortBy) {
        if ("hot".equals(sortBy)) {
            wrapper.orderByDesc(UgcWork::getLikeCount);
        } else if ("views".equals(sortBy)) {
            wrapper.orderByDesc(UgcWork::getViewCount);
        } else if ("oldest".equals(sortBy)) {
            wrapper.orderByAsc(UgcWork::getCreateTime);
        } else if ("latest".equals(sortBy) || !StringUtils.hasText(sortBy)) {
            wrapper.orderByDesc(UgcWork::getPublishTime);
            wrapper.orderByDesc(UgcWork::getCreateTime);
        } else {
            wrapper.orderByDesc(UgcWork::getCreateTime);
        }
    }

    /**
     * 解析筛选参数：单状态或逗号分隔多状态（如 published,taken_down）
     * status 字段已改为 VARCHAR，直接使用字符串枚举值
     */
    private List<String> parseStatusFilter(String status) {
        String[] parts = status.split(",");
        return Stream.of(parts)
                .map(String::trim)
                .filter(StringUtils::hasText)
                .flatMap(token -> resolveStatusValues(token).stream())
                .distinct()
                .collect(Collectors.toList());
    }

    private List<String> resolveStatusValues(String token) {
        switch (token) {
            case "pending_review":
                return List.of(WorkPublishStatus.PENDING_REVIEW.getValue());
            case "published":
                return List.of(WorkPublishStatus.PUBLISHED.getValue());
            case "rejected":
                return List.of(WorkPublishStatus.REJECTED.getValue());
            case "taken_down":
            case "unpublished":
                return List.of(WorkPublishStatus.UNPUBLISHED.getValue());
            case "draft":
                return List.of(WorkPublishStatus.DRAFT.getValue());
            default:
                return Collections.emptyList();
        }
    }

    private long countByStatus(String status) {
        return ugcWorkMapper.selectCount(
                new LambdaQueryWrapper<UgcWork>()
                        .eq(UgcWork::getIsDeleted, 0)
                        .eq(UgcWork::getStatus, status));
    }

    private long countTodayReviewLogs(LocalDateTime dayStart) {
        return ugcReviewLogMapper.selectCount(
                new LambdaQueryWrapper<UgcReviewLog>()
                        .eq(UgcReviewLog::getTargetType, "work")
                        .in(UgcReviewLog::getAction, "approve", "reject")
                        .ge(UgcReviewLog::getCreateTime, dayStart));
    }

    private long countTodayLogsByAction(String action, LocalDateTime dayStart) {
        return ugcReviewLogMapper.selectCount(
                new LambdaQueryWrapper<UgcReviewLog>()
                        .eq(UgcReviewLog::getTargetType, "work")
                        .eq(UgcReviewLog::getAction, action)
                        .ge(UgcReviewLog::getCreateTime, dayStart));
    }

    private long sumAllViewCounts() {
        List<Map<String, Object>> maps = ugcWorkMapper.selectMaps(
                new QueryWrapper<UgcWork>()
                        .select("IFNULL(SUM(view_count),0) AS sv")
                        .eq("is_deleted", 0));
        if (maps.isEmpty() || maps.get(0).get("sv") == null) {
            return 0L;
        }
        return ((Number) maps.get(0).get("sv")).longValue();
    }

    private void createLog(Long workId, String action, String reason, String note, Long operatorId) {
        UgcReviewLog logEntry = new UgcReviewLog();
        logEntry.setTargetType("work");
        logEntry.setTargetId(workId);
        logEntry.setWorkId(workId);
        logEntry.setAction(action);
        logEntry.setReason(reason);
        logEntry.setNote(note);
        logEntry.setOperatorId(operatorId);
        logEntry.setCreateTime(LocalDateTime.now());
        ugcReviewLogMapper.insert(logEntry);
    }

    private Map<String, Object> buildReviewWorkVo(UgcWork work) {
        Map<String, Object> vo = new LinkedHashMap<>();
        vo.put("id", work.getId());
        vo.put("title", work.getTitle());
        vo.put("coverUrl", work.getCoverUrl());
        vo.put("description", work.getDescription());
        vo.put("statusCode", work.getLeaiStatus());
        vo.put("status", work.getStatus());
        vo.put("visibility", work.getVisibility());
        vo.put("isRecommended", work.getIsRecommended());
        vo.put("viewCount", work.getViewCount());
        vo.put("likeCount", work.getLikeCount());
        vo.put("favoriteCount", work.getFavoriteCount());
        vo.put("reviewNote", work.getReviewNote());
        vo.put("reviewTime", work.getReviewTime());
        vo.put("publishTime", work.getPublishTime());
        vo.put("createTime", work.getCreateTime());

        // 补充作者信息（user 与 creator 同构，便于前端组件复用）
        if (work.getUserId() != null) {
            SysUser user = sysUserMapper.selectById(work.getUserId());
            if (user != null) {
                Map<String, Object> userInfo = new LinkedHashMap<>();
                userInfo.put("id", user.getId());
                userInfo.put("username", user.getUsername());
                userInfo.put("nickname", user.getNickname());
                userInfo.put("avatar", user.getAvatar());
                vo.put("user", userInfo);
                vo.put("creator", userInfo);
            }
        }
        return vo;
    }
}
