package com.sckw.file.service;


import com.aliyun.oss.model.OSSObject;
import com.sckw.core.common.enums.NumberConstant;
import com.sckw.core.common.enums.StringConstant;
import com.sckw.core.common.enums.enums.FileEnum;
import com.sckw.core.model.file.FileInfo;
import com.sckw.core.utils.FileUtils;
import com.sckw.core.utils.IdWorker;
import com.sckw.core.utils.StringUtils;
import com.sckw.core.web.constant.HttpStatus;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.HttpResult;
import com.sckw.file.api.dto.FileInfoDTO;
import com.sckw.file.dao.KwsFileInfoDao;
import com.sckw.file.model.kwfFileInfo;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
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 org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.zip.Adler32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


/**
 * @author lfdc
 * @version 1.0
 * @className FileService
 * @description 文件上传下载service
 * @company sckw
 * @date 2023-06-02 16:06:46
 */
@Slf4j
@Service
public class FileService {

    @Autowired
    KwsFileInfoDao fileInfoDao;

    /**
     * 上传文件至OSS
     *
     * @param file
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public HttpResult uploadFile(MultipartFile file) {
        HttpResult result = new HttpResult();
        List<Map<String, Object>> resultList = new ArrayList<>();
        result.setCode(HttpStatus.SUCCESS_CODE);
        boolean isEmpty = file.isEmpty();
        if (isEmpty) {
            result.setCode(HttpStatus.GLOBAL_EXCEPTION_CODE);
            result.setMsg("上传请不要选择空文件");
            return result;
        }
        String oFileName = file.getOriginalFilename();
        BigDecimal fileSize = FileUtils.getFileSize(file, StringConstant.KB);
        kwfFileInfo fileInfo = new kwfFileInfo();
        fileInfo.setOriginalName(oFileName);
        fileInfo.setFileSuffix(FilenameUtils.getExtension(oFileName));
        fileInfo.setFileSize(StringUtils.isBlank(fileSize) ? new BigDecimal(NumberConstant.ZERO) : fileSize);
        Map<String, String> infoMap = FileUtils.uploadFileByInfo(file, FileEnum.DOCUMENT_ADDRESS);
        fileInfo.setId(new IdWorker(1).nextId());
        fileInfo.setType(FileEnum.FILE_STORE_TYPE_OSS.getFileType());
        fileInfo.setFileName(infoMap.get("fileName"));
        fileInfo.setMd5(infoMap.get("fileMd5"));
        fileInfo.setFilePath(infoMap.get("filePath"));
        fileInfo.setCreateTime(new Date());
        fileInfo.setUpdateTime(new Date());
        fileInfo.setStatus(0);
        fileInfo.setDelFlag(0);
        fileInfo.setCreateBy(LoginUserHolder.getUserId());
        fileInfo.setUpdateBy(LoginUserHolder.getUserId());
        fileInfoDao.insert(fileInfo);
        if (StringUtils.isNotBlank(infoMap.get("filePath"))) {
            result.setMsg("上传成功");
            Map<String, Object> map = new HashMap<>(NumberConstant.SIXTEEN);
            map.put("fileKey", infoMap.get("fileMd5"));
            map.put("fileName", infoMap.get("fileName"));
            resultList.add(map);
            result.setData(resultList);
        } else {
            result.setCode(HttpStatus.GLOBAL_EXCEPTION_CODE);
            result.setMsg("上传请选择文件");
        }
        return result;
    }


    /**
     * 批量上传文件至OSS
     *
     * @param file
     * @return
     */
    @Async
    public HttpResult uploadFileList(MultipartFile[] file) {
        HttpResult result = new HttpResult();
        List<Map<String, Object>> resultList = new ArrayList<>();
        if (!ObjectUtils.isEmpty(file) && file.length > 0) {
            List<MultipartFile> multipartFiles = Arrays.asList(file);
            for (MultipartFile multipartFile : multipartFiles) {
                Map<String, Object> map = new HashMap<>(NumberConstant.SIXTEEN);
                //文件大小
                String fileSize = FileUtils.getFileSize(multipartFile);
                //文件名称
                String originalFilename = multipartFile.getOriginalFilename();
                map.put("code", HttpStatus.SUCCESS_CODE);
                map.put("fileName", originalFilename);
                map.put("message", HttpStatus.SUCCESS_MESSAGE);
                String oosUrl = null;
                //上传文件是否成功
                try {
                    oosUrl = FileUtils.uploadFile(multipartFile, FileEnum.DOCUMENT_ADDRESS);
                } catch (Exception e) {
                    map.put("code", HttpStatus.GLOBAL_EXCEPTION_CODE);
                    map.put("fileName", originalFilename);
                    map.put("message", e);
                }
                if (StringUtils.isBlank(oosUrl)) {
                    map.put("code", HttpStatus.GLOBAL_EXCEPTION_CODE);
                    map.put("fileName", originalFilename);
                    map.put("message", HttpStatus.SUCCESS_MESSAGE);
                }
                //上传至oss文件地址
                map.put("oosUrl",oosUrl);
                resultList.add(map);
            }
        } else {
            result.setCode(HttpStatus.GLOBAL_EXCEPTION_CODE);
            result.setMsg("上传选择文件为空");
        }
        result.setData(resultList);
        return result;
    }


