
package org.sky.scientific.controller;

import com.alibaba.fastjson.JSON;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.sky.core.boot.ctrl.KdController;
import org.sky.core.secure.utils.SecureUtil;
import org.sky.core.tool.api.R;
import org.sky.core.tool.utils.DateUtil;
import org.sky.scientific.mapper.DownloadTaskMapper;
import org.sky.scientific.pojo.entity.ArchiveAttachEntity;
import org.sky.scientific.pojo.entity.DownloadTask;
import org.sky.scientific.service.IArchiveService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
 * 科研档案管理 控制器
 *
 * @author Kd
 * @since 2025-07-01
 */
@Slf4j
@RestController
@RequestMapping("/archive")
@Tag(name = "科研档案管理")
public class ArchiveCenterController extends KdController {

	private static final int BUFFER_SIZE = 8192; // 8KB缓冲区

	@Resource
	private IArchiveService service;
	@Resource
	private DownloadTaskMapper downloadTaskMapper;

	@GetMapping("fjbczl")
	@ApiOperationSupport(order = 1)
	@Operation(summary = "附件补充资料-查询")
	public R<ArchiveAttachEntity> fjbczl(String year) {
		return R.data(service.fjbczl(year));
	}

	@PostMapping("fjbczl")
	@ApiOperationSupport(order = 2)
	@Operation(summary = "附件补充资料-保存")
	public R<Boolean> updateFjbczl(@Valid @RequestBody ArchiveAttachEntity attach) {
		return R.status(service.fjbczlUpdate(attach));
	}

	@GetMapping("fjbczl/download")
	@ApiOperationSupport(order = 5)
	@Operation(summary = "附件补充资料-一键下载")
	public void ownloadFjbczlZipFiles(HttpServletRequest request, HttpServletResponse response, String year) {
		service.downloadFjbczlZipFiles(request, response, year);
	}

	@PostMapping("generate")
	@ApiOperationSupport(order = 6)
	@Operation(summary = "档案中心-一键下载/一键导出高新备查/一键导出加计备查-生成", description = "返回任务Id，后端生产待下载的文件")
	public R generateCenterZipFiles(@Valid @RequestBody DownloadTask task) {
		if (task.getId() != null) {
			DownloadTask dbTask = downloadTaskMapper.selectById(task.getId());
			if (dbTask == null) {
				dbTask = new DownloadTask();
				dbTask.setStatus(4);
				return R.data(dbTask);
			}
			if ((dbTask.getStatus() == 0 && DateUtil.between(dbTask.getCreateTime(), DateUtil.now()).toSeconds() > 300) || dbTask.getStatus() == 4) {
				task.setStatus(4);
				downloadTaskMapper.updateById(task);
//				return R.fail("下载任务超时，3分钟未完成,请联系管理员");
				return R.data(task);
			}
			return R.data(dbTask);
		} else {
			task.setYearAndMonth(task.getYearAndMonth());
			task.setTenantId(SecureUtil.getTenantId());
			task.setStatus(0);
			int result = downloadTaskMapper.insertDownloadTask(task);
			RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
			if (result == 1) {
				new Thread(() -> {
					RequestContextHolder.setRequestAttributes(requestAttributes);
					service.downloadCenterZipFiles(task);
				}).start();
				return R.data(task);
			}
		}
		return R.success();
	}

	@SneakyThrows
	@GetMapping("center/download")
	@ApiOperationSupport(order = 6)
	@Operation(summary = "档案中心-一键下载/一键导出高新备查/一键导出加计备查")
	public void downloadCenterZipFiles(HttpServletResponse response, Long taskId) {
		DownloadTask task = downloadTaskMapper.selectById(taskId);
		if (task == null) {
			response.setContentType("application/json;charset=UTF-8");
			PrintWriter writer = response.getWriter();
			writer.write(JSON.toJSONString(R.fail("下载任务不存在，请联系管理员")));
			writer.flush();
		} else if (task.getStatus() == 2) {
			File file = new File(task.getZipUrl());
			if (!file.exists()) {
				response.setContentType("application/json;charset=UTF-8");
				PrintWriter writer = response.getWriter();
				writer.write(JSON.toJSONString(R.fail("文件不存在")));
				writer.flush();
			}


			try (FileInputStream fis = new FileInputStream(file);
				 BufferedInputStream bis = new BufferedInputStream(fis);
				 ServletOutputStream outputStream = response.getOutputStream()) {

				// 设置内容类型
				response.setContentType("application/octet-stream");

				// 设置文件大小
				response.setContentLengthLong(file.length());

				// 设置下载文件名（解决中文乱码）
				String encodedFileName = encodeFileName(file.getName());
				response.setHeader("Content-Disposition",
					"attachment; filename=\"" + encodedFileName + "\"; filename*=UTF-8''" + encodedFileName);

				// 缓存控制
				response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
				response.setHeader("Pragma", "no-cache");
				response.setHeader("Expires", "0");

				// 安全头
				response.setHeader("X-Content-Type-Options", "nosniff");

				// 传输文件数据
				byte[] buffer = new byte[8192];
				int bytesRead;
				long totalBytes = 0;

				while ((bytesRead = bis.read(buffer)) != -1) {
					outputStream.write(buffer, 0, bytesRead);
					totalBytes += bytesRead;
				}

				outputStream.flush();
				log.info("文件下载完成: {}, 大小: {} mb", task.getZipUrl(), totalBytes / 1024 / 1024);

			} catch (IOException e) {
				log.error("文件下载失败: {}", task.getZipUrl(), e);
				setErrorResponse(response, "文件下载失败", HttpStatus.INTERNAL_SERVER_ERROR);
			}
		}
	}


	/**
	 * 编码文件名
	 */
	private String encodeFileName(String fileName) {
		try {
			return URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString())
				.replaceAll("\\+", "%20");
		} catch (UnsupportedEncodingException e) {
			return fileName;
		}
	}

	/**
	 * 设置错误响应
	 */
	private void setErrorResponse(HttpServletResponse response, String message, HttpStatus status) {
		try {
			response.setStatus(status.value());
			response.setContentType("application/json");
			response.getWriter().write("{\"error\": \"" + message + "\"}");
		} catch (IOException e) {
			log.error("设置错误响应失败", e);
		}
	}
}
