package egovframework.com.its.web.server.service;

import egovframework.com.its.web.server.mapper.NoticeMapper;
import egovframework.com.its.web.server.util.PageCriteria;
import egovframework.com.its.web.server.util.PageMaker;
import egovframework.com.its.web.server.vo.NoticeVO;
import egovframework.com.its.web.server.vo.ResultVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@RequiredArgsConstructor
@Service
public class NoticeService{

    private final NoticeMapper noticeMapper;
//    @Value("${attatch_path}")
//    private final String ATTATCH_FILE_PATH;
//    @Value("${upload_path}")
//    private final String IMAGE_FILE_PATH;

    private final String[] fileExtArray = {"xls", "xlsx", "doc", "docx",
            "ppt", "pptx", "csv", "txt", "hwp", "pdf", "ai", "psd", "zip"};

    public Map<String, Object> selectBoardList(HashMap<String, String> paramMap, PageCriteria criteria) {
        criteria.setBoardId(paramMap.get("boardId"));
        if (paramMap.get("page") != null) {
            criteria.setPage(Integer.parseInt(paramMap.get("page")));
        } else {
            criteria.setPage(1);
        }

        String searchText = paramMap.get("searchText");
        if (searchText != null) {
            criteria.setSearchType(paramMap.get("searchType"));
            criteria.setSearchText(searchText);
        }
        else {
            criteria.setSearchText("");
        }

        PageMaker pageMaker = new PageMaker();
        pageMaker.setCriteria(criteria);
        pageMaker.setTotalCount(this.noticeMapper.getNoticeTotalCount(paramMap));
        List<NoticeVO> noticeList = this.noticeMapper.getNoticeList(criteria);;
        SimpleDateFormat transFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");

        for (NoticeVO vo : noticeList) {
            try {
                Date date = transFormat.parse(vo.getRegDate());
                vo.setRegDate(format.format(date));
            } catch (ParseException e) {
                log.error("/admin/noticeList.do, date format Exception...");
            }
        }

        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("noticeList", noticeList);
        resultMap.put("pageMaker", pageMaker);

        return resultMap;
    }

    public NoticeVO selectBoardView(HashMap<String, String> paramMap) {
        NoticeVO result = this.getNotice(paramMap);

        if (result.getAttachFile() != null) {
            String attatchFile = result.getAttachFile();
            String[] fileArr = attatchFile.split("[|]", -1);
            List<String> attatchFiles = new ArrayList<>();
            if (fileArr.length > 0) {
                for (String file : fileArr) {
                    //if (!file.isEmpty()) {
                    attatchFiles.add(file);
                    //}
                }
            }
            result.setAttatchFiles(attatchFiles);
        }

        if (result.getAttachFileId() != null) {
            String attatchFileId = result.getAttachFileId();
            String[] idArr = attatchFileId.split("[|]", -1);
            List<String> attatchFileIds = new ArrayList<>();
            if (idArr.length > 0) {
                for (String id : idArr) {
                    //if (!id.isEmpty()) {
                    attatchFileIds.add(id);
                    //}
                }
            }
            result.setAttatchFileIds(attatchFileIds);
        }

        SimpleDateFormat transFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        try {
            Date date = transFormat.parse(result.getRegDate());
            result.setRegDate(format.format(date));
        } catch (ParseException e) {
            log.error("/admin/noticeView.do date format Exception...");
        }
        return result;
    }

    public int updateNoticeReadCount(HashMap<String, String> paramMap) {
        return this.noticeMapper.updateNoticeReadCount(paramMap);
    }

    public NoticeVO getNotice(Map<String, String> paramMap) {
        return this.noticeMapper.getNotice(paramMap);
    }