    /**
     * OSS下载文件/获取文件地址
     *
     * @param fileName kll/uploads/20230621/07ccbec381a011d121a215719199ac49.html
     */
    public void fileDownload(String fileName) {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        FileUtils.downloadByUrl(response, fileName);
    }


    public void remove(String fileName) {
        String str = FileUtils.getOSSAddressPrefix();
        String fileNameSubstring = StringUtils.substring(fileName, str.length() + 1);
        FileUtils.remove(fileName);
    }

    public HttpResult selectAll() {
        BigDecimal bigDecimal1 = new BigDecimal(NumberConstant.ZERO);
        BigDecimal bigDecimal2 = new BigDecimal(NumberConstant.SIX);
        BigDecimal multiply = bigDecimal2.divide(bigDecimal1);
        return HttpResult.ok("", multiply);
    }

    public HttpResult downAllOssFile(String fileAllName, HttpServletRequest request, HttpServletResponse response) {
        try {
            String momentFileName = "全部资源下载.zip";
            // 创建临时文件
            File zipFile = File.createTempFile("批量下载", ".zip");
            FileOutputStream f = new FileOutputStream(zipFile);
            CheckedOutputStream csum = new CheckedOutputStream(f, new Adler32());
            // 用于将数据压缩成Zip文件格式
            ZipOutputStream zos = new ZipOutputStream(csum);
            String[] files = fileAllName.split(",");
            for (String string : files) {
                String fName = string.trim();
                String eachFileName = fName.substring(fName.lastIndexOf("/") + 1);
                String tmp = fName.substring(0, fName.lastIndexOf("/"));
                tmp = tmp.substring(tmp.lastIndexOf("/") + 1);
                String fileName = tmp + "/" + eachFileName;
                OSSObject ossObject = FileUtils.downloadOssFile(response.getOutputStream(), fileName);
                InputStream inputStream = ossObject.getObjectContent();
                zos.putNextEntry(new ZipEntry(eachFileName));
                int bytesRead;
                // 向压缩文件中输出数据
                while ((bytesRead = inputStream.read()) != -1) {
                    zos.write(bytesRead);
                }
                inputStream.close();
                zos.closeEntry();
            }
            zos.close();
            String header = request.getHeader("User-Agent").toUpperCase();
            if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) {
                momentFileName = URLEncoder.encode(momentFileName, StringConstant.ENCODING_UTF_EIGHT);
                //IE下载文件名空格变+号问题
                momentFileName = momentFileName.replace("+", "%20");
            } else {
                momentFileName = new String(momentFileName.getBytes(), StringConstant.ENCODING_ISO);
            }
            response.reset();
            response.setContentType("text/plain");
            response.setContentType("application/octet-stream; charset=utf-8");
            response.setHeader("Location", momentFileName);
            response.setHeader("Cache-Control", "max-age=0");
            response.setHeader("Content-Disposition", "attachment; filename=" + momentFileName);
            FileInputStream fis = new FileInputStream(zipFile);
            BufferedInputStream buff = new BufferedInputStream(fis);
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            byte[] car = new byte[1024];
            int l = 0;
            while (l < zipFile.length()) {
                int j = buff.read(car, 0, 1024);
                l += j;
                out.write(car, 0, j);
            }
            // 关闭流
            fis.close();
            buff.close();
            out.close();
            // 删除临时文件
            zipFile.delete();
        } catch (Exception e) {
            e.printStackTrace();
            log.info("batch list down file error :{}", e.getMessage(), e);
        }
        return null;
    }

    public HttpResult uploadFileInfo(MultipartFile file) {
        FileInfo fileInfo = FileUtils.getFileDataList(file);
        fileInfo.setType(FileEnum.FILE_STORE_TYPE_OSS.getFileType());
        FileInfo returnFileInfo = FileUtils.uploadFileInfo(file, fileInfo, FileEnum.FILE_STORE_TYPE_OSS);
        return HttpResult.ok(returnFileInfo);
    }


    public HttpResult fileDubboUpload(InputStream inputStream, FileInfoDTO fileInfo) {
        Map<String, String> map = FileUtils.uploadFileByInfo(inputStream, fileInfo.getOriginalName(), FileEnum.Local_Address);
        return HttpResult.ok(map);
    }
}
