package incheon.res.rdm.com.onnara;

import java.io.*;
import java.math.BigDecimal;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.SimpleDateFormat;
import java.util.*;

import incheon.res.rdm.com.attachfile.service.RdmComAttachfileService;
import incheon.res.rdm.com.attachfile.vo.RdmComAttachfileVO;
import org.apache.commons.io.output.FileWriterWithEncoding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;

@Component
public class OnnaraDocBuilder {

	private static final Logger LOGGER = LoggerFactory.getLogger(OnnaraDocBuilder.class);

	private final Map<String, String> SGG_SERVERID = new HashMap<>() {{
		// TODO 테스트용 (인천동구), 관리기관별로 다름
		put("6280000", "DOC628000002");	// 인천광역시
		put("3490000", "DOC");	// 인천광역시 중구
		put("3500000", "DOC350000001");	// 인천광역시 동구
		put("3510500", "DOC");	// 인천광역시 미추홀구
		put("3510572", "DOC");	// 인천광역시 미추홀구 도시경관과
		put("3520000", "DOC");	// 인천광역시 연수구
		put("3530000", "DOC");	// 인천광역시 남동구
		put("3540000", "DOC");	// 인천광역시 부평구
		put("3560000", "DOC");	// 인천광역시 서구
		put("3560038", "DOC");	// 인천광역시 서구 검단행정과
		put("3570000", "DOC");	// 인천광역시 강화군
	}};

	private final String SENDER_SERVERID = "ADM628000096";
	private final String MAINTYPE = "MES98";
	private final String SUBTYPE = "amise98";
	private final String SEND_FILE_PATH = "/idc01/mw/ged/ged_bizframe_exchgagent/data/sendtemp";
	private final String RECEIVE_FILE_PATH = "/idc01/mw/ged/ged_bizframe_exchgagent/data/receivetemp";

	private String RECEIVER_SERVERID = "";
	private String tempFilePath = "";
	private String administrativenum = "";
	private String folder = "";
	private String title = "";
	private String content = "";

	@Resource
	private RdmComAttachfileService rdmComAttachfileService;
	@Resource
	private RdmComAttachfileService fileService;



	/**
	 *	전자문서 생성
	 *		1. 첨부문서
	 *		2. header.inf
	 *		3. exchange.xml
	 *		4. eof.inf
	 */
	@Transactional(rollbackFor = Exception.class)
	public boolean createDoc(Map<String, String> userInfo,
							 String roadDggMngNo,
							 String docTtl,
							 String docMtxt,
							 Map<String, MultipartFile> files) throws Exception{

		SimpleDateFormat fmt= new SimpleDateFormat("yyyyMMddHHmmss");
		Date today = new Date();
		String time = fmt.format(today);

		try{
			title = docTtl;
			content = docMtxt;
			RECEIVER_SERVERID = SGG_SERVERID.get(userInfo.get("roadMngInstCd"));

			// 작업폴더 생성
			administrativenum = roadDggMngNo;
			String random5 = String.format("%05d", new Random().nextInt(100000));
			folder = SUBTYPE + SENDER_SERVERID + RECEIVER_SERVERID + time + random5;
			tempFilePath = "/idc01/mw/idsp/upload/res/rps/" + folder;

			File file = new File(tempFilePath);
			if (!file.isDirectory()) {
				file.mkdirs();
			}

			// 첨부문서 생성 및 테이블 저장
			if(!files.isEmpty()){
				if(!createAttach(files)) {
					throw new RuntimeException("::::: createAttach failed");
				}
			}

			// 첨부문서 조회
			RdmComAttachfileVO fileVO = new RdmComAttachfileVO();
			fileVO.setTblNam("RMT_DOCC_DT");
			fileVO.setDatSeq(roadDggMngNo);
			List<RdmComAttachfileVO> attach = fileService.selectAttachfileList(fileVO);

			// 전송파일 생성
			if(!headerInf(userInfo)) {
				throw new RuntimeException("::::: headerInf failed");
			}
			if(!exchangeXml(userInfo, attach)) {
				throw new RuntimeException("::::: exchangeXml failed");
			}
			if(!eofInf()) {
				throw new RuntimeException("::::: eofInf failed");
			}
			if(!copyAndDeleteFolder()) {
				throw new RuntimeException("::::: copyAndDeleteFolder failed");
			}

			return true;

		}catch(Exception e){
			LOGGER.error(":::::OnnaraDocBuilder createDoc : " + e);
			LOGGER.error(":::::OnnaraDocBuilder createDoc folder : " + folder);
			return false;
		}
	}