    /**
     * 첨부 파일 다운로드
     * @param paramMap 파라미터
     */
    public ResultVO attatchedFileDownload(Map<String, Object> paramMap, String ATTATCH_FILE_PATH){
        File uploadFileHome = new File(ATTATCH_FILE_PATH);
        String fileName     = paramMap.get("fileName").toString();
        String fileId       = paramMap.get("fileId").toString();
        String filteredName = "";
        String base64 = null;

        String msg = "파일 다운로드가 정상적으로 처리되었습니다.";
        String result = "S";


        File downloadFile = new File(uploadFileHome, fileId);
        int fileSize = (int)downloadFile.length();

        if (fileSize > 0) {
            try{
                byte[] bytes = Files.readAllBytes(downloadFile.toPath());
                base64 = Base64.getEncoder().encodeToString(bytes);
            }
            catch (IOException e1) {
                msg = "파일을 불러오는 중 오류가 발생하였습니다.";
                result = "F";
                log.error("IOException : {}", msg);
            }
        }
        else {
            log.error("파일이 존재하지 않습니다. fileId : {}, fileName : {}", fileId, fileName);
            msg = "파일이 존재하지 않습니다. 파일명 : "+ fileName;
            result = "F";
        }

        if (paramMap.get("boardNo") != null && result.equals("S")) {
            HashMap<String, String> updateMap = new HashMap<>();
            updateMap.put("boardNo", (String)paramMap.get("boardNo"));
            updateMap.put("boardId", "2");
            this.updateNoticeReadCount(updateMap);
        }

        ResultVO resultVo = new ResultVO();
        resultVo.setResult(result);
        resultVo.setMsg(msg);
        resultVo.setFiles(base64);
        resultVo.setMimeType(URLConnection.guessContentTypeFromName(fileName));
        return resultVo;
    }
//    public ResultVO attatchedFileDownload(HttpServletRequest request, HttpServletResponse response, Map<String, Object> paramMap, String ATTATCH_FILE_PATH){
//        log.info("ATTATCH_FILE_PATH : {}",ATTATCH_FILE_PATH);
//        File uploadFileHome = new File(ATTATCH_FILE_PATH);
//        String fileName     = paramMap.get("fileName").toString();
//        String fileId       = paramMap.get("fileId").toString();
//        String filteredName = "";
//
//        String msg = "파일 다운로드가 정상적으로 처리되었습니다.";
//        String result = "S";
//        if (fileName != null && !"".equals(fileName)) {
//            filteredName = fileName.replaceAll("(\r\n|\r|\n|\n\r|&|/)", "");
//        }
//
//        File downloadFile = new File(uploadFileHome, fileId);
//        int fileSize = (int)downloadFile.length();
//
//        if (fileSize > 0) {
//            FileInputStream inStream = null;
//            OutputStream outStream = null;
//            try {
//                if (downloadFile != null) inStream = new FileInputStream(downloadFile);
//                // obtains ServletContext
//                ServletContext context = request.getSession().getServletContext();
//
//                // gets MIME type of the file
//                String mimeType = context.getMimeType(downloadFile.getAbsolutePath());
//                String filteredMimeType = "application/octet-stream";
//
//                if (mimeType != null) filteredMimeType = mimeType.replaceAll("(\r\n|\r|\n|\n\r)", "");
//
//                response.setContentType(filteredMimeType);
//                response.setContentLength(fileSize);
//
//                String userAgent = request.getHeader("User-Agent");
//                String header = "attachment; filename="
//                        + new String(filteredName.getBytes("euc-kr"), "latin1") + ";";
//
//                if (userAgent != null) {
//                    if (userAgent.indexOf("MSIE 5.5") > -1) {// MS IE 5.5 이하
//                        header =  "filename=" + URLEncoder.encode(filteredName, "UTF-8") + ";";
//                    }
//                    else if (userAgent.indexOf("MSIE") > -1 || userAgent.indexOf("Trident") > -1) { // MS IE (보통은 6.x 이상 가정)
//                        header = "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8") + ";";
//                    }
//                }
//
//                response.setHeader("Content-Disposition", header);
//                outStream = response.getOutputStream();
//
//                byte[] buffer = new byte[4096];
//                int bytesRead = -1;
//
//                if (inStream != null && inStream.available() > 0) {
//                    while ((bytesRead = inStream.read(buffer)) != -1) {
//                        if (outStream != null) {
//                            outStream.write(buffer, 0, bytesRead);
//                        }
//                    }
//                    if (paramMap.get("boardNo") != null) {
//                        HashMap<String, String> updateMap = new HashMap<>();
//                        updateMap.put("boardNo", (String)paramMap.get("boardNo"));
//                        updateMap.put("boardId", "2");
//                        this.updateNoticeReadCount(updateMap);
//                    }
//                }
//            } catch (IOException e) {
//                log.error("IOException : /notice/getFile.do, can not close inStream or outStream");
//                msg = "파일 다운로드 중 오류가 발생하였습니다.";
//                result = "F";
////                throw new RuntimeException("IOException : /notice/getFile.do, can not close inStream or outStream");
//            } finally {
//                try {
//                    if (inStream != null) {
//                        inStream.close();
//                    }
//
//                    if (outStream != null) {
//                        outStream.close();
//                    }
//                } catch (IOException e) {
//                    log.error("IOException : /notice/getFile.do, can not close inStream or outStream");
////                    throw new RuntimeException("IOException : /notice/getFile.do, can not close inStream or outStream");
//                    msg = "파일 다운로드 중 오류가 발생하였습니다.";
//                    result = "F";
//                }
//            }
//        }
//        else {
//            log.info("파일이 존재하지 않습니다. fileId : {}, fileName : {}", fileId, fileName);
////            throw new NotFoundException("파일이 존재하지 않습니다. fileId : " + fileId + ", fileName : "+ fileName);
//            msg = "파일이 존재하지 않습니다. 파일명 : "+ fileName;
//            result = "F";
//        }
//
//        ResultVO resultVo = new ResultVO();
//        resultVo.setResult(result);
//        resultVo.setMsg(msg);
//        return resultVo;
//    }

