package com.its.web.service.notice;

import com.its.web.dto.notice.AttachFileDto;
import com.its.web.dto.notice.NoticeDto;
import com.its.web.mapper.its.notice.NoticeMapper;
import com.its.web.pagination.Pagination;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Slf4j
@RequiredArgsConstructor
@Service
public class NoticeService {
    private final NoticeMapper mapper;

    @Value("${board-location}")
    String boardLocation;

    public Pagination findAllList(String page, String searchType, String searchText) {
        Pagination pagination = new Pagination(page, this.mapper.getNoticeTotalCount(), searchType, searchText);
        List<NoticeDto> list = this.mapper.findAllNotice(pagination);
        pagination.setList(list);
        return pagination;
    }

    public NoticeDto findNotice(String boardNo) {
        try {
            return this.mapper.findNoticeById(Long.parseLong(boardNo));
        }
        catch (NumberFormatException e){
            log.error("Cause NumberFormatException, Please Check The Board No -> {}", boardNo);
            return null;
        }
    }

    public List<NoticeDto> findMainNotice(int num) {
        return this.mapper.findMainNotice(num);
    }

    public AttachFileDto getAttachFile(String boardNo, String fileId) {
        AttachFileDto dto = new AttachFileDto();
        dto.setBoardNo(boardNo);
        String message = null;
        if (boardNo != null && fileId != null) {
            Map<String, String> paramMap = new HashMap<>();

            paramMap.put("boardNo", boardNo);
            paramMap.put("fileId", fileId);
            int result = this.mapper.getAttachFileCount(paramMap);
            if (result > 0) {
                File file = new File(boardLocation, fileId);
                int fileSize = (int) file.length();

                if (fileSize > 0) {
                    try {
                        byte[] byteArray = FileUtils.readFileToByteArray(file);
                        if (byteArray.length > 0) {
                            int i = 0;
                            dto.setAttachFile(new byte[byteArray.length]);
                            for (byte b : byteArray) {
                                dto.getAttachFile()[i++] = b;
                            }
                            message = "파일 전송 완료.";
                        }
                        else {
                            message = "파일을 찾을 수 없습니다.";
                        }
                    }
                    catch (FileNotFoundException e) {
                        log.error("File Not FoundException");
                        message = "파일을 찾을 수 없습니다.";
                    } catch (IOException e) {
                        log.error("IOException");
                        message = "파일을 읽는 중 오류가 발생하였습니다.";
                    }
                }
            }
            else {
                message = "파일을 찾일 수 없습니다.";
            }
        }
        dto.setMessage(message);
        return dto;
    }

    public Map<String, String> deleteBoard(String boardNo) {
        Map<String, String> resultMap = new HashMap<>();
        int affectedRows = this.mapper.deleteBoard(boardNo);
        String message = "선택하신 게시물이 삭제되지 않았습니다.";
        String success = "F";
        if (affectedRows > 0) {
            message = "선택하신 게시물이 삭제되었습니다.";
            success = "S";
        }
        resultMap.put("message", message);
        resultMap.put("success", success);
        return resultMap;
    }

    public Map<String, String> writeNotice(Map<String, Object> paramMap, MultipartFile attachFile) {
        Map<String, String> resultMap = new HashMap<>();
        String fileName = "";
        String fileId = "";
        String message = "";
        String success = "S";

        if (attachFile != null && !attachFile.isEmpty()){
            fileName = attachFile.getOriginalFilename();

            if (fileName != null) {
                String ext = fileName.substring(fileName.lastIndexOf("."), fileName.length());
                fileId   = UUID.randomUUID().toString().replaceAll("-", "") + ext;

                boolean isSuccess = uploadAttachFile(attachFile, fileId);
                if (!isSuccess) {
                    message = "파일 생성 중 오류가 발생하였습니다.";
                    success = "F";
                }
            }
        }

        if (success.equals("S")) {
            paramMap.put("attachFile", fileName + "||");
            paramMap.put("attachFileId", fileId + "||");
            int affectedRows = this.mapper.insertNotice(paramMap);
            message = "작성하신 게시물이 저장되었습니다.";
            if (affectedRows <= 0) {
                message = "작성하신 게시물이 저장되지 않았습니다.";
                success = "F";
            }
        }

        resultMap.put("message", message);
        resultMap.put("success", success);
        return resultMap;
    }

