package org.sky.scientific.utils;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.springframework.util.StringUtils;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;

public class ZipDownloadUtils {

	private static final String SUFFIX_ZIP = ".zip";
	private static final String UNNAMED = "未命名";
	/**
	 * 安全处理文件名/目录名
	 * @param name
	 * @return
	 */
	public static String safeName(String name) {
		if (name == null) return "null";
		return name.replaceAll("[\\\\/:*?\"<>|]", "_");
	}

	/**
	 * HTTP下载写入Zip
	 * @param zipOut
	 * @param fileUrl
	 * @param zipEntryName
	 * @throws IOException
	 */
	public static void writeHttpFileToZip(ZipArchiveOutputStream zipOut, String fileUrl, String zipEntryName) throws IOException {
		ZipArchiveEntry entry = new ZipArchiveEntry(zipEntryName);
		zipOut.putArchiveEntry(entry);
		try (InputStream in = openHttpStream(fileUrl, 8000, 20000)) {
			byte[] buffer = new byte[4096];
			int len;
			while ((len = in.read(buffer)) != -1) {
				zipOut.write(buffer, 0, len);
			}
		} catch (Exception e) {
			zipOut.write(("下载失败: " + fileUrl).getBytes(StandardCharsets.UTF_8));
		}
		zipOut.closeArchiveEntry();
	}

	/**
	 * 本地文件写入Zip
	 * @param zipOut
	 * @param localFilePath
	 * @param zipEntryName
	 * @throws IOException
	 */
	public static void writeLocalFileToZip(ZipArchiveOutputStream zipOut, String localFilePath, String zipEntryName) throws IOException {
		File file = new File(localFilePath);
		if (!file.exists() || file.isDirectory()) {
			writeTextToZip(zipOut, zipEntryName + "_empty.txt", "文件不存在或是目录: " + localFilePath);
			return;
		}

		ZipArchiveEntry entry = new ZipArchiveEntry(zipEntryName);
		zipOut.putArchiveEntry(entry);
		try (InputStream fis = new FileInputStream(file)) {
			byte[] buffer = new byte[4096];
			int len;
			while ((len = fis.read(buffer)) != -1) {
				zipOut.write(buffer, 0, len);
			}
		}
		zipOut.closeArchiveEntry();
	}

	/**
	 * 写入空目录到Zip
	 * @param zipOut
	 * @param zipEntryName
 	 * @throws IOException
	 */
	public static void writeEmptyDirToZip(ZipArchiveOutputStream zipOut, String zipEntryName) throws IOException {
		ZipArchiveEntry entry = new ZipArchiveEntry(zipEntryName);
		zipOut.putArchiveEntry(entry);
 		zipOut.closeArchiveEntry();
	}

	/**
	 * 写入文本文件到Zip（如empty.txt）
	 * @param zipOut
	 * @param zipEntryName
	 * @param content
	 * @throws IOException
	 */
	public static void writeTextToZip(ZipArchiveOutputStream zipOut, String zipEntryName, String content) throws IOException {
		ZipArchiveEntry entry = new ZipArchiveEntry(zipEntryName);
		zipOut.putArchiveEntry(entry);
		zipOut.write(content.getBytes(StandardCharsets.UTF_8));
		zipOut.closeArchiveEntry();
	}

	/**
	 * 打开HTTP文件流
	 * @param url
	 * @param connectTimeout
	 * @param readTimeout
	 * @return
	 * @throws IOException
	 */
	public static InputStream openHttpStream(String url, int connectTimeout, int readTimeout) throws IOException {
		URLConnection conn = new URL(url).openConnection();
		conn.setConnectTimeout(connectTimeout);
		conn.setReadTimeout(readTimeout);
		return conn.getInputStream();
	}

	/**
	 * 从url获取文件名
	 * @param url
	 * @return
	 * @throws IOException
	 */
	public static String getFileName(String url)  {
		return url.substring(url.lastIndexOf('/')+1);
	}

	/**
	 * 设置response
	 * @param request
	 * @param response
	 * @param fileName
	 * @throws UnsupportedEncodingException
	 */
	public static void setResponse(HttpServletRequest request, HttpServletResponse response, String fileName) throws UnsupportedEncodingException {
		if (!StringUtils.hasText(fileName)) {
			fileName = LocalDate.now() + UNNAMED;
		}
		if (!fileName.endsWith(SUFFIX_ZIP)) {
			fileName = fileName + SUFFIX_ZIP;
		}
		response.setHeader("Connection", "close");
		response.setHeader("Content-Type", "application/octet-stream;charset=UTF-8");
		String filename = encodeFileName(request, fileName);
		response.setHeader("Content-Disposition", "attachment;filename=" + filename);
	}

	/**
	 * 文件名在不同浏览器兼容处理
	 * @param request 请求信息
	 * @param fileName 文件名
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String encodeFileName(HttpServletRequest request, String fileName) throws UnsupportedEncodingException {
		String userAgent = request.getHeader("USER-AGENT");
		// 火狐浏览器
		if (userAgent.contains("Firefox") || userAgent.contains("firefox")) {
			fileName = new String(fileName.getBytes(), "ISO8859-1");
		} else {
			// 其他浏览器
			fileName = URLEncoder.encode(fileName, "UTF-8");
		}
		return fileName;
	}

}