    public int addBoard(List<MultipartFile> attatchFile, String userId, Map<String, String> paramMap, String attachFilePath, String imageFilePath) {
        boolean isWriteSuccess = true;
        String fileNames = "";
        String fileIds = "";
        for (MultipartFile file : attatchFile) {
            Map<String, Object> map = uploadFiles(file, false, attachFilePath, imageFilePath);
            fileNames += map.get("fileName");
            fileIds   += map.get("fileId");
            isWriteSuccess = (Boolean) map.get("isWriteSuccess");
            if (!isWriteSuccess) {
                break;
            }
            fileNames += "|";
            fileIds += "|";
        }

        if (isWriteSuccess) {
            fileIds = fileIds.substring(0, fileIds.length() - 1);
            fileNames = fileNames.substring(0, fileNames.length() - 1);
            Map<String, Object> resultMap = getaddUpdateBoardParam(fileIds, fileNames, paramMap);
            resultMap.put("categoryCd", "N");
            resultMap.put("webUserId", userId);
            return this.noticeMapper.addNotice(resultMap);
        }
        return 0;
    }

    public int updateBoard(List<MultipartFile> attachFile, Map<String, String> paramMap,
                           List<String> attachFileName, String attachPath, String uploadPath) {
        NoticeVO vo             = this.noticeMapper.getNotice(paramMap);
        String[] orginAttatch   = new String[]{};
        String[] orginAttatId   = new String[]{};
        if (vo.getAttachFile() != null) {
            orginAttatch = vo.getAttachFile().split("\\|");
        }
        if (vo.getAttachFileId() != null) {
            orginAttatId = vo.getAttachFileId().split("\\|");
        }

        boolean isWriteSuccess = true;

        String fileNames = "";
        String fileIds = "";

        for (int ii = 0; ii < attachFile.size(); ii++) {
            MultipartFile file = attachFile.get(ii);
            String fileName = file.getOriginalFilename();
            if ( fileName == null || "".equals(fileName)) {
                if (orginAttatch.length > ii && attachFileName.size() > ii) {
                    if (!orginAttatch[ii].isEmpty() && !attachFileName.get(ii).isEmpty()) {
                        if (orginAttatch[ii].equals(attachFileName.get(ii))) {
                            fileIds   += orginAttatId[ii];
                            fileNames += attachFileName.get(ii);
                        }
                    }
                }
            }
            else {
                Map<String, Object> filesMap = uploadFiles(file, false, attachPath, uploadPath);
                isWriteSuccess = (Boolean) filesMap.get("isWriteSuccess");
                if (!isWriteSuccess) {
                    break;
                }
                fileIds   += (String) filesMap.get("fileId");
                fileNames += (String) filesMap.get("fileName");
            }
            fileNames += "|";
            fileIds   += "|";
        }

        if (isWriteSuccess) {
            fileIds = fileIds.substring(0, fileIds.length() - 1);
            fileNames = fileNames.substring(0, fileNames.length() - 1);
            Map<String, Object> resultMap = getaddUpdateBoardParam(fileIds, fileNames, paramMap);
            resultMap.put("boardNo", paramMap.get("boardNo"));
            return this.noticeMapper.updateNotice(resultMap);
        }
        return 0;
    }

