package com.kamco.cd.kamcoback.mapsheet.service;

import com.kamco.cd.kamcoback.common.utils.FIleChecker;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.FilesDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.FoldersDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.SrchFilesDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.SrchFoldersDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.AddReq;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.DmlReturn;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.ErrorDataDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.ErrorSearchReq;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngFilesDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.YearSearchReq;
import com.kamco.cd.kamcoback.postgres.core.MapSheetMngCoreService;
import com.kamco.cd.kamcoback.postgres.entity.YearEntity;
import jakarta.validation.Valid;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Comparator;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MapSheetMngService {

  private final MapSheetMngCoreService mapSheetMngCoreService;

  @Value("${file.sync-root-dir}")
  private String syncRootDir;

  @Value("${file.sync-tmp-dir}")
  private String syncTmpDir;

  @Value("${file.sync-file-extention}")
  private String syncFileExtention;

  public List<MngDto> findMapSheetMngList() {
    return mapSheetMngCoreService.findMapSheetMngList();
  }

  public List<Integer> findMapSheetMngYyyyList() {
    return mapSheetMngCoreService.findMapSheetMngYyyyList();
  }

  public List<Integer> getListMapListYYYYLimit10() {

    YearSearchReq req = YearSearchReq.builder().status("NOTYET").page(0).size(10).build();
    // List조회
    Page<YearEntity> years = mapSheetMngCoreService.getListMapListYYYYWithPaging(req);
    return years.map(YearEntity::getYyyy).getContent().stream()
        .sorted(Comparator.reverseOrder())
        .toList();
  }

  public MngDto findMapSheetMng(int mngYyyy) {
    return mapSheetMngCoreService.findMapSheetMng(mngYyyy);
  }

  @Transactional
  public DmlReturn mngComplete(int mngYyyy) {

    mapSheetMngCoreService.MapSheetMngComplete(mngYyyy);

    return new DmlReturn("success", "작업완료 처리되었습니다.");
  }

  public Page<ErrorDataDto> findMapSheetErrorList(@Valid ErrorSearchReq searchReq) {
    return mapSheetMngCoreService.findMapSheetErrorList(searchReq);
  }

  public ErrorDataDto findMapSheetError(Long hstUid) {
    return mapSheetMngCoreService.findMapSheetError(hstUid);
  }

  @Transactional
  public DmlReturn mngDataSave(AddReq addReq) {
    int execCnt = mapSheetMngCoreService.mngDataSave(addReq);
    return new MapSheetMngDto.DmlReturn("success", addReq.getMngYyyy() + "년, " + execCnt + "건 생성");
  }

  public DmlReturn updateExceptUseInference(@Valid List<Long> hstUidList) {
    return mapSheetMngCoreService.updateExceptUseInference(hstUidList);
  }

  @Transactional
  public DmlReturn uploadPair(
      MultipartFile tfwFile, MultipartFile tifFile, Long hstUid, Boolean overwrite) {

    String rootPath = syncRootDir;
    String tmpPath = syncTmpDir;

    DmlReturn dmlReturn = new DmlReturn("success", "UPLOAD COMPLETE");

    ErrorDataDto errDto = mapSheetMngCoreService.findMapSheetError(hstUid);

    if (errDto == null) {
      return new DmlReturn("fail", "NO hstUid Data");
    }

    // 파일검증용 임시저장 폴더 확인
    if (!FIleChecker.mkDir(tmpPath)) {
      return new DmlReturn("fail", "CREATE TEMP FOLDER ERROR");
    }

    // 업로드 파일 사이즈,확장자명 체크
    dmlReturn = this.validationFile(tfwFile, tifFile);
    if (dmlReturn.getFlag().equals("fail")) return dmlReturn;

    MngDto mngDto = mapSheetMngCoreService.findMapSheetMng(errDto.getMngYyyy());
    String targetYearDir = mngDto.getMngPath();

    // 중복체크
    if (!overwrite) {
      dmlReturn =
          this.duplicateFile(
              errDto.getMngYyyy(), tfwFile.getOriginalFilename(), tifFile.getOriginalFilename());
      if (dmlReturn.getFlag().equals("duplicate")) return dmlReturn;
    }

    // 멀티파트 파일 tmp폴더 저장(파일형식 체크를 위해)
    String tfwTmpPath = tmpPath + tfwFile.getOriginalFilename();
    String tifTmpPath = tmpPath + tifFile.getOriginalFilename();

    if (!FIleChecker.multipartSaveTo(tfwFile, tfwTmpPath))
      return new DmlReturn("fail", "UPLOAD ERROR");
    if (!FIleChecker.multipartSaveTo(tifFile, tifTmpPath))
      return new DmlReturn("fail", "UPLOAD ERROR");

    if (!FIleChecker.cmmndGdalInfo(tifTmpPath)) return new DmlReturn("fail", "TIF TYPE ERROR");
    if (!FIleChecker.checkTfw(tfwTmpPath)) return new DmlReturn("fail", "TFW TYPE ERROR");

    // 싱크파일목록으로 업로드 경로 확인
    List<MngFilesDto> mngFiles = mapSheetMngCoreService.findByHstUidMapSheetFileList(hstUid);
    String uploadPath = "";
    for (MngFilesDto dto : mngFiles) {
      uploadPath = dto.getFilePath();
      break;
    }

    Path tfwTmpSavePath = Paths.get(tfwTmpPath);
    Path tifTmpSavePath = Paths.get(tifTmpPath);
    Path tfwTargetPath = null;
    Path tifTargetPath = null;

    // 파일이 존재하지 않을 경우(0개) 해당년도 다른 파일경로로 참조
    if (uploadPath.isEmpty()) {
      MngFilesDto filesDto =
          mapSheetMngCoreService.findYyyyToMapSheetFilePathRefer(errDto.getMngYyyy());
      String referPath = filesDto.getFilePath();
      uploadPath = Paths.get(referPath).getParent().toString() + "/" + errDto.getRefMapSheetNum();
    }

    // 업로드 경로 확인(없으면 생성)
    if (!FIleChecker.mkDir(uploadPath)) {
      return new DmlReturn("fail", "CREATE FOLDER ERROR");
    }

    tfwTargetPath = Paths.get(uploadPath).resolve(tfwFile.getOriginalFilename());
    tifTargetPath = Paths.get(uploadPath).resolve(tifFile.getOriginalFilename());

    try {
      Files.move(tfwTmpSavePath, tfwTargetPath, StandardCopyOption.REPLACE_EXISTING);
      Files.move(tifTmpSavePath, tifTargetPath, StandardCopyOption.REPLACE_EXISTING);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }

    // hst업데이트
    MapSheetMngDto.SyncCheckStateReqUpdateDto updReqSyncCheckState =
        new MapSheetMngDto.SyncCheckStateReqUpdateDto();
    updReqSyncCheckState.setHstUid(hstUid);
    updReqSyncCheckState.setFilePath(uploadPath);
    updReqSyncCheckState.setSyncCheckTfwFileName(tfwFile.getOriginalFilename());
    updReqSyncCheckState.setSyncCheckTifFileName(tifFile.getOriginalFilename());
    updReqSyncCheckState.setSyncCheckState("DONE");
    mapSheetMngCoreService.updateMapSheetMngHstSyncCheckState(updReqSyncCheckState);
    // 파일정보 업데이트
    mapSheetMngCoreService.deleteByHstUidMngFile(hstUid);

    MapSheetMngDto.MngFileAddReq addReq = new MapSheetMngDto.MngFileAddReq();
    addReq.setMngYyyy(errDto.getMngYyyy());
    addReq.setMapSheetNum(errDto.getMapSheetNum());
    addReq.setRefMapSheetNum(errDto.getRefMapSheetNum());
    addReq.setFilePath(uploadPath);

    addReq.setFileName(tfwFile.getOriginalFilename());
    addReq.setFileExt("tfw");
    addReq.setFileSize(tfwFile.getSize());
    addReq.setHstUid(errDto.getHstUid());
    addReq.setFileState("DONE");

    mapSheetMngCoreService.mngFileSave(addReq);

    addReq.setFileName(tifFile.getOriginalFilename());
    addReq.setFileExt("tif");
    addReq.setFileSize(tifFile.getSize());
    mapSheetMngCoreService.mngFileSave(addReq);

    return new DmlReturn("success", "파일 업로드 완료되었습니다.");
  }

  public List<MngFilesDto> findByHstUidMapSheetFileList(Long hstUid) {
    return mapSheetMngCoreService.findByHstUidMapSheetFileList(hstUid);
  }

  @Transactional
  public DmlReturn setUseByFileUidMngFile(List<Long> fileUids) {

    long hstUid = 0;

    DmlReturn dmlReturn = new DmlReturn("success", "정상처리되었습니다.");

    MapSheetMngDto.SyncCheckStateReqUpdateDto reqDto =
        new MapSheetMngDto.SyncCheckStateReqUpdateDto();

    for (Long uid : fileUids) {
      MapSheetMngDto.MngFilesDto dto = mapSheetMngCoreService.findByFileUidMapSheetFile(uid);

      reqDto.setHstUid(dto.getHstUid());
      reqDto.setFilePath(dto.getFilePath());
      reqDto.setSyncCheckState("DONE");

      if (dto.getFileExt().equals("tif")) reqDto.setSyncCheckTifFileName(dto.getFileName());
      else if (dto.getFileExt().equals("tfw")) reqDto.setSyncCheckTfwFileName(dto.getFileName());

      mapSheetMngCoreService.updateByFileUidFileState(uid, "DONE");
    }

    // 선택제외 삭제처리
    mapSheetMngCoreService.deleteByNotInFileUidMngFile(reqDto.getHstUid(), fileUids);
    // Hst(내역) 테이블 상태 업데이트
    mapSheetMngCoreService.updateByHstUidSyncCheckState(reqDto);

    return new DmlReturn("success", fileUids.size() + "개 파일이 사용설정되었습니다.");
  }

  public DmlReturn validationFile(MultipartFile tfwFile, MultipartFile tifFile) {
    if (!FIleChecker.validationMultipart(tfwFile)) return new DmlReturn("fail", "TFW SIZE 오류");
    else if (!FIleChecker.validationMultipart(tifFile)) return new DmlReturn("fail", "TFW SIZE 오류");
    else if (!FIleChecker.checkExtensions(tfwFile.getOriginalFilename(), "tfw"))
      return new DmlReturn("fail", "TFW FILENAME ERROR");
    else if (!FIleChecker.checkExtensions(tifFile.getOriginalFilename(), "tif"))
      return new DmlReturn("fail", "TIF FILENAME ERROR");

    return new DmlReturn("success", "파일체크");
  }

  public DmlReturn duplicateFile(int mngYyyy, String tfwFileName, String tifFileName) {
    int tfwCnt = mapSheetMngCoreService.findByYearFileNameFileCount(mngYyyy, tfwFileName);
    int tifCnt = mapSheetMngCoreService.findByYearFileNameFileCount(mngYyyy, tifFileName);

    if (tfwCnt > 0 || tifCnt > 0) {
      String resMsg = "";
      if (tfwCnt > 0) resMsg = tfwFileName;

      if (tifCnt > 0) {
        if (tfwCnt > 0) resMsg = resMsg + "," + tifFileName;
        else resMsg = tifFileName;
      }
      return new DmlReturn("duplicate", resMsg);
    }

    return new DmlReturn("success", "파일체크");
  }

  public FoldersDto getFolderAll(SrchFoldersDto srchDto) {

    Path startPath = Paths.get(syncRootDir + srchDto.getDirPath());
    String dirPath = syncRootDir + srchDto.getDirPath();
    String sortType = "name desc";

    List<FIleChecker.Folder> folderList = FIleChecker.getFolderAll(dirPath);

    int folderTotCnt = folderList.size();
    int folderErrTotCnt =
        (int)
            folderList.stream().filter(dto -> dto.getIsValid().toString().equals("false")).count();

    return new FoldersDto(dirPath, folderTotCnt, folderErrTotCnt, folderList);
  }

  public FilesDto getFilesAll(SrchFilesDto srchDto) {

    String dirPath = srchDto.getDirPath();
    int startPos = srchDto.getStartPos();
    int endPos = srchDto.getEndPos();

    List<FIleChecker.Basic> files =
        FIleChecker.getFilesFromAllDepth(
            srchDto.getDirPath(),
            "*",
            srchDto.getExtension(),
            1,
            srchDto.getSortType(),
            startPos,
            endPos);

    int fileListPos = 0;
    int fileTotCnt = files.size();
    long fileTotSize = FIleChecker.getFileTotSize(files);

    return new FilesDto(dirPath, fileTotCnt, fileTotSize, files);
  }
}