    public Map<String, String> modifyNotice(Map<String, Object> paramMap, MultipartFile attachFile) {
        String fileName = "";
        String fileId = "";
        String message = "";
        String success = "S";
        Map<String, String> resultMap = new HashMap<>();

        if (attachFile != null && !attachFile.isEmpty()){
            fileName = attachFile.getOriginalFilename();

            if (fileName != null) {
                String ext = fileName.substring(fileName.lastIndexOf("."), fileName.length());
                fileId   = UUID.randomUUID().toString().replaceAll("-", "") + ext;
                paramMap.put("fileName", fileName);
                int sameCount = this.mapper.checkImageName(paramMap);
                if (sameCount == 0) {
                    boolean isSuccess = uploadAttachFile(attachFile, fileId);
                    if (!isSuccess) {
                        message = "파일 생성 중 오류가 발생하였습니다.";
                        success = "F";
                    }
                }

            }
        }

        if (success.equals("S")) {
            paramMap.put("attachFile", fileName + "||");
            paramMap.put("attachFileId", fileId + "||");
            int affectedRows = this.mapper.updateNotice(paramMap);
            message = "작성하신 게시물이 수정되었습니다.";
            if (affectedRows <= 0) {
                message = "작성하신 게시물이 수정되지 않았습니다.";
                success = "F";
            }
        }

        resultMap.put("message", message);
        resultMap.put("success", success);
        return resultMap;
    }

    public boolean uploadAttachFile(MultipartFile attachFile, String fileId) {
        File file = new File(boardLocation);
        boolean isMkFile = true;
        if (!file.exists()) {
            isMkFile = file.mkdirs();
        }
        if (isMkFile) {
            File transFile = new File(boardLocation + "/" + fileId);

            try {
                attachFile.transferTo(transFile);
            }
            catch (IOException e) {
                log.error("파일 생성 중 오류가 발생하였습니다. {}", e.getMessage());
                isMkFile = false;
            }
        }
        else {
            log.error("디렉토리 생성 중 오류가 발생하였습니다.");
        }

        return isMkFile;
    }

    public int updateNoticeReadCount(String boardNo) {
        return this.mapper.updateNoticeReadCount(boardNo);
    }

    public String imageUpload(HttpServletRequest req){
        String uploadImageInfo = "";
        String fileName = req.getHeader("file-name");
        try {
            fileName = URLDecoder.decode(fileName, "UTF-8");
        }
        catch (UnsupportedEncodingException exception) {
            log.error("Can not Decoding UTF-8");
        }
        String filePath = boardLocation + "/upload";
        File file = new File(filePath);
        boolean isMkdirs = true;
        if (!file.exists()) {
            isMkdirs = file.mkdirs();
        }

        if (isMkdirs) {
            String realFileNm;
            realFileNm = UUID.randomUUID().toString().replace("-", "") + fileName.substring(fileName.lastIndexOf("."));
            String rlFileNm = filePath + File.separator + realFileNm;

            try (
                    InputStream is = req.getInputStream();
                    OutputStream os = new FileOutputStream(rlFileNm);
            ) {
                int numRead;
                byte[] byteArray = new byte[Integer.parseInt(req.getHeader("file-size"))];
                if (is != null) {
                    while ((numRead = is.read(byteArray, 0, byteArray.length)) != -1) {
                        os.write(byteArray, 0, numRead);
                    }
                }
                os.flush();
            } catch (IOException e) {
                log.error("noticeImgupload() IO Exception");
            } catch (Exception e1) {
                log.error("noticeImgupload() Exception");
            }
            uploadImageInfo += "&bNewLine=true";
            uploadImageInfo += "&sFileName=" + fileName;
            uploadImageInfo += "&sFileURL=" + "/api/notice/upload/" + realFileNm;
        }

        return uploadImageInfo;
    }

    public byte[] getImage(String imageName) {
        byte[] image = null;
        File file = new File(boardLocation + "/upload", imageName);
        int fileSize = (int) file.length();
        if (fileSize > 0) {
            try {
                byte[] byteArray = FileUtils.readFileToByteArray(file);
                if (byteArray.length > 0) {
                    int ii = 0;
                    image = new byte[byteArray.length];
                    for (byte b : byteArray) {
                        image[ii++] = b;
                    }
                }
            } catch (FileNotFoundException e) {
                log.error("Not Found File - {}", boardLocation + "/upload/" + imageName);
            } catch (IOException e) {
                log.error("Can Not Send Image Cause IOException - {}", boardLocation + "/upload/" + imageName);
            }
        }
        return image;
    }
}



