package com.dbnt.kcgfilemanager.controller;

import com.dbnt.kcgfilemanager.config.LogStatus;
import com.dbnt.kcgfilemanager.model.*;
import com.dbnt.kcgfilemanager.service.BoardCategoryService;
import com.dbnt.kcgfilemanager.service.BoardService;
import com.dbnt.kcgfilemanager.service.CategoryRoleService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.security.Principal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@RestController
@RequiredArgsConstructor
@RequestMapping("/board")
public class BoardController {

  private final BoardService boardService;
  private final BoardCategoryService boardCategoryService;
  private final CategoryRoleService categoryRoleService;


  @GetMapping("/main")
  public ModelAndView main(Board param) {
    ModelAndView mav = new ModelAndView("board/main");
    param.setStatus("M");
    param.setQueryInfo();
    mav.addObject("contentList", boardService.selectContentList(param));
    param.setContentCnt(boardService.selectContentListCnt(param));
    param.setPaginationInfo();
    mav.addObject("searchParams", param);
    return mav;
  }

  @GetMapping("/contentWrite")
  public ModelAndView contentWrite(@AuthenticationPrincipal UserInfo loginUser, Board content) {
    ModelAndView mav = new ModelAndView("board/contentWrite");
    if(content.getContentSeq() == null) {
      mav.addObject("type", "new");
      mav.addObject("userId", loginUser.getUserId());
      mav.addObject("userName", loginUser.getName());
    }else{
      mav.addObject("type", "modify");
      mav.addObject("content", boardService.selectContentModifyInfo(content.getContentSeq()));
    }

    mav.addObject("userRole", loginUser.getUserRole());
    CategoryRole categoryRole = new CategoryRole();
    categoryRole.setUserSeq(loginUser.getUserSeq());
    mav.addObject("categoryRole", categoryRoleService.selectCategorySeqListToUser(categoryRole));
    return mav;
  }

  @PostMapping("/saveContent")
  public Integer saveContent(Board content, MultipartHttpServletRequest request){
    content.setFileList(request.getMultiFileMap().get("uploadFiles"));
    return boardService.saveContent(content);
  }

  @PostMapping("/updateContent")
  public Integer updateContent(Board content, @RequestParam(value = "fileSeq", required = false) List<Integer> deleteFileSeq, MultipartHttpServletRequest request, @AuthenticationPrincipal UserInfo loginUser){
    content.setFileList(request.getMultiFileMap().get("uploadFiles"));
    return boardService.updateContent(content, deleteFileSeq, loginUser);
  }

  @GetMapping("/contentList")
  public ModelAndView contentList(Board board, @RequestParam(value = "tagName", required = false) List<String> tagNameList){
    ModelAndView mav = new ModelAndView("board/contentList");
    mav.addObject("pageTitle", boardCategoryService.getDepth4PageTitle(board.getCategorySeq()));
    board.setQueryInfo();
    if(tagNameList != null && tagNameList.size() != 0){
      board = boardService.setHashTagSearch(board, tagNameList);
    }
    mav.addObject("contentList", boardService.selectContentList(board));
    board.setContentCnt(boardService.selectContentListCnt(board));
    board.setPaginationInfo();
    mav.addObject("searchParams", board);
    return mav;
  }

  @PostMapping("/fullSearchBoardContent")
  @ResponseBody
  public ModelAndView fullSearchBoardContent(
      Board board,
     @RequestParam(value = "searchCategorySeq", required = false) List<Integer> categorySeqList,
     @RequestParam(value = "tagName", required = false) List<String> tagNameList
  ){
    ModelAndView mav = new ModelAndView("board/contentSearchResult");
    if(tagNameList != null && tagNameList.size() != 0){
      board = boardService.setHashTagSearch(board, tagNameList);
    }
    mav.addObject("boardList", boardService.fullSearchBoardContent(categorySeqList, board));
    return mav;
  }

