package com.kamco.cd.kamcoback.common.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.gce.geotiff.GeoTiffReader;

public class FIleChecker {

  public static boolean isValidFile(String pathStr) {

    Path path = Paths.get(pathStr);

    if (!Files.exists(path)) {
      return false;
    }

    if (!Files.isRegularFile(path)) {
      return false;
    }

    if (!Files.isReadable(path)) {
      return false;
    }

    try {
      if (Files.size(path) <= 0) {
        return false;
      }
    } catch (IOException e) {
      return false;
    }

    return true;
  }

  public static boolean verifyFileIntegrity(Path path, String expectedHash)
      throws IOException, NoSuchAlgorithmException {

    // 1. 알고리즘 선택 (SHA-256 권장, MD5는 보안상 비추천)
    MessageDigest digest = MessageDigest.getInstance("SHA-256");

    try (InputStream fis = Files.newInputStream(path)) {
      byte[] buffer = new byte[8192]; // 8KB 버퍼
      int bytesRead;
      while ((bytesRead = fis.read(buffer)) != -1) {
        digest.update(buffer, 0, bytesRead);
      }
    }

    // 3. 계산된 바이트 배열을 16진수 문자열로 변환
    StringBuilder sb = new StringBuilder();
    for (byte b : digest.digest()) {
      sb.append(String.format("%02x", b));
    }
    String actualHash = sb.toString();

    return actualHash.equalsIgnoreCase(expectedHash);
  }

  public static boolean checkTfw(String filePath) {

    File file = new File(filePath);

    if (!file.exists()) {
      return false;
    }

    // 1. 파일의 모든 라인을 읽어옴
    List<Double> lines = new ArrayList<>();
    try (BufferedReader br = new BufferedReader(new FileReader(file))) {
      String line;
      while ((line = br.readLine()) != null) {
        if (!line.trim().isEmpty()) { // 빈 줄 제외
          lines.add(Double.parseDouble(line.trim()));
        }
      }
    } catch (IOException ignored) {
      return false;
    }

    // 2. 6줄이 맞는지 확인
    if (lines.size() < 6) {
      // System.out.println("유효하지 않은 TFW 파일입니다. (데이터 부족)");
      return false;
    }

    return true;
  }

  public static boolean checkGeoTiff(String filePath) {

    File file = new File(filePath);

    if (!file.exists()) {
      return false;
    }

    GeoTiffReader reader = null;
    try {
      // 1. 파일 포맷 및 헤더 확인
      reader = new GeoTiffReader(file);

      // 2. 실제 데이터 로딩 (여기서 파일 깨짐 여부 확인됨)
      // null을 넣으면 전체 영역을 읽지 않고 메타데이터 위주로 체크하여 빠름
      GridCoverage2D coverage = reader.read(null);

      if (coverage == null) return false;

      // 3. GIS 필수 정보(좌표계)가 있는지 확인
      // if (coverage.getCoordinateReferenceSystem() == null) {
      // GeoTIFF가 아니라 일반 TIFF일 수도 있음(이미지는 정상이지만, 좌표계(CRS) 정보가 없습니다.)
      // }

      return true;

    } catch (Exception e) {
      System.err.println("손상된 TIF 파일입니다: " + e.getMessage());
      return false;
    } finally {
      // 리소스 해제 (필수)
      if (reader != null) reader.dispose();
    }
  }

  public static Boolean cmmndGdalInfo(String filePath) {

    File file = new File(filePath);

    if (!file.exists()) {
      return false;
    }

    String resStr = "";
    boolean hasDriver = false;

    // 리눅스/맥용
    // ProcessBuilder pb = new ProcessBuilder("sh", "-c", "gdalinfo "+filePath+" | grep -i 'Geo'");

    List<String> command = new ArrayList<>();

    // 윈도우용
    /*
    command.add("cmd.exe"); // 윈도우 명령 프롬프트 실행
    command.add("/c");      // 명령어를 수행하고 종료한다는 옵션
    command.add("gdalinfo");
    command.add(filePath);
    command.add("|");
    command.add("findstr");
    command.add("/i");
    command.add("Geo");
    */

    command.add("sh"); // 리눅스,맥 명령 프롬프트 실행
    command.add("-c"); // 명령어를 수행하고 종료한다는 옵션
    command.add("gdalinfo");
    command.add(filePath);
    command.add("|");
    command.add("grep");
    command.add("-i");
    command.add("Geo");

    ProcessBuilder processBuilder = new ProcessBuilder(command);
    processBuilder.redirectErrorStream(true);

    try {
      Process process = processBuilder.start();

      // 인코딩은 윈도우 한글 환경에 맞게 MS949로 지정
      BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

      String line;
      while ((line = reader.readLine()) != null) {
        // System.out.println(line);
        if (line.contains("Driver: GTiff/GeoTIFF")) {
          hasDriver = true;
          break;
        }
      }

      int exitCode = process.waitFor();

    } catch (Exception e) {
      e.printStackTrace();
    }

    return hasDriver;
  }
}
