package ink.wgink.module.file.service.v2.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.common.rpc.rest.pojo.RemoteFileInputStream;
import ink.wgink.exceptions.FileException;
import ink.wgink.exceptions.SearchException;
import ink.wgink.module.file.components.FileComponent;
import ink.wgink.module.file.dao.IFileDao;
import ink.wgink.module.file.enums.UploadTypeEnum;
import ink.wgink.module.file.pojo.dtos.FileInfoDTO;
import ink.wgink.module.file.pojo.dtos.v2.FileUploadSuccessDTO;
import ink.wgink.module.file.pojo.vos.v2.FileSaveVO;
import ink.wgink.module.file.pojo.vos.v2.FileUpdateVO;
import ink.wgink.module.file.remote.IFileCenterRemoteService;
import ink.wgink.module.file.service.filedownload.IFileDownloadService;
import ink.wgink.module.file.service.v2.IFileService;
import ink.wgink.module.file.utils.FileUtil;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.pos.FilePO;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.properties.FileCenterProperties;
import ink.wgink.properties.FileProperties;
import ink.wgink.util.UUIDUtil;
import ink.wgink.util.date.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @ClassName: FileV2ServiceImpl
 * @Description: 文件V2
 * @Author: wanggeng
 * @Date: 2022/4/13 16:15
 * @Version: 1.0
 */
@Service("fileServiceV2")
public class FileServiceImpl extends DefaultBaseService implements IFileService {

    @Autowired
    private FileProperties fileProperties;
    @Autowired
    private FileComponent fileComponent;
    @Autowired
    private IFileDao fileDao;
    @Autowired
    private IFileDownloadService fileDownloadService;
    @Autowired
    private IFileCenterRemoteService fileUploadCenterService;

    @Override
    public FileUploadSuccessDTO uploadSingle(MultipartFile uploadFile, UploadTypeEnum uploadTypeEnum) {
        FileSaveVO fileSaveVO = getCenterFileSaveVO(uploadFile, uploadTypeEnum, securityComponent.getCurrentUser().getUserId());
        return saveFile(fileSaveVO);
    }

    @Override
    public FileUploadSuccessDTO uploadSingle(InputStream inputStream, UploadTypeEnum uploadTypeEnum, String fileName) {
        FileSaveVO fileSaveVO = getCenterFileSaveVO(inputStream, uploadTypeEnum, fileName, securityComponent.getCurrentUser().getUserId());
        return saveFile(fileSaveVO);
    }


    @Override
    public FileUploadSuccessDTO uploadSingleByToken(String token, MultipartFile uploadFile, UploadTypeEnum uploadTypeEnum) {
        FileSaveVO fileSaveVO = getCenterFileSaveVO(uploadFile, uploadTypeEnum, getAppTokenUser(token).getId());
        return saveFile(fileSaveVO);
    }

    @Override
    public FileUploadSuccessDTO uploadSingleByToken(String token, InputStream inputStream, UploadTypeEnum uploadTypeEnum, String fileName) {
        FileSaveVO fileSaveVO = getCenterFileSaveVO(inputStream, uploadTypeEnum, fileName, getAppTokenUser(token).getId());
        return saveFile(fileSaveVO);
    }

    @Override
    public FileUploadSuccessDTO uploadSingleByUserId(String userId, MultipartFile uploadFile, UploadTypeEnum uploadTypeEnum) {
        FileSaveVO fileSaveVO = getCenterFileSaveVO(uploadFile, uploadTypeEnum, userId);
        return saveFile(fileSaveVO);
    }

    @Override
    public FileUploadSuccessDTO uploadSingleByUserId(String userId, InputStream inputStream, UploadTypeEnum uploadTypeEnum, String fileName) {
        FileSaveVO fileSaveVO = getCenterFileSaveVO(inputStream, uploadTypeEnum, fileName, userId);
        return saveFile(fileSaveVO);
    }

    @Override
    public FileUploadSuccessDTO saveFile(FileSaveVO fileSaveVO) {
        String fileId = UUIDUtil.getUUID();
        Map<String, Object> params = getHashMap(10);
        params.put("fileId", fileId);
        params.put("fileName", fileSaveVO.getFileName());
        params.put("filePath", fileSaveVO.getUploadPath());
        params.put("fileUrl", fileSaveVO.getFileUrl());
        params.put("fileType", fileSaveVO.getFileType());
        params.put("fileSize", fileSaveVO.getFileSize());
        params.put("fileSummary", fileSaveVO.getFileSummary());
        params.put("isBack", 0);

        String time = DateUtil.getTime();
        params.put("creator", fileSaveVO.getCreator());
        params.put("modifier", fileSaveVO.getCreator());
        params.put("gmtCreate", time);
        params.put("gmtModified", time);
        params.put("isDelete", 0);
        fileDao.save(params);

        return new FileUploadSuccessDTO(fileId, fileSaveVO.getFileName(), fileSaveVO.getFileSize(), fileSaveVO.getFileUrl());
    }

