package cn.ey.biz.module.system.service.file;

import cn.ey.biz.common.pojo.PageResult;
import cn.ey.biz.common.util.io.FileUtils;
import cn.ey.biz.framework.file.core.client.FileClient;
import cn.ey.biz.framework.file.core.utils.FileTypeUtils;
import cn.ey.biz.module.system.api.file.dto.FileRespDTO;
import cn.ey.biz.module.system.controller.admin.file.vo.file.FilePageReqVO;
import cn.ey.biz.module.system.convert.file.FileConvert;
import cn.ey.biz.module.system.dal.dataobject.file.FileDO;
import cn.ey.biz.module.system.dal.mapper.file.FileMapper;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static cn.ey.biz.common.exception.util.ServiceExceptionUtil.exception;
import static cn.ey.biz.module.system.enums.ErrorCodeConstants.*;

/**
 * 文件 Service 实现类
 *
 */
@Service
@Slf4j
public class FileServiceImpl implements FileService {

    @Resource
    private FileConfigService fileConfigService;

    @Resource
    private FileMapper fileMapper;

    @Override
    public PageResult<FileDO> getFilePage(FilePageReqVO pageReqVO) {
        return fileMapper.selectPage(pageReqVO);
    }

    @Override
    @SneakyThrows
    public FileDO createFile(String name, String path, byte[] content,String fileType) {
        // 计算默认的 path 名
        String type = FileTypeUtils.getMineType(content, name);
        if (StrUtil.isEmpty(path)) {
            // path = FileUtils.generatePath(content, name);
            path = FileUtils.generateSimplePath(content, name);
        }
        // 如果 name 为空，则使用 path 填充
        if (StrUtil.isEmpty(name)) {
            name = path;
        }

        // 上传到文件存储器
        FileClient client = fileConfigService.getMasterFileClient();
        Assert.notNull(client, "客户端(master) 不能为空");
        String url = client.upload(content, path);

        // 保存到数据库
        FileDO file = new FileDO();
        file.setConfigId(client.getId());
        file.setName(name);
        file.setPath(path);
        file.setUrl(url);
        file.setType(type);
        file.setSize(content.length);
        file.setFileType(fileType);
        fileMapper.insert(file);
        return file;
    }

    @Override
    public  List<FileDO> batchCreateFile(MultipartFile[] files)  {
       //1、校验
        if(files==null && files.length==0){
            throw  exception(FILE_IS_EMPTY);
        }
        //2、批量上传
        List<FileDO> fileDOS=new ArrayList<>();
        try {
            for (int i = 0; i < files.length; i++){
                FileDO fileDO = this.createFile(files[i].getOriginalFilename(), null,
                                                IoUtil.readBytes(files[i].getInputStream()),null);
                fileDOS.add(fileDO);
            }
        }  catch (Exception e) {
            //3.如果批量上传时，某个失败，则整个回滚
            fileDOS.forEach(fileDO->{
                try {
                    deleteFile(fileDO.getId());
                } catch (Exception exception) { }

            });
            fileDOS.clear();
            log.error("batch upload file error："+e.getMessage());
            throw exception(FILE_BATCH_UPLOAD_ERROR);

        }

        return fileDOS;
    }

    @Override
    public void deleteFile(Long id) throws Exception {
        // 校验存在
        FileDO file = this.validateFileExists(id);

        // 从文件存储器中删除
        FileClient client = fileConfigService.getFileClient(file.getConfigId());
        Assert.notNull(client, "客户端({}) 不能为空", file.getConfigId());
        client.delete(file.getPath());

        // 删除记录
        fileMapper.deleteById(id);
    }

    private FileDO validateFileExists(Long id) {
        FileDO fileDO = fileMapper.selectById(id);
        if (fileDO == null) {
            throw exception(FILE_NOT_EXISTS);
        }
        return fileDO;
    }

    @Override
    public byte[] getFileContent(Long configId, String path) throws Exception {
        FileClient client = fileConfigService.getFileClient(configId);
        Assert.notNull(client, "客户端({}) 不能为空", configId);
        return client.getContent(path);
    }

    @Override
    public FileDO getFile(Long configId, String path){
       return fileMapper.selectOne(FileDO::getConfigId,configId,FileDO::getPath,path);
    }

    @Override
    public FileDO getFile(String name) {
        LambdaQueryWrapper<FileDO> wrappers = Wrappers.lambdaQuery(FileDO.class)
                .eq(FileDO::getName, name);
        List<FileDO> fileDOList=fileMapper.selectList(wrappers);
        if(fileDOList!=null &&fileDOList.size()>0){
            return fileDOList.get(0);
        }
        return null;
    }

    @Override
    public FileRespDTO getFileId(Long id) {
        LambdaQueryWrapper<FileDO> wrappers = Wrappers.lambdaQuery(FileDO.class)
                .eq(FileDO::getId, id);
        List<FileDO> fileDOList=fileMapper.selectList(wrappers);
        if(fileDOList!=null &&fileDOList.size()>0){
            return  FileConvert.INSTANCE.convertFile(fileDOList.get(0));
        }
        return null;
    }

    @Override
    public List<FileDO> getFileList(String fileType){
        LambdaQueryWrapper<FileDO> wrappers = Wrappers.lambdaQuery(FileDO.class)
                .eq(FileDO::getFileType, fileType);
        List<FileDO> fileDOList=fileMapper.selectList(wrappers);
        return  fileDOList;
    }

    @Override
    public FileRespDTO getByFileType(String fileType) throws Exception {
        List<FileDO> fileDOList=getFileList(fileType);
        if(CollectionUtil.isNotEmpty(fileDOList)){
            FileDO fileDO=fileDOList.get(0);
            byte[] content=getFileContent(StringCutOut(fileDO.getUrl()),fileDO.getPath());
            FileRespDTO fileRespDTO=FileConvert.INSTANCE.convertFile(fileDO);
            fileRespDTO.setContent(content);
            fileRespDTO.setFile(byteTransitionFile(content,fileDO.getName()));
            return fileRespDTO;
        }
        return null;
    }

    /**
     * 取出url中的数据
     * @param text3
     * @return
     */
    public Long StringCutOut(String text3){
        String reg3 = "(?<=/file/)[\\s\\S]*(?=/get/)";
        Pattern p3 = Pattern.compile(reg3);
        Matcher m3 = p3.matcher(text3);
        if(m3.find()){
            System.out.println(m3.group());
            return Long.valueOf(m3.group());
        }
        return null;
    }

    /**
     * byte[] 转  File
     * @param bytes
     * @param fileName
     * @return
     */
    public File byteTransitionFile(byte[] bytes,String fileName) {
        try {
            File file = new File(fileName);
            FileOutputStream outputStream = new FileOutputStream(file);
            outputStream.write(bytes);
            outputStream.close();
            return file;
        } catch (IOException e) {
            log.error("写入文件时出错：" + e.getMessage());
        }
        return null;
    }

}
