package com.ruoyi.project.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.project.business.domain.TbArea;
import com.ruoyi.project.business.domain.dto.RemoveDirectoryDto;
import com.ruoyi.project.business.domain.train.TtFileDatabase;
import com.ruoyi.project.business.domain.train.TtFileDirectory;
import com.ruoyi.project.business.domain.vo.train.FileDataVisibleRangeVo;
import com.ruoyi.project.business.domain.vo.train.FileDatabaseReq;
import com.ruoyi.project.business.domain.vo.train.FileDatabaseRes;
import com.ruoyi.project.business.domain.vo.train.FileDatabaseVo;
import com.ruoyi.project.business.mapper.TtFileDatabaseMapper;
import com.ruoyi.project.business.service.ITbAreaService;
import com.ruoyi.project.business.service.train.ITtFileDatabaseService;
import com.ruoyi.project.business.service.train.ITtFileDirectoryService;
import com.ruoyi.project.config.AppConfig;
import com.ruoyi.project.system.domain.SysRole;
import com.ruoyi.project.system.service.ISysRoleService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author fangk
 * @description 针对表【tt_file_database】的数据库操作Service实现
 * @createDate 2024-05-20 15:28:25
 */
@Service
@RequiredArgsConstructor
public class TtFileDatabaseServiceImpl extends ServiceImpl<TtFileDatabaseMapper, TtFileDatabase>
        implements ITtFileDatabaseService {


    private final ITtFileDirectoryService fileDirectoryService;

    private final ITbAreaService areaService;

    private final ISysRoleService sysRoleService;

    @Override
    @Transactional
    public boolean add(FileDatabaseVo fileDatabaseVo) {
        String fileList = fileDatabaseVo.getFileList();
        String[] files = fileList.split(",");
        List<TtFileDatabase> fileDataList = new ArrayList<>();
        // SysDictData dict = new SysDictData();
        // dict.setDictType("database_file_type");
        // List<SysDictData> dicts = dictDataService.selectDictDataList(dict);
        // Set<String> fileTypeValues = dicts.stream().map(SysDictData::getDictValue).collect(Collectors.toSet());

        for (String file : files) {
            TtFileDatabase fileData = new TtFileDatabase();
            BeanUtils.copyProperties(fileDatabaseVo, fileData);
            // 获取文件名
            String fileName = file.substring(file.lastIndexOf("/") + 1);
            fileData.setFileName(fileName);
            // 获取文件类型   // 转换为小写
            String fileType = file.substring(file.lastIndexOf(".") + 1).toLowerCase();

            // if (!fileTypeValues.contains(fileType)) {
            //    fileType = "other";
            //}

            fileData.setFileType(fileType);
            fileData.setFilePath(file);

            // 设置所有人可读
            fileData.setVisibleRange1("*");
            fileData.setVisibleRange2("*");

            fileDataList.add(fileData);
        }
        return saveBatch(fileDataList);
    }

    @Override
    public List<FileDatabaseRes> selectTtFileDatabaseList(FileDatabaseReq req) {
        // List<TtFileDatabase> list = list(Wrappers.lambdaQuery(TtFileDatabase.class)
        //        .eq(req.getDirectoryId() != null, TtFileDatabase::getDirectoryId, req.getDirectoryId())
        //        .like(StringUtils.isNotBlank(req.getFileName()), TtFileDatabase::getFileName, req.getFileName())
        //        .eq(StringUtils.isNotBlank(req.getFileType()), TtFileDatabase::getFileType, req.getFileType())
        //        .between(req.getStartTime() != null && req.getEndTime() != null, TtFileDatabase::getCreateTime, req.getStartTime(), req.getEndTime())
        //);

        TtFileDirectory directory = fileDirectoryService.getById(req.getDirectoryId());
        if (directory != null && directory.getDerectoryName().equals(AppConfig.getDataFolder())) {
            req.setDirectoryId(null);
        }

        // 如果不是超级管理员和系统管理员，只能查看自己的区域和角色的资料库
        if (!SecurityUtils.isSuperOrSystemAdmin()) {
            // SysUser user = SecurityUtils.getLoginUser().getUser();
            // List<Long> roleIds = user.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList());
            List<String> roleKeys = SecurityUtils.getRoleKeys();
            roleKeys.add("*");
            List<String> areaIds = SecurityUtils.getAreaIds().stream().map(String::valueOf).collect(Collectors.toList());
            areaIds.add("*");
            // req.setRoleIds(roleIds);
            req.setRoleKeys(roleKeys);
            req.setAreaIds(areaIds);
        }

        // TODO 角色和区域可以使用内存化查询，其中区域已经缓存到内存
        PageUtils.startPage();
        List<FileDatabaseRes> list = baseMapper.selectTtFileDatabaseList(req);
        List<TbArea> areas = areaService.getAllAreaList();
        Map<Long, String> areaId2NameMapping = areas.stream().collect(Collectors.toMap(TbArea::getAreaId, TbArea::getAreaName));
        List<SysRole> roles = sysRoleService.selectRoleAll();
        Map<String, String> roleId2NameMapping = roles.stream().collect(Collectors.toMap(SysRole::getRoleKey, SysRole::getRoleName));
        for (FileDatabaseRes data : list) {
            // 设置区域名称   TODO 1. 抽取公共逻辑  2. 国际化 (暂时区域和角色名称不国际化)
            if (StringUtils.isNotBlank(data.getVisibleRange2())) {
                String areaNames = Arrays.stream(data.getVisibleRange2().split(","))
                        .filter(StringUtils::isNotBlank)
                        .map(item -> ("*".equals(item)) ? "所有区域" : areaId2NameMapping.get(Long.parseLong(item)))
                        .collect(Collectors.joining(","));
                data.setVisibleRange2Names(areaNames);
            }
            // 设置角色名称
            if (StringUtils.isNotBlank(data.getVisibleRange1())) {
                String roleNames = Arrays.stream(data.getVisibleRange1().split(","))
                        .filter(StringUtils::isNotBlank)
                        .map(item -> ("*".equals(item)) ? "所有角色" : roleId2NameMapping.get(item))
                        .collect(Collectors.joining(","));
                data.setVisibleRange1Names(roleNames);
            }
        }
        return list;

    }

    @Override
    public List<TtFileDatabase> getFileTypes() {
        Wrapper<TtFileDatabase> wrapper = Wrappers.lambdaQuery(TtFileDatabase.class).select(TtFileDatabase::getFileType).groupBy(TtFileDatabase::getFileType);
        List<TtFileDatabase> list = list(wrapper);
        // Set<String> collect = list.stream().map(TtFileDatabase::getFileType).collect(Collectors.toSet());
        return list.stream().distinct().collect(Collectors.toList());
        // return collect;
    }

    @SneakyThrows
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeDirectoryAndData(Long id) {
        // 删除目录及其子目录
        RemoveDirectoryDto dto = fileDirectoryService.removeDirectoryAndChildren(id);

        // 删除目录下的文件
        boolean r = remove(Wrappers.lambdaQuery(TtFileDatabase.class).in(TtFileDatabase::getDirectoryId, dto.getRemoveDirectoryIds()));

        // 移至回收站（不用保留目录结构）    // TODO  这两个 文件操作咋回滚
        FileUtils.transferDirectory(dto.getRemovePhysicalDirectory(), AppConfig.getRecyclePath(), true);

        // 删除物理目录
        FileUtils.removeDirectory(dto.getRemovePhysicalDirectory());

        return r;
    }

    @SneakyThrows
    @Override
    public boolean edit(TtFileDatabase ttFileDatabase) {
        TtFileDatabase origin = getById(ttFileDatabase.getId());
        boolean r = updateById(ttFileDatabase);

        if (!origin.getDirectoryId().equals(ttFileDatabase.getDirectoryId())) {
            String dataFolder = fileDirectoryService.getDataFolder(ttFileDatabase.getDirectoryId());
            String oldDataFolder = fileDirectoryService.getDataFolder(origin.getDirectoryId());
            Files.move(Paths.get(oldDataFolder, origin.getFileName()), Paths.get(dataFolder, origin.getFileName()));
        }

        return r;
    }

    @Override
    @Transactional
    public boolean editVisibleRange(FileDataVisibleRangeVo vo) {
        // 如果没有提供ids， 获取目录ids
        List<Long> ids = vo.getIds();
        List<TtFileDatabase> databaseList;
        if (CollectionUtils.isNotEmpty(ids)) {
            databaseList = list(Wrappers.lambdaQuery(TtFileDatabase.class).in(TtFileDatabase::getId, ids));
        } else {
            List<Long> directoryIds = vo.getDirectoryIds();
            if (CollectionUtils.isEmpty(directoryIds)) {
                throw new RuntimeException(MessageUtils.message("train.fileData.visibleRangeMsg"));
            }
            // 获取该目录下所有子目录
            List<TtFileDirectory> subDirectoryList = fileDirectoryService.getSubDirectoryWithSelf(directoryIds);
            List<Long> dIds = subDirectoryList.stream().map(TtFileDirectory::getId).collect(Collectors.toList());
            databaseList = list(Wrappers.lambdaQuery(TtFileDatabase.class).in(TtFileDatabase::getDirectoryId, dIds));
        }
        // for (TtFileDatabase d : databaseList) {
        //     d.setVisibleRange1(vo.getVisibleRange1());
        //     d.setVisibleRange2(vo.getVisibleRange2());
        // }

        List<Long> dataIds = databaseList.stream().map(TtFileDatabase::getId).collect(Collectors.toList());


        vo.setIds(dataIds);
        vo.setUpdateBy(SecurityUtils.getUserId());

        // 如果不是超级管理员和系统管理员，只能查看自己的区域和角色的资料库
        if (!SecurityUtils.isSuperOrSystemAdmin()) {
            // SysUser user = SecurityUtils.getLoginUser().getUser();
            // List<Long> roleIds = user.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList());
            // List<Long> areaIds = user.getAreaIdList();
            List<String> roleKeys = SecurityUtils.getRoleKeys();
            List<Long> areaIds = SecurityUtils.getAreaIds();
            vo.setRoleKeys(roleKeys);
            vo.setAreaIds(areaIds);
        }


        // return updateBatchById(databaseList);
        // LambdaUpdateWrapper<TtFileDatabase> set = Wrappers.lambdaUpdate(TtFileDatabase.class).in(TtFileDatabase::getId, dataIds)
        //         .set(TtFileDatabase::getVisibleRange1, vo.getVisibleRange1())
        //         .set(TtFileDatabase::getVisibleRange2, vo.getVisibleRange2())
        //         .last(" find_")
        //         ;
        // return update(set);

        if(StringUtils.isEmpty(vo.getVisibleRange1())){
            vo.setVisibleRange1("*");
        }
        if(StringUtils.isEmpty(vo.getVisibleRange2())){
            vo.setVisibleRange2("*");
        }
        Boolean res = baseMapper.editVisibleRange(vo) > 0;
        return res;
    }

    @Override
    public TtFileDatabase selectTtFileDatabaseById(Long trainId) {
        return baseMapper.selectTtFileDatabaseById(trainId);
    }

}