    @Override
    public void update(FileUpdateVO fileUpdateVO) {
        Map<String, Object> params = getHashMap(10);
        params.put("fileId", fileUpdateVO.getFileId());
        params.put("fileName", fileUpdateVO.getFileName());
        params.put("filePath", fileUpdateVO.getUploadPath());
        params.put("fileUrl", fileComponent.getFileUrl(fileUpdateVO.getUploadPath()));
        params.put("fileType", fileUpdateVO.getFileType());
        params.put("fileSize", fileUpdateVO.getFileSize());
        params.put("modifier", fileUpdateVO.getCreator());
        params.put("gmtModified", DateUtil.getTime());
        fileDao.update(params);
    }

    @Override
    public void delete(List<String> fileIds) {
        if (fileIds.isEmpty()) {
            return;
        }
        Map<String, Object> params = getHashMap(2);
        params.put("fileIds", fileIds);
        List<FilePO> filePOS = fileDao.listPO(params);
        // 删除源文件
        filePOS.forEach(filePO -> {
            File file = new File(filePO.getFilePath());
            if (!file.exists()) {
                return;
            }
            file.delete();
        });
        // 删除记录
        fileDao.delete(params);
    }

    @Override
    public FilePO getPO(Map<String, Object> params) {
        return fileDao.getPO(params);
    }

    @Override
    public FilePO getPO(String fileId) {
        Map<String, Object> params = getHashMap(2);
        params.put("fileId", fileId);
        return getPO(params);
    }

    @Override
    public void downloadRedirect(HttpServletRequest request, HttpServletResponse response, boolean isOpen, String fileId) {
        FilePO filePO = getPO(fileId);
        if (filePO == null) {
            throw new FileException("查询失败");
        }
        File file = new File(filePO.getFilePath());
        if (!file.exists()) {
            throw new FileException("文件不存在");
        }
        fileDownloadService.downloadRedirect(request, response, isOpen, filePO);
    }

    @Override
    public void download(HttpServletRequest request, HttpServletResponse response, String fileId) {
        FilePO filePO = getPO(fileId);
        if (filePO == null) {
            throw new FileException("查询失败");
        }
        File file = new File(filePO.getFilePath());
        if (!file.exists()) {
            throw new FileException("文件不存在");
        }
        fileDownloadService.download(request, response, filePO);
    }

    @Override
    public List<FileInfoDTO> list(Map<String, Object> params) {
        params = params == null ? getHashMap(0) : params;
        setQueryFileType(params);
        List<FileInfoDTO> fileInfoDTOs = fileDao.listInfo(params);
        setDownloadCount(fileInfoDTOs);
        return fileInfoDTOs;
    }