    public void deleteNotice(Map<String, Object> paramMap) {
        this.noticeMapper.deleteNotice(paramMap);
    }

    public Map<String, Object> uploadFiles(MultipartFile file, Boolean isImage, String ATTATCH_FILE_PATH, String IMAGE_FILE_PATH){
        Map<String, Object> resultMap = new HashMap<>();
        String fileName = file.getOriginalFilename();
        String contentType = file.getContentType();
        String fileUuid = "";
        Boolean isWriteSuccess = true;
        File uploadFileHome = null;
        if (!"".equals(fileName) && fileName != null) {
            String extension = fileName.substring(fileName.lastIndexOf(".")+1);
            if (isImage) {
                if (contentType != null && !contentType.contains("image")) {
                    isWriteSuccess = false;
                    fileUuid = "";
                    fileName = "";
                } else {
                    uploadFileHome = new File(IMAGE_FILE_PATH);
                }
            }
            else {
                boolean isContainType = false;
                for (String ext : fileExtArray) {
                    if (extension != null && ext.equals(extension)) {
                        isContainType = true;
                        break;
                    }
                }

                if (contentType != null && contentType.contains("image")) {
                    isContainType = true;
                }

                if (!isContainType) {
                    log.error("Check the file types : {}", contentType);
                    isWriteSuccess = false;
                    fileUuid = "";
                    fileName = "";
                } else {
                    uploadFileHome = new File(ATTATCH_FILE_PATH);
                }
            }
            if (isWriteSuccess) {
                uploadFileHome.setExecutable(false, true);
                uploadFileHome.setReadable(true);
                uploadFileHome.setWritable(false, true);

                if (!uploadFileHome.exists()) {
                    uploadFileHome.mkdir();
                }

                fileUuid = UUID.randomUUID().toString().replace("-", "");
                File uploadImgFile = new File(uploadFileHome, fileUuid);
                try {
                    if (file.getSize() <= 200000000) {
                        file.transferTo(uploadImgFile);
                    }
                    else {
                        log.error("Image is Too Large Size(Limit Size 200000000)");
                        isWriteSuccess = false;
                    }
                } catch (IllegalStateException | IOException e) {
                    log.error("Can not transfer To uploadImgFile...");
                    isWriteSuccess = false;
                }
            }
        }
        resultMap.put("fileName", fileName);
        resultMap.put("fileId", fileUuid);
        resultMap.put("isWriteSuccess", isWriteSuccess);
        return resultMap;
    }

    public Map<String, Object> getaddUpdateBoardParam(String fileIds, String fileNames,
                                                         Map<String, String> paramMap) {
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("bSubject", paramMap.get("subject"));
        resultMap.put("bContent", paramMap.get("content"));
        resultMap.put("attachFile", fileNames);
        resultMap.put("ATTACHFILEID", fileIds);
        resultMap.put("bNotice", (paramMap.get("notice") == null) ? "N" : "Y");
        resultMap.put("boardId", paramMap.get("boardId"));
        return resultMap;
    }

}