	/**
	 *	header.inf 생성
	 */
	public boolean headerInf(Map<String, String> userInfo) {

		boolean successAt = false;

		SimpleDateFormat fmt= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date today = new Date();
		String time = fmt.format(today);

		StringBuffer headerInfo = new StringBuffer();
		try{
			headerInfo.append("type=send\n");
			headerInfo.append("date=" + time + "\n");
			headerInfo.append("sender=" + SENDER_SERVERID  + "\n");
			headerInfo.append("receiver=" + RECEIVER_SERVERID  + "\n");
			headerInfo.append("sender_userid=" + userInfo.get("userId") + "\n");
			headerInfo.append("receiver_userid=" + userInfo.get("userId") + "\n");
			headerInfo.append("sender_email=" + userInfo.get("emlAddr") + "\n");
			headerInfo.append("sender_orgname=" + userInfo.get("roadMngInstNm") + "\n");
			headerInfo.append("sender_systemname=인천시 도로굴착복구시스템\n");
			headerInfo.append("administrative_num=" + administrativenum + "\n");

			successAt = createTempFile(headerInfo.toString(), "header.inf");

		}catch(Exception e){
			LOGGER.error(":::::OnnaraDocBuilder headerInf : " + e);
			LOGGER.error(":::::OnnaraDocBuilder headerInf headerInfo : " + headerInfo);
		}

		return successAt;
	}

	/**
	 *	온나라 시스템으로 보내기 전 파일들을 임시 폴더에 생성
	 */
	public boolean createTempFile(String content, String fileName) throws Exception {

		boolean successAt = false;
		BufferedWriter out = null;
		String fullFilePath = "";

		try{
			fullFilePath = tempFilePath + "/" + fileName;

			File file = new File(fullFilePath);

			out = new BufferedWriter(new FileWriterWithEncoding(file, "EUC-KR"));
			out.write(content);
			out.flush();

			successAt = true;

		}catch(Exception e){
			LOGGER.error(":::::OnnaraDocBuilder createTempFile : " + e);
			LOGGER.error(":::::OnnaraDocBuilder createTempFile path : " + fullFilePath);
		} finally {
			out.close();
		}

		return successAt;
	}

	/**
	 *	exchange.xml 생성
	 */
	public boolean exchangeXml(Map<String, String> userInfo, List<RdmComAttachfileVO> attach) {

		boolean successAt = false;

		SimpleDateFormat fmt= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date today = new Date();
		String time = fmt.format(today);

		StringBuffer sendXML = new StringBuffer();
		try{
			sendXML.append("<?xml version='1.0' encoding='EUC-KR'?>\n");
			sendXML.append("<!DOCTYPE EXCHANGE SYSTEM 'exchange.dtd'>\n");
			sendXML.append("<EXCHANGE>\n");
			sendXML.append("<HEADER>\n");
			sendXML.append("<COMMON>\n");
			sendXML.append("<SENDER>\n");
			sendXML.append("<SERVERID>" + SENDER_SERVERID + "</SERVERID>\n");
			sendXML.append("<USERID>" + userInfo.get("userId") + "</USERID>\n");
			sendXML.append("</SENDER>\n");
			sendXML.append("<RECEIVER>\n");
			sendXML.append("<SERVERID>" + RECEIVER_SERVERID + "</SERVERID>\n");
			sendXML.append("<USERID>" + userInfo.get("userId") + "</USERID>\n");
			sendXML.append("</RECEIVER>\n");
			sendXML.append("<TITLE><![CDATA[" + title + "]]></TITLE>\n");
			sendXML.append("<CREATED_DATE>" + time + "</CREATED_DATE>\n");
			sendXML.append("<ATTACHNUM>" + attach.size() + "</ATTACHNUM>\n");
			sendXML.append("<ADMINISTRATIVE_NUM>" + administrativenum + "</ADMINISTRATIVE_NUM>\n");
			sendXML.append("</COMMON>\n");
			sendXML.append("<DIRECTION>\n");
			sendXML.append("<TO_DOCUMENT_SYSTEM notification='all'>\n");
			sendXML.append("<MODIFICATION_FLAG>\n");
			sendXML.append("<MODIFIABLE modifyflag='yes'/>\n");
			sendXML.append("</MODIFICATION_FLAG>\n");
			sendXML.append("</TO_DOCUMENT_SYSTEM>\n");
			sendXML.append("</DIRECTION>\n");
			sendXML.append("</HEADER>\n");
			sendXML.append("<BODY><![CDATA[" + content + "]]></BODY>\n");
			sendXML.append("<ATTACHMENTS>\n");
			sendXML.append("<ADMINISTRATIVE_DB/>\n");
			if(attach.size() > 0) {
				for (RdmComAttachfileVO fileVO : attach) {
					String filename = fileVO.getOrgNam();
					sendXML.append("<ATTACHMENT filename='" + filename + "'><![CDATA[" + filename + "]]></ATTACHMENT>\n");
				}
			}
			sendXML.append("</ATTACHMENTS>\n");
			sendXML.append("</EXCHANGE>\n");

			successAt = createTempFile(sendXML.toString(), "exchange.xml");

		}catch(Exception e){
			LOGGER.error(":::::OnnaraDocBuilder openContentXml : " + e);
			LOGGER.error(":::::OnnaraDocBuilder openContentXml sendXML : " + sendXML);
		}

		return successAt;
	}

