package incheon.com.cmm.web;

import incheon.com.cmm.EgovWebUtil;
import incheon.com.cmm.service.EgovFileMngService;
import incheon.com.cmm.service.EgovProperties;
import incheon.com.cmm.service.FileVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.rte.fdl.cryptography.EgovCryptoService;
import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Base64;
import java.util.Map;

/**
 * 파일 다운로드를 위한 컨트롤러 클래스
 * @author 공통서비스개발팀 이삼섭
 * @since 2009.06.01
 * @version 1.0
 * @see
 *
 * <pre>
 * << 개정이력(Modification Information) >>
 *
 *   수정일      수정자           수정내용
 *  -------    --------    ---------------------------
 *   2009.3.25  이삼섭          최초 생성
 *
 * Copyright (C) 2009 by MOPAS  All right reserved.
 * </pre>
 */
@Slf4j
@Controller
@Tag(name="EgovFileDownloadController",description = "파일 다운로드")
public class EgovFileDownloadController {

	@Resource(name = "EgovFileMngService")
	private EgovFileMngService fileService;
	
	/** 암호화서비스 */
    @Resource(name="egovARIACryptoService")
    EgovCryptoService cryptoService;
	
	public static final String ALGORITM_KEY = EgovProperties.getProperty("Globals.crypto.algoritm");

	/**
	 * 브라우저 구분 얻기.
	 *
	 * @param request
	 * @return
	 */
	private String getBrowser(HttpServletRequest request) {
		String header = request.getHeader("User-Agent");
		if (header.indexOf("MSIE") > -1) {
			return "MSIE";
		} else if (header.indexOf("Trident") > -1) { // IE11 문자열 깨짐 방지
			return "Trident";
		} else if (header.indexOf("Chrome") > -1) {
			return "Chrome";
		} else if (header.indexOf("Opera") > -1) {
			return "Opera";
		}
		return "Firefox";
	}

	/**
	 * Disposition 지정하기.
	 *
	 * @param filename
	 * @param request
	 * @param response
	 * @throws Exception
	 */
	private void setDisposition(String filename, HttpServletRequest request, HttpServletResponse response)
		throws Exception {
		String browser = getBrowser(request);

		String dispositionPrefix = "attachment; filename=";
		String encodedFilename = null;

		if (browser.equals("MSIE")) {
			encodedFilename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
		} else if (browser.equals("Trident")) { // IE11 문자열 깨짐 방지
			encodedFilename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20");
		} else if (browser.equals("Firefox")) {
			encodedFilename = "\"" + new String(filename.getBytes("UTF-8"), "8859_1") + "\"";
		} else if (browser.equals("Opera")) {
			encodedFilename = "\"" + new String(filename.getBytes("UTF-8"), "8859_1") + "\"";
		} else if (browser.equals("Chrome")) {
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < filename.length(); i++) {
				char c = filename.charAt(i);
				if (c > '~') {
					sb.append(URLEncoder.encode("" + c, "UTF-8"));
				} else {
					sb.append(c);
				}
			}
			encodedFilename = sb.toString();
		} else {
			//throw new RuntimeException("Not supported browser");
			throw new IOException("Not supported browser");
		}

		response.setHeader("Content-Disposition", dispositionPrefix + encodedFilename);

		if ("Opera".equals(browser)) {
			response.setContentType("application/octet-stream;charset=UTF-8");
		}
	}

	/**
	 * 첨부파일로 등록된 파일에 대하여 다운로드를 제공한다.
	 *
	 * @param commandMap
	 * @param response
	 * @throws Exception
	 */
	
	@Operation(
			summary = "파일 다운로드",
			description = "첨부파일로 등록된 파일에 대하여 다운로드를 제공",
			tags = {"EgovFileDownloadController"}
	)
	@ApiResponses(value = {
			@ApiResponse(responseCode = "200", description = "성공")
	})
	@GetMapping(value = "/file")
	public void cvplFileDownload(
			@RequestParam Map<String, Object> commandMap,
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		String param_atchFileId = (String) commandMap.get("atchFileId");
		if (param_atchFileId == null || param_atchFileId.isEmpty()) {
			throw new FileNotFoundException("atchFileId 파라미터가 없습니다.");
		}

		try {
			// 공백 대신 +로 치환
			param_atchFileId = param_atchFileId.replaceAll(" ", "+");
			// Base64 URL-safe 디코딩
			byte[] decodedBytes = Base64.getUrlDecoder().decode(param_atchFileId);
			// 복호화
			String decodedFileId = new String(cryptoService.decrypt(decodedBytes, ALGORITM_KEY));

			String fileSn = (String) commandMap.get("fileSn");

			FileVO fileVO = new FileVO();
			fileVO.setAtchFileId(decodedFileId);
			fileVO.setFileSn(fileSn);

			FileVO fvo = fileService.selectFileInf(fileVO);
			if (fvo == null) {
				throw new FileNotFoundException("파일 정보를 찾을 수 없습니다.");
			}

			String fileStreCours = EgovWebUtil.filePathBlackList(fvo.getFileStreCours());
			String streFileNm = EgovWebUtil.filePathBlackList(fvo.getStreFileNm());

			File uFile = new File(fileStreCours, streFileNm);
			long fSize = uFile.length();

			if (fSize > 0) {
				String mimetype = "application/x-stuff";

				response.setContentType(mimetype);
				setDisposition(fvo.getOrignlFileNm(), request, response);

				try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(uFile));
					 BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream())) {
					FileCopyUtils.copy(in, out);
					out.flush();
				} catch (FileNotFoundException ex) {
					log.debug("IGNORED: {}", ex.getMessage());
				}
			} else {
				throw new FileNotFoundException("파일이 존재하지 않거나 크기가 0입니다.");
			}

		} catch (IllegalArgumentException e) {
			// Base64 디코딩 실패 등
			log.error("Base64 디코딩 실패: {}", e.getMessage());
			throw new FileNotFoundException("잘못된 atchFileId 인코딩입니다.");
		} catch (Exception e) {
			log.error("파일 다운로드 중 오류 발생", e);
			throw e;
		}
	}

}