  @GetMapping("/selectBoardContent")
  public ModelAndView selectBoardContent(Board content, @AuthenticationPrincipal UserInfo loginUser){
    ModelAndView mav = new ModelAndView("board/contentDetail");
    Board target = boardService.selectContentByContentSeqAndViewCntUp(content.getContentSeq());
    mav.addObject("content", boardService.selectContentForeignAttribute(target));
    mav.addObject("loginUser", loginUser);
    return mav;
  }
  @GetMapping("/selectBoardLog")
  public ModelAndView selectBoardLog(Board content){
    ModelAndView mav = new ModelAndView("board/contentLog");
    mav.addObject("contentSeq", content.getContentSeq());
    mav.addObject("statusMap", LogStatus.getStatusMap());
    mav.addObject("logList", boardService.selectContentLog(content.getContentSeq()));
    return mav;
  }
  @DeleteMapping("/deleteContent")
  public Integer deleteContent(Board content, @AuthenticationPrincipal UserInfo loginUser){
    return boardService.deleteContent(content, loginUser);
  }

  @GetMapping("/contentSearch")
  public ModelAndView contentSearch(Board content){
    ModelAndView mav = new ModelAndView("board/contentSearch");
    return mav;
  }

  @GetMapping("/fileDownload")
  public void fileDownload(Principal principal, Integer contentSeq, Integer fileSeq, HttpServletRequest request, HttpServletResponse response){
    FileInfo downlodFileInfo = boardService.selectDownloadFileInfo(contentSeq, fileSeq, ((UserInfo)((UsernamePasswordAuthenticationToken) principal).getPrincipal()).getUserId());

    BufferedInputStream in;
    BufferedOutputStream out;
    try {
      File file = new File(downlodFileInfo.getSavePath(), downlodFileInfo.getConversionName());
      setDisposition(downlodFileInfo.getFullName(), request, response);
      in = new BufferedInputStream(new FileInputStream(file));
      out = new BufferedOutputStream(response.getOutputStream());
      FileCopyUtils.copy(in, out);
      out.flush();
      if(out!=null) out.close();
      if(in!=null )in.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  @GetMapping("/fileDownloadToZip")
  public void fileDownloadToZip(Principal principal, Integer contentSeq, @RequestParam(value = "fileSeq") List<Integer> fileSeqList, HttpServletResponse response){
    List<FileInfo> targetList = boardService.selectDownloadFileInfoList(contentSeq, fileSeqList, ((UserInfo)((UsernamePasswordAuthenticationToken) principal).getPrincipal()).getUserId());

    BufferedInputStream in;
    BufferedOutputStream out;

    String tempZipPath = "C:\\kcgFileManager\\tempZip\\";
    File tempFolder = new File(tempZipPath);
    if (!tempFolder.exists() || tempFolder.isFile()) {
      tempFolder.mkdirs();
    }
    String downloadFileName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));

    tempZipPath += downloadFileName+".zip";
    try{
      FileOutputStream fout = new FileOutputStream(tempZipPath);
      ZipOutputStream zout = new ZipOutputStream(fout);
      for(FileInfo downLoadFile: targetList){
        ZipEntry zipEntry = new ZipEntry(downLoadFile.getFullName());
        zout.putNextEntry(zipEntry);

        FileInputStream fin = new FileInputStream(downLoadFile.getSavePath()+"\\"+downLoadFile.getConversionName());
        byte[] buffer = new byte[1024];
        int length;
        while((length = fin.read(buffer)) > 0){
          zout.write(buffer, 0, length);
        }

        zout.closeEntry();
        fin.close();
      }
      zout.close();

      response.setContentType("application/zip");
      response.addHeader("Content-Disposition", "attachment; filename="+downloadFileName+".zip");

      FileInputStream fis=new FileInputStream(tempZipPath);
      ServletOutputStream so=response.getOutputStream();
      in=new BufferedInputStream(fis);
      out=new BufferedOutputStream(so);

      byte[] data=new byte[2048];
      int input;
      while((input=in.read(data))!=-1){
        out.write(data,0,input);
        out.flush();
      }

      if(out!=null) out.close();
      if(fis!=null) fis.close();
      if(in!=null) in.close();
      if(so!=null) so.close();
    }catch (IOException e){
      e.printStackTrace();
    } finally {
      File tempZip = new File(tempZipPath);
      tempZip.delete();
    }
  }

  private void setDisposition(String filename, HttpServletRequest request, HttpServletResponse response) throws IOException {
    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 IOException("Not supported browser");
    }

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

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

  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";
  }
}