	/**
	 *	첨부문서 생성 및 도로굴착점용첨부파일 테이블에 insert
	 */
	public boolean createAttach(Map<String, MultipartFile> files) throws Exception {

		boolean successAt = false;

		String path = tempFilePath + "/";

		try{
			for (Map.Entry<String, MultipartFile> entry : files.entrySet()) {
				MultipartFile multipartFile = entry.getValue();
				String originalName = multipartFile.getOriginalFilename();
				if (!"".equals(originalName)) {
					String newFileName = "attach_" + originalName;

					File file = new File(path + newFileName);
					// 첨부문서 생성
					multipartFile.transferTo(file);

					// 도로굴착점용첨부파일 테이블에 insert
					RdmComAttachfileVO fvo = new RdmComAttachfileVO();
					fvo.setDatSeq(administrativenum);
					fvo.setTblNam("RMT_DOCC_DT");
					fvo.setAdfNam(newFileName);
					fvo.setOrgNam(originalName);
					fvo.setAdfSiz(BigDecimal.valueOf(file.length()));
					fvo.setSubSeq(new BigDecimal(0));
					fvo.setAdfPth(path + newFileName);

					rdmComAttachfileService.insertAttachfile(fvo);
				}
			}

			successAt = true;

		}catch(Exception e){
			LOGGER.error(":::::OnnaraDocBuilder createAttach : " + e);
			LOGGER.error(":::::OnnaraDocBuilder createAttach path : " + path);
		}

		return successAt;
	}

	/**
	 *	eof.inf 생성
	 *		- 파일 존재여부만 판단하므로 내용없음
	 */
	public boolean eofInf() {

		boolean successAt = false;

		StringBuffer eofInfo = new StringBuffer();

		try{
			String content = eofInfo.toString();
			successAt = createTempFile(content, "eof.inf");

		}catch(Exception e ){
			LOGGER.error(":::::OnnaraDocBuilder eofInf : " + e);
		}

		return successAt;
	}

	/**
	 *	연계폴더로 복사 후 임시폴더에서 삭제
	 */
	public boolean copyAndDeleteFolder() {

		Path source = Paths.get(tempFilePath);
		Path target = Paths.get(SEND_FILE_PATH).resolve(source.getFileName());

		try {
			// 복사
			Files.walkFileTree(source, new SimpleFileVisitor<>() {

				@Override
				public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
					Path targetDir = target.resolve(source.relativize(dir));
					if (!Files.exists(targetDir)) {
						Files.createDirectories(targetDir);
					}
					return FileVisitResult.CONTINUE;
				}

				@Override
				public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
					Path targetFile = target.resolve(source.relativize(file));

					Files.copy(
							file,
							targetFile,
							StandardCopyOption.REPLACE_EXISTING,
							StandardCopyOption.COPY_ATTRIBUTES
					);

					return FileVisitResult.CONTINUE;
				}
			});

			// 삭제
			Files.walkFileTree(source, new SimpleFileVisitor<>() {

				@Override
				public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
					Files.delete(file);
					return FileVisitResult.CONTINUE;
				}

				@Override
				public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
					Files.delete(dir);
					return FileVisitResult.CONTINUE;
				}
			});

			return true;

		} catch (Exception e) {
			LOGGER.error(":::::OnnaraDocBuilder copyAndDeleteFolder : " + e);
			return false;
		}
	}

}
