package com.hdkj.lt.io.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.hdkj.attachments.client.entity.Attachment;
import com.hdkj.attachments.client.entity.AttachmentsParam;
import com.hdkj.attachments.client.facade.IAttachmentFacadeClient;
import com.hdkj.attachments.client.facade.impl.AttachmentFacadeHttpClientImpl;
import com.hdkj.attachments.client.response.ResponseData;
import com.hdkj.lt.io.aop.FileTypeCheckAop;
import com.hdkj.lt.io.config.FileCheckProperties;
import com.hdkj.lt.io.service.IFileService;
import com.ruoyi.common.third.constants.StringPool;
import lombok.RequiredArgsConstructor;
import org.apache.commons.codec.Charsets;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @Description
 * @Author wcx
 * @Date 2025/6/4 8:48
 * @Version 1.0
 */
@Service
@RequiredArgsConstructor
public class FileServiceImpl implements IFileService {

    private final IAttachmentFacadeClient attachmentFacadeClient;

    private final FileCheckProperties fileCheckProperties;

    private final FileTypeCheckAop fileTypeCheckAop;


    @Override
    public void download(Long id, HttpServletResponse response) throws Exception {
        ResponseData<Attachment> detail = attachmentFacadeClient.detail(id);
        String fileName = detail.getData().getOriginName();
        byte[] data = attachmentFacadeClient.download(id).getData();
        try (BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream())) {
            // 转码，免得文件名中文乱码
            fileName = UriUtils.encode(fileName, StringPool.UTF_8);
            // 清空response
            response.reset();
            // 设置文件下载头
            response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName);
            // 设置文件ContentType类型，这样设置，会自动判断下载文件类型(svg文件前端需要指定特殊类型)
            if (StringUtils.endsWithIgnoreCase(fileName, ".svg")) {
                response.setContentType("image/svg+xml");
            } else {
                response.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
            }
            out.write(data);
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void downloadZip(List<Long> ids, HttpServletResponse response) throws Exception {
        try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
            // 文件名（暂时以时间命名）
            String fileName = DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
            // 清空response
            response.reset();
            response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setHeader(HttpHeaders.CONTENT_TYPE, "application/zip");
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, String.format("attachment;filename=%s.zip", fileName));
            response.setCharacterEncoding(Charsets.UTF_8.toString());
            for (Long id : ids) {
                ResponseData<Attachment> detail = attachmentFacadeClient.detail(id);
                byte[] data = attachmentFacadeClient.download(id).getData();
                if (ObjectUtils.isNotEmpty(data)) {
                    zos.putNextEntry(new ZipEntry(detail.getData().getOriginName()));
                    Integer offset = 0; // 起始读取位置
                    Integer bufferSize = 10240; // 10KB缓冲区
                    while (offset < data.length) {
                        Integer chunkSize = Math.min(bufferSize, data.length - offset);
                        zos.write(data, offset, chunkSize);
                        offset += chunkSize;
                    }
                    zos.closeEntry();
                }
                data = null; // 快速回收防止内存溢出
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public ResponseData<List<Attachment>> list(AttachmentsParam attachmentsParam) throws Exception {
        return attachmentFacadeClient.list(attachmentsParam);
    }

    @Override
    public ResponseData<Attachment> detail(Long id) throws Exception {
        return attachmentFacadeClient.detail(id);
    }

    @Override
    public ResponseData<List<Attachment>> uploads(MultipartFile[] multipartFiles) throws Exception {
        // 文件上传安全校验开
        if (fileCheckProperties.isEnabled()) {
            for (MultipartFile multipartFile : multipartFiles) {
                try {
                    fileTypeCheckAop.checkFile(multipartFile);
                } catch (RuntimeException runtimeException) {
                    return ResponseData.error(runtimeException.getMessage());
                }
            }
        }
        // 文件上传安全校验结束
        List<Attachment> attachments = new ArrayList<>();
        for (MultipartFile multipartFile : multipartFiles) {
            attachments.add(attachmentFacadeClient.upload(multipartFile).getData());
        }
        return ResponseData.success(attachments);
    }

    @Override
    public ResponseData<Attachment> upload(MultipartFile multipartFile) throws Exception {
        // 文件上传安全校验开始
        if (fileCheckProperties.isEnabled()) {
            try {
                fileTypeCheckAop.checkFile(multipartFile);
            } catch (RuntimeException runtimeException) {
                return ResponseData.error(runtimeException.getMessage());
            }
        }
        // 文件上传安全校验结束
        return attachmentFacadeClient.upload(multipartFile);
    }

    @Override
    public ResponseData<Void> delete(Long id) throws Exception {
        return attachmentFacadeClient.delete(id);
    }

    @Override
    public ResponseData<byte[]> getFileById(Long id) throws Exception {
        byte[] fileData = attachmentFacadeClient.download(id).getData();
        return ResponseData.success(fileData);
    }
}