    @Override
    public SuccessResultList<List<FileInfoDTO>> listPage(ListPage page) {
        PageHelper.startPage(page.getPage(), page.getRows());
        List<FileInfoDTO> fileInfoDTOs = list(page.getParams());
        setDownloadCount(fileInfoDTOs);
        PageInfo<FileInfoDTO> pageInfo = new PageInfo<>(fileInfoDTOs);
        return new SuccessResultList<>(fileInfoDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    @Override
    public FileSaveVO getCenterFileSaveVO(InputStream inputStream, UploadTypeEnum uploadTypeEnum, String fileName, String creator) {
        String fileType = fileComponent.getFileType(fileName);
        String uploadPath = fileComponent.getUploadPath(uploadTypeEnum, fileType);
        String uuidFileName = UUIDUtil.get32UUID() + "." + fileType;
        long fileSize = FileUtil.save(inputStream, uuidFileName, uploadPath);
        // 保存文件
        FileSaveVO fileSaveVO = new FileSaveVO();
        fileSaveVO.setFileName(fileName);
        fileSaveVO.setFileType(fileType);
        fileSaveVO.setUploadPath(uploadPath + File.separator + uuidFileName);
        fileSaveVO.setFileUrl(fileComponent.getFileUrl(fileSaveVO.getUploadPath()));
        fileSaveVO.setFileSize(fileSize);
        fileSaveVO.setCreator(creator);
        fileSaveVO.setFileSummary(FILE_SUMMARY_LOCAL);
        return fileSaveVO;
    }

    /**
     * 设置查询文件类型
     *
     * @param params
     */
    private void setQueryFileType(Map<String, Object> params) {
        String fileType = (String) params.get("fileType");
        if (StringUtils.isBlank(fileType)) {
            return;
        }
        List<String> fileTypes;
        if (StringUtils.equals("image", fileType)) {
            fileTypes = Arrays.asList(fileComponent.getImageTypes());
        } else if (StringUtils.equals("video", fileType)) {
            fileTypes = Arrays.asList(fileComponent.getVideoTypes());
        } else if (StringUtils.equals("audio", fileType)) {
            fileTypes = Arrays.asList(fileComponent.getAudioTypes());
        } else if (StringUtils.equals("file", fileType)) {
            fileTypes = Arrays.asList(fileComponent.getFileTypes());
        } else {
            fileTypes = new ArrayList<>();
        }
        params.put("fileTypes", fileTypes);
    }

    /**
     * 设置下载次数
     *
     * @param fileInfoDTOs
     */
    private void setDownloadCount(List<FileInfoDTO> fileInfoDTOs) {
        fileInfoDTOs.forEach(fileInfoDTO -> {
            Integer downloadCount = fileDownloadService.countByFileId(fileInfoDTO.getFileId());
            fileInfoDTO.setDownloadCount(downloadCount);
        });
    }

    /**
     * 获取文件保存VO
     *
     * @param uploadFile
     * @param uploadTypeEnum
     * @return
     */
    private FileSaveVO getCenterFileSaveVO(MultipartFile uploadFile, UploadTypeEnum uploadTypeEnum, String creator) {
        String fileName = uploadFile.getOriginalFilename();
        InputStream inputStream;
        try {
            inputStream = uploadFile.getInputStream();
        } catch (IOException e) {
            throw new SearchException(e);
        }
        // 上传到文件中心
        if (fileProperties.getCenter() != null) {
            return getCenterFileSaveVO(inputStream, uploadTypeEnum, fileName, uploadFile.getSize(), creator);
        }
        return getCenterFileSaveVO(inputStream, uploadTypeEnum, fileName, creator);
    }

    /**
     * 上传文件到文件中心
     *
     * @param inputStream
     * @param uploadTypeEnum
     * @param fileName
     * @param fileSize
     * @param creator
     * @return
     */
    private FileSaveVO getCenterFileSaveVO(InputStream inputStream, UploadTypeEnum uploadTypeEnum, String fileName, long fileSize, String creator) {
        RemoteFileInputStream remoteFileInputStream = new RemoteFileInputStream();
        remoteFileInputStream.setInputStream(inputStream);
        remoteFileInputStream.setFileName(fileName);
        remoteFileInputStream.setFileSize(fileSize);

        String fileType = fileComponent.getFileType(fileName);
        FileCenterProperties fileCenterProperties = fileProperties.getCenter();
        FileUploadSuccessDTO fileUploadSuccessDTO;
        if (UploadTypeEnum.IMAGE.equals(uploadTypeEnum)) {
            fileUploadSuccessDTO = fileUploadCenterService.uploadImage(fileCenterProperties.getUploadUrl(),
                    fileCenterProperties.getAccessKey(),
                    fileCenterProperties.getAccessSecret(),
                    remoteFileInputStream,
                    creator);
        } else if (UploadTypeEnum.VIDEO.equals(uploadTypeEnum)) {
            fileUploadSuccessDTO = fileUploadCenterService.uploadVideo(fileCenterProperties.getUploadUrl(),
                    fileCenterProperties.getAccessKey(),
                    fileCenterProperties.getAccessSecret(),
                    remoteFileInputStream,
                    creator);
        } else if (UploadTypeEnum.AUDIO.equals(uploadTypeEnum)) {
            fileUploadSuccessDTO = fileUploadCenterService.uploadAudio(fileCenterProperties.getUploadUrl(),
                    fileCenterProperties.getAccessKey(),
                    fileCenterProperties.getAccessSecret(),
                    remoteFileInputStream,
                    creator);
        } else {
            fileUploadSuccessDTO = fileUploadCenterService.uploadFile(fileCenterProperties.getUploadUrl(),
                    fileCenterProperties.getAccessKey(),
                    fileCenterProperties.getAccessSecret(),
                    remoteFileInputStream,
                    creator);
        }

        FileSaveVO fileSaveVO = new FileSaveVO();
        fileSaveVO.setUploadPath(fileCenterProperties.getUploadUrl());
        fileSaveVO.setFileUrl(fileUploadSuccessDTO.getFileUrl());
        fileSaveVO.setFileType(fileType);
        fileSaveVO.setFileSize(fileSize);
        fileSaveVO.setFileName(fileName);
        fileSaveVO.setCreator(creator);
        fileSaveVO.setFileSummary(FILE_SUMMARY_CENTER);
        return fileSaveVO;
    }

}
