package com.keyware.shandan.control;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.keyware.shandan.bianmu.entity.DirectoryVo;
import com.keyware.shandan.bianmu.service.DirectoryService;
import com.keyware.shandan.frame.properties.CustomProperties;
import com.keyware.shandan.system.entity.SysFile;
import com.keyware.shandan.system.entity.SysUser;
import com.keyware.shandan.system.service.SysFileService;
import com.keyware.shandan.system.service.SysUserService;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 用于对文件进行失效验证
 */
@Slf4j
@Component
public class InvalidFileHandler {
    private final String storagePath;
    private final SysUserService userService;
    private final DirectoryService directoryService;
    private final SysFileService fileService;

    private final ConcurrentHashMap<String, InvalidItem> cache = new ConcurrentHashMap<>();

    public InvalidFileHandler(CustomProperties customProperties,
                              SysUserService userService,
                              DirectoryService directoryService,
                              SysFileService fileService) {
        this.userService = userService;
        this.directoryService = directoryService;
        this.fileService = fileService;
        this.storagePath = customProperties.getFileStorage().getPath();
    }

    /**
     * 开始验证
     */
    public void startValid() {
        log.info("文件校验处理器启动成功");
        new Thread(() -> {
            while (true) {
                refreshInvalidCache("ROOT");
                try {
                    Thread.sleep(1000 * 10);// 1小时执行一次
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
    }

    /**
     * 刷新失效文件的缓存
     *
     * @param dirId 指定目录ID
     */
    public void refreshInvalidCache(String dirId) {
        if (!StringUtils.hasText(dirId)) {
            dirId = "ROOT";
        }
        Set<String> idSet = new HashSet<>();
        directoryService.handlerAllChildrenListById(dirId, (context) -> {
            DirectoryVo dir = context.getResultObject();
            if (StringUtils.hasText(dir.getResourceId())) {
                // 查询对应的文件资源
                SysFile sf = fileService.getById(dir.getResourceId());
                if (sf != null) {
                    File file = new File(storagePath + File.separator + sf.getPath());
                    if (!file.exists()) {
                        SysUser user = userService.getById(sf.getModifyUser());
                        InvalidItem item = InvalidItem.builder()
                                .id(sf.getId())
                                .dirId(dir.getId())
                                .directoryPath(dir.getDirectoryPath())
                                .fileName(sf.getFileName())
                                .fileType(sf.getFileType())
                                .fileSize(sf.getFileSize())
                                .createTime(DateUtil.format(sf.getModifyTime(), "yyyy-MM-dd HH:mm"))
                                .createUser(user == null ? sf.getModifyUser() : user.getUserName())
                                .build();
                        cache.put(sf.getId(), item);
                        idSet.add(sf.getId());
                    }
                }
            }
        });

        // 与新的结果进行比对，将结果中不存在的缓存清除掉
        List<String> keys = new ArrayList<>();
        cache.forEachKey(1, keys::add);
        keys.forEach(key -> {
            if (!idSet.contains(key)) {
                cache.remove(key);
            }
        });
    }

    /**
     * 检索指定目录下的失效文件
     *
     * @param dirId   目录ID
     * @param refresh 是否重新刷新
     * @return
     */
    public List<InvalidItem> listByDir(String dirId, boolean refresh) {
        DirectoryVo dir = directoryService.getById(dirId);
        Assert.notNull(dir, "查询的目录不存在");
        if (refresh) {
            refreshInvalidCache(dirId);
        }
        String path = dir.getDirectoryPath();
        return cache.values().stream().filter(item -> item.getDirectoryPath().startsWith(path + "/")).collect(Collectors.toList());
    }

    /**
     * 清理文件数据
     *
     * @param fileId 文件ID
     */
    public void clean(String fileId) {
        fileService.deleteById(fileId);
        cleanDirectory(fileId);
        cache.remove(fileId);
    }

    /**
     * 移除指定文件的缓存
     *
     * @param fileId 文件ID
     */
    public void removeCache(String fileId) {
        cache.remove(fileId);
    }

    /**
     * 递归清理文件管理的目录资源，以及引用的资源
     *
     * @param resourceId
     */
    private void cleanDirectory(String resourceId) {
        LambdaQueryWrapper<DirectoryVo> query = new LambdaQueryWrapper<>();
        query.eq(DirectoryVo::getResourceId, resourceId);
        List<DirectoryVo> dirs = directoryService.list(query);
        dirs.forEach(dir -> {
            cleanDirectory(dir.getId());
            directoryService.deleteById(dir.getId());
        });
    }

    /**
     * 失效的缓存项
     */
    @Data
    @Builder
    public static class InvalidItem {
        private String id;
        private String dirId;
        private String directoryPath;
        private String fileName;
        private String fileType;
        private Double fileSize;
        private String createTime;
        private String createUser;
    }
}
