package com.test.bijihoudaun.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.test.bijihoudaun.entity.ImageName;
import com.test.bijihoudaun.entity.MarkdownFile;
import com.test.bijihoudaun.entity.MarkdownFileVO;
import com.test.bijihoudaun.mapper.ImageNameMapper;
import com.test.bijihoudaun.mapper.MarkdownFileMapper;
import com.test.bijihoudaun.service.MarkdownFileService;
import com.test.bijihoudaun.util.MarkdownImageExtractor;
import com.test.bijihoudaun.util.SnowflakeIdGenerator;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

@Service
@Transactional
public class MarkdownFileServiceImpl
        extends ServiceImpl<MarkdownFileMapper, MarkdownFile>
        implements MarkdownFileService {

    @Autowired
    MarkdownFileMapper markdownFileMapper;
    @Resource
    ImageNameMapper imageNameMapper;
    @Resource
    SnowflakeIdGenerator snowflakeIdGenerator;


    @Override
    public MarkdownFile updateMarkdownContent(MarkdownFile markdownFile) {
        long id;
        markdownFile.setUpdatedAt(new Date());
        // 如果ID为空或0，则视为新文件
        if (ObjectUtil.isNull(markdownFile.getId()) || markdownFile.getId() == 0L) {
            long l = snowflakeIdGenerator.nextId();
            markdownFile.setId(l);
            markdownFile.setCreatedAt(new Date());
            this.save(markdownFile); // 使用MyBatis-Plus的save方法
            id=l;
        } else {
            this.updateById(markdownFile); // 使用MyBatis-Plus的updateById方法
            id=markdownFile.getId();
        }

        List<String> strings = MarkdownImageExtractor.extractImageFilenames(markdownFile.getContent());
        // 异步处理图片文件名同步
        syncImageNames(id, strings);
        return markdownFile;
    }
    
    @Override
    public MarkdownFile getMarkdownById(Long id, boolean isAuthenticated) {
        MarkdownFile file = this.getById(id);
        if (file != null && !isAuthenticated && file.getIsPrivate() != null && file.getIsPrivate() == 1) {
            // 对于未认证用户，私密笔记只返回标题，内容置空
            file.setContent("");
            return file;
        }
        return file;
    }

    
    @Override
    public List<MarkdownFileVO> getFilesByGroupingId(String groupingId) {
        return markdownFileMapper.selectByGroupingIdWithGrouping(groupingId);
    }
    
    @Override
    public boolean deleteMarkdownFile(Long id) {
        LambdaUpdateWrapper<MarkdownFile> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(MarkdownFile::getId, id)
                .set(MarkdownFile::getIsDeleted, 1)
                .set(MarkdownFile::getDeletedAt, new Date());
        return this.update(updateWrapper);
    }

    @Override
    public List<MarkdownFile> test() {
        return markdownFileMapper.selectList(null);
    }

    @Override
    public List<MarkdownFile> getAllMarkdownFiles() {
        return markdownFileMapper.selectList(null);
    }

    @Override
    public List<MarkdownFile> searchByTitle(String keyword) {
        QueryWrapper<MarkdownFile> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("title", keyword);
        return this.list(queryWrapper);
    }

    @Override
    public MarkdownFile updateMarkdownTitle(Long id, String title) {
        MarkdownFile file = this.getById(id);
        if (ObjectUtil.isNotNull(file)) {
            file.setTitle(title);
            file.setUpdatedAt(new Date());
            this.updateById(file);
        }
        return file;
    }

    @Override
    public List<MarkdownFileVO> getRecentFiles(int limit) {
        return markdownFileMapper.selectRecentWithGrouping(limit);
    }


    @Async("imageNameSyncExecutor")
    public void syncImageNames(Long markdownId, List<String> strings) {
        // 查询数据库中已存在的文件名
        List<ImageName> imageNames = imageNameMapper.selectList(new LambdaUpdateWrapper<ImageName>()
                .eq(ImageName::getMarkdownId, markdownId));
        
        // 若是数据库中的数据为null，则插入
        if (CollUtil.isEmpty(imageNames)) {
            if (CollUtil.isNotEmpty(strings)) {
                List<ImageName> list = strings.stream().map(fileName -> {
                    ImageName imageName = new ImageName();
                    imageName.setFileName(fileName);
                    imageName.setMarkdownId(markdownId);
                    return imageName;
                }).toList();
                // 批量插入新的文件名
                list.forEach(imageName -> imageNameMapper.insert(imageName));
            }
        } else {
            // 数据库中已有记录，需要对比处理
            // 获取数据库中的文件名列表
            List<String> dbFileNames = imageNames.stream()
                    .map(ImageName::getFileName)
                    .toList();

            // 找出需要新增的文件名（在strings中但不在数据库中）
            List<String> toInsert = strings.stream()
                    .filter(fileName -> !dbFileNames.contains(fileName))
                    .toList();

            // 找出需要删除的记录（在数据库中但不在strings中）
            List<ImageName> toDelete = imageNames.stream()
                    .filter(imageName -> !strings.contains(imageName.getFileName()))
                    .toList();

            // 插入新增的文件名
            if (CollUtil.isNotEmpty(toInsert)) {
                List<ImageName> insertList = toInsert.stream().map(fileName -> {
                    ImageName imageName = new ImageName();
                    imageName.setFileName(fileName);
                    imageName.setMarkdownId(markdownId);
                    return imageName;
                }).toList();

                imageNameMapper.insert(insertList);
            }

            // 删除不再需要的记录
            if (CollUtil.isNotEmpty(toDelete)) {
                List<Long> deleteIds = toDelete.stream()
                        .map(ImageName::getId)
                        .toList();
                imageNameMapper.deleteByIds(deleteIds);
            }
        }
    }

}
