package com.njcn.cssystem.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.cssystem.mapper.CsElementMapper;
import com.njcn.cssystem.pojo.param.ElementParam;
import com.njcn.cssystem.pojo.po.CsElement;
import com.njcn.cssystem.service.IElementService;
import com.njcn.cssystem.utils.SvgZipProcessor;
import com.njcn.oss.constant.OssPath;
import com.njcn.oss.utils.FileStorageUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.Adler32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * <p>
 * 组态图元库 服务实现类
 * </p>
 *
 * @author xuyang
 * @since 2023-07-12
 */
@Slf4j
@Service
@AllArgsConstructor
public class CsElementServiceImpl extends ServiceImpl<CsElementMapper, CsElement> implements IElementService {

    private final FileStorageUtil fileStorageUtil;
    private final SvgZipProcessor svgZipProcessor;

    @Override
    public CsElement addElement(ElementParam param) {
//        CsElement po = this.lambdaQuery().eq(CsElement::getStatus,1)
//                          .eq(CsElement::getElementCode,param.getElementCode())
//                          .eq(CsElement::getElementName,param.getElementName())
//                          .eq(CsElement::getElementMark,param.getElementMark()).one();
//        if (!Objects.isNull(po)){
//            throw new BusinessException(CsSystemResponseEnum.SAME_DATA_ERROR);
//        }
        CsElement csElement = new CsElement();
        BeanUtils.copyProperties(param,csElement);
        String path =  fileStorageUtil.uploadMultipart(param.getMultipartFile(), OssPath.ELEMENT);
        csElement.setPath(path);
        csElement.setStatus(1);
        this.saveOrUpdate(csElement);
        csElement.setPath(path);
        return csElement;
    }

    @Override
    public List<CsElement> findElement() {
        List<CsElement> list = this.lambdaQuery().eq(CsElement::getStatus,1).list();
        return list;
    }

    @Override
    public void deleteById(String id) {
        CsElement csElement = this.lambdaQuery().eq(CsElement::getId,id).one();
        csElement.setStatus(0);
        this.updateById(csElement);
    }

    @Override
    public List<CsElement> addByZip(ElementParam param) {
        List<CsElement> list = new ArrayList<>();
        try {
            // 验证并提取SVG文件
            Map<String, InputStream> svgFiles = SvgZipProcessor.extractValidSvgFiles(param.getZipFile());
            log.info("提取到 {} 个SVG文件:", svgFiles.size());
            svgFiles.forEach((name, stream) -> {
                //获取文件名称
                String[] arr = name.split("/");
                //存储数据库、上传文件服务器
                CsElement csElement = new CsElement();
                BeanUtils.copyProperties(param,csElement);
                String path =  fileStorageUtil.uploadStreamSpecifyName(stream, OssPath.ELEMENT, arr[arr.length - 1]);
                csElement.setPath(path);
                csElement.setStatus(1);
                csElement.setElementName(arr[arr.length - 1].split("\\.")[0]);
                this.save(csElement);
                csElement.setPath(path);
                list.add(csElement);
            });
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage());
        } catch (IOException | SvgZipProcessor.InvalidSvgException e) {
            throw new RuntimeException(e);
        }
        return list;
    }

    @Override
    public HttpServletResponse downloadZip(String name, HttpServletRequest request, HttpServletResponse response) {
        LambdaQueryWrapper<CsElement> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CsElement::getElementSonType,name).eq(CsElement::getStatus,1);
        List<CsElement> list = this.list(wrapper);
        if(CollectionUtils.isNotEmpty(list)) {
            try {
                Map<String, String> filePathMap = list.stream().filter(r -> StringUtils.isNotBlank(r.getPath())).collect(Collectors.toMap(CsElement::getId, CsElement::getPath));
                // 创建临时文件
                File zipFile = File.createTempFile("zip_" + name, ".zip");
                FileOutputStream f = new FileOutputStream(zipFile);
                CheckedOutputStream csum = new CheckedOutputStream(f, new Adler32());
                // 用于将数据压缩成Zip文件格式
                ZipOutputStream zos = new ZipOutputStream(csum);
                for (Map.Entry<String, String> entry : filePathMap.entrySet()) {
                    CsElement csElement = this.getById(entry.getKey());
                    InputStream inputStream = fileStorageUtil.getFileStream(entry.getValue());
                    // 对于每一个要被存放到压缩包的文件，都必须调用ZipOutputStream对象的putNextEntry()方法，确保压缩包里面文件不同名
                    String path = csElement.getPath();
                    zos.putNextEntry(new ZipEntry(csElement.getElementName() + ".svg"));
                    int bytesRead = 0;
                    // 向压缩文件中输出数据
                    while ((bytesRead = inputStream.read()) != -1) {
                        zos.write(bytesRead);
                    }
                    inputStream.close();
                    zos.closeEntry(); // 当前文件写完，定位为写入下一条项目
                }
                zos.close();
                InputStream fis = new BufferedInputStream(Files.newInputStream(zipFile.toPath()));
                byte[] buffer = new byte[fis.available()];
                fis.read(buffer);
                fis.close();
                // 清空response
                response.reset();
                // 设置response的Header
                response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(name + ".zip", "utf-8"));
                response.addHeader("Content-Length", "" + zipFile.length());
                OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
                response.setContentType("application/octet-stream");
                toClient.write(buffer);
                toClient.flush();
                toClient.close();
                zipFile.delete();
            } catch (Exception e) {
                log.error("下载异常");
            }
        }
        return response;
    }

}
