
package com.seer.teach.teacher.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import  com.seer.teach.teacher.common.dto.ReadingStatusDTO;
import com.seer.teach.common.dto.mq.WordItem;
import com.seer.teach.common.enums.BookIsFreeEnums;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.enums.teacher.SmartReadEnum;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.teacher.common.req.AppBookReadReq;
import com.seer.teach.teacher.common.resp.*;
import com.seer.teach.teacher.common.utils.UserStatusCacheUtils;
import com.seer.teach.teacher.convert.BookConvert;
import com.seer.teach.teacher.module.entity.*;
import com.seer.teach.teacher.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 阅读书籍相关服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ReadBookServiceImpl implements ReadBookService {

    private final TreasuryArticleReadDurationsService treasuryArticleReadDurationsService;

    private final TreasuryBoxArticleAudioWordsService treasuryBoxArticleAudioWordsService;

    private final TreasuryBoxArticleAudiosService treasuryBoxArticleAudiosService;

    private final BookChapterAudioWordsService bookChapterAudioWordsService;

    private final static String HISTORY_DESC = "您上次听书到 -- 《%s》%s ~";

    private final TreasuryBoxArticlesService treasuryBoxArticlesService;

    private final BookChapterAudiosService bookChapterAudiosService;

    private final ReadingRecordsService readingRecordsService;

    private final BookChaptersService bookChaptersService;

    private final MyBooksService myBooksService;

    private final BooksService booksService;

    /**
     * 获取用户最近一次阅读历史信息
     *
     * @return 返回用户的最新阅读历史信息，包括是否成功、章节ID及描述文本
     */
    @Override
    public BookHistoryResp getUserHistory() {
        // 获取当前登录用户ID
        Integer userId = StpUtil.getLoginIdAsInt();
        // 查询用户最新的阅读记录
        ReadingRecordsEntity history = readingRecordsService.lambdaQuery().eq(ReadingRecordsEntity::getUserId, userId).orderByDesc(ReadingRecordsEntity::getLastReadTime).last("limit 1").one();
        if (Objects.isNull(history)) {
            return new BookHistoryResp(false, null, null);
        }
        // 查询对应章节信息
        BookChaptersEntity chapter = bookChaptersService.getById(history.getChapterId());
        if (Objects.isNull(chapter)) {
            return new BookHistoryResp(false, null, null);
        }
        // 查询书籍信息
        BooksEntity book = booksService.getById(history.getBookId());
        if (Objects.isNull(book)) {
            return new BookHistoryResp(false, null, null);
        }
        // 构造并返回响应数据
        String desc = String.format(HISTORY_DESC, book.getTitle(), chapter.getTitle());
        return new BookHistoryResp(true, chapter.getId(), desc);
    }

    /**
     * 分页查询指定用户的最新阅读记录列表
     *
     * @param page   分页参数对象
     * @param userId 用户ID
     * @return 返回分页后的阅读记录列表
     */
    @Override
    public Page<ReadingRecordsEntity> getLatestReadingByUser(Page<ReadingRecordsEntity> page, Integer userId) {
        return readingRecordsService.getLatestReadingByUser(page, userId);
    }

    /**
     * 根据书籍ID集合批量获取书籍实体列表
     *
     * @param bookIds 书籍ID集合
     * @return 返回与给定ID匹配的书籍实体列表
     */
    @Override
    public List<BooksEntity> getBookByIds(List<Integer> bookIds) {
        return booksService.listByIds(bookIds);
    }

    /**
     * 统计当前用户拥有的书籍总数（包括免费书籍、我的书籍以及宝箱文章）
     *
     * @return 当前用户拥有的书籍总数量
     */
    @Override
    public Integer getUserBookCount() {
        Integer userId = StpUtil.getLoginIdAsInt();
        // 免费书籍的数量
        Long count = booksService.lambdaQuery().eq(BooksEntity::getIsFree, BookIsFreeEnums.DISABLED.getCode()).count();
        // 我的书籍数量
        Long myBook = myBooksService.lambdaQuery().eq(MyBooksEntity::getUserId, userId).count();
        // 宝箱中的文章数量
        Long article = treasuryBoxArticlesService.lambdaQuery().count();
        return Math.toIntExact(count + myBook + article);
    }

    /**
     * 分页查询健康知识类型的文章列表（type=2）
     *
     * @param page 分页参数对象
     * @return 返回符合条件的健康知识文章分页结果
     */
    @Override
    public IPage<TreasuryBoxArticlesEntity> healthKnowPage(IPage<TreasuryBoxArticlesEntity> page) {
        return treasuryBoxArticlesService.page(page, new LambdaQueryWrapper<TreasuryBoxArticlesEntity>().eq(TreasuryBoxArticlesEntity::getType, 2));
    }

    /**
     * 分页查询编程学习类型的文章列表（type=1）
     *
     * @param page 分页参数对象
     * @return 返回符合条件的编程学习文章分页结果
     */
    @Override
    public IPage<TreasuryBoxArticlesEntity> programming(IPage<TreasuryBoxArticlesEntity> page) {
        return treasuryBoxArticlesService.page(page, new LambdaQueryWrapper<TreasuryBoxArticlesEntity>().eq(TreasuryBoxArticlesEntity::getType, 1));
    }

    /**
     * 获取指定章节的信息
     *
     * @param id 章节ID
     * @return 包含书籍基本信息和章节列表的响应对象
     */
    @Override
    public AppChapterInfoResp chapters(Integer id) {
        BooksEntity book = booksService.getById(id);
        List<BookChaptersEntity> chapters = bookChaptersService.lambdaQuery().eq(BookChaptersEntity::getBookId, id).orderByAsc(BookChaptersEntity::getSort).list();
        List<ChapterInfoResp> result = BookConvert.INSTANCE.toChapterInfoList(chapters);
        return BookConvert.INSTANCE.toAppChapterInfoResp(book, result);
    }

    /**
     * 根据请求参数读取音频数据
     *
     * @param params 请求参数，包含类型和ID等信息
     * @return 音频数据列表，每项包含音频URL和对应的单词项列表
     */
    @Override
    public List<AudioData> read(AppBookReadReq params) {
        Integer userId = StpUtil.getLoginIdAsInt();
        if (SmartReadEnum.HEALTH.getType().equals(params.getType())
                || SmartReadEnum.PROGRAMMING.getType().equals(params.getType())) {
            return getArticleAudios(userId,params.getId());
        }
        return getBookAudios(params.getId(),userId);
    }

    /**
     * 获取文章类型的音频数据
     */
    private List<AudioData> getArticleAudios(Integer userId,Integer articleId) {
        List<TreasuryBoxArticleAudiosEntity> audios =
                treasuryBoxArticleAudiosService.getTreasuryBoxArticleAudios(articleId);
        AssertUtils.notEmpty(audios, ResultCodeEnum.INTERNAL_SERVER_ERROR);
        treasuryArticleReadDurationsService.insertRecord(userId,articleId);
        UserStatusCacheUtils.setReading(userId, ReadingStatusDTO.readTreasuryBox(articleId));
        return buildAudioData(
                audios,
                TreasuryBoxArticleAudiosEntity::getId,
                treasuryBoxArticleAudioWordsService::getTreasuryBoxArticleAudioWords,
                TreasuryBoxArticleAudioWordsEntity::getAudioId,
                TreasuryBoxArticleAudioWordsEntity::getResult
        );
    }

    /**
     * 获取书籍类型的音频数据
     */
    private List<AudioData> getBookAudios(Integer chapterId,Integer userId) {
        List<BookChapterAudiosEntity> audios =
                bookChapterAudiosService.getBookChapterAudios(chapterId, 0, 0);
        AssertUtils.notEmpty(audios, ResultCodeEnum.INTERNAL_SERVER_ERROR);
        Integer bookId = bookChaptersService.getById(chapterId).getBookId();
        readingRecordsService.insertRecord(userId,bookId,chapterId);
        UserStatusCacheUtils.setReading(userId, ReadingStatusDTO.smartRead(chapterId));
        return buildAudioData(
                audios,
                BookChapterAudiosEntity::getId,
                bookChapterAudioWordsService::getWordItemsByAudioId,
                BookChapterAudioWordsEntity::getAudioId,
                BookChapterAudioWordsEntity::getResult
        );
    }

    /**
     * 通用构建音频数据方法
     *
     * @param audios            音频实体列表
     * @param audioIdGetter     用于获取音频ID的函数
     * @param wordsFetcher      根据音频ID列表获取词项的方法
     * @param wordAudioIdGetter 词项实体中的 audioId 获取函数
     * @param wordJsonGetter    词项实体中 JSON 字符串获取函数
     */
    private <A, W> List<AudioData> buildAudioData(
            List<A> audios,
            Function<A, Integer> audioIdGetter,
            Function<List<Integer>, List<W>> wordsFetcher,
            Function<W, Integer> wordAudioIdGetter,
            Function<W, String> wordJsonGetter
    ) {
        List<Integer> audioIds = audios.stream()
                .map(audioIdGetter)
                .collect(Collectors.toList());
        Map<Integer, List<W>> wordsMap = wordsFetcher.apply(audioIds)
                .stream()
                .collect(Collectors.groupingBy(wordAudioIdGetter));
        return audios.stream()
                .map(audio -> {
                    Integer audioId = audioIdGetter.apply(audio);
                    List<W> words = wordsMap.getOrDefault(audioId, Collections.emptyList());
                    List<WordItem> wordItems = words.stream()
                            .flatMap(w -> parseWordItems(wordJsonGetter.apply(w)).stream())
                            .collect(Collectors.toList());
                    String url = null;
                    if (audio instanceof BookChapterAudiosEntity) {
                        url = ((BookChapterAudiosEntity) audio).getAudioUrl();
                    } else if (audio instanceof TreasuryBoxArticleAudiosEntity) {
                        url = ((TreasuryBoxArticleAudiosEntity) audio).getAudioUrl();
                    }
                    return new AudioData(url, wordItems);
                })
                .collect(Collectors.toList());
    }

    /**
     * JSON → WordItem
     */
    private List<WordItem> parseWordItems(String json) {
        return JSONUtil.toList(json, WordItem.class);
    }
}