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

import com.kamco.cd.kamcoback.geojson.config.GeoJsonMonitorConfig;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.springframework.stereotype.Service;

/** 압축파일 처리 서비스 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ArchiveExtractorService {

  private final GeoJsonMonitorConfig config;

  /** 압축파일에서 GeoJSON 파일들을 추출 */
  public Map<String, String> extractGeoJsonFiles(Path archiveFile) throws IOException {
    Map<String, String> geoJsonContents = new HashMap<>();
    String fileName = archiveFile.getFileName().toString().toLowerCase();

    log.info("압축파일 추출 시작: {}", archiveFile);

    try {
      if (fileName.endsWith(".zip")) {
        extractFromZip(archiveFile, geoJsonContents);
      } else if (fileName.endsWith(".tar")
          || fileName.endsWith(".tar.gz")
          || fileName.endsWith(".tgz")) {
        extractFromTar(archiveFile, geoJsonContents);
      } else {
        throw new IllegalArgumentException("지원하지 않는 압축파일 형식: " + fileName);
      }
    } catch (Exception e) {
      log.error("압축파일 추출 실패: {}", archiveFile, e);
      throw e;
    }

    log.info("압축파일에서 {}개의 GeoJSON 파일을 추출했습니다: {}", geoJsonContents.size(), archiveFile);
    return geoJsonContents;
  }

  /** ZIP 파일에서 GeoJSON 추출 */
  private void extractFromZip(Path zipFile, Map<String, String> geoJsonContents)
      throws IOException {
    try (ZipFile zip = new ZipFile(zipFile.toFile())) {
      Enumeration<ZipArchiveEntry> entries = zip.getEntries();

      while (entries.hasMoreElements()) {
        ZipArchiveEntry entry = entries.nextElement();

        if (!entry.isDirectory() && isGeoJsonFile(entry.getName())) {
          try (InputStream inputStream = zip.getInputStream(entry)) {
            String content = readInputStream(inputStream);
            geoJsonContents.put(entry.getName(), content);
            log.debug("ZIP에서 추출: {}", entry.getName());
          }
        }
      }
    }
  }

  /** TAR 파일에서 GeoJSON 추출 */
  private void extractFromTar(Path tarFile, Map<String, String> geoJsonContents)
      throws IOException {
    String fileName = tarFile.getFileName().toString().toLowerCase();
    InputStream fileInputStream = Files.newInputStream(tarFile);

    try {
      // GZIP 압축된 TAR 파일인지 확인
      if (fileName.endsWith(".gz") || fileName.endsWith(".tgz")) {
        fileInputStream = new GzipCompressorInputStream(fileInputStream);
      }

      try (TarArchiveInputStream tarInputStream = new TarArchiveInputStream(fileInputStream)) {
        ArchiveEntry entry;

        while ((entry = tarInputStream.getNextEntry()) != null) {
          if (!entry.isDirectory() && isGeoJsonFile(entry.getName())) {
            String content = readInputStream(tarInputStream);
            geoJsonContents.put(entry.getName(), content);
            log.debug("TAR에서 추출: {}", entry.getName());
          }
        }
      }
    } finally {
      try {
        fileInputStream.close();
      } catch (IOException e) {
        log.warn("파일 스트림 종료 실패", e);
      }
    }
  }

  /** InputStream에서 문자열 읽기 */
  private String readInputStream(InputStream inputStream) throws IOException {
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"))) {
      StringBuilder content = new StringBuilder();
      String line;

      while ((line = reader.readLine()) != null) {
        content.append(line).append("\n");
      }

      return content.toString();
    }
  }

  /** 파일이 GeoJSON 파일인지 확인 */
  private boolean isGeoJsonFile(String fileName) {
    String lowerFileName = fileName.toLowerCase();
    return lowerFileName.endsWith(".geojson") || lowerFileName.endsWith(".json");
  }

  /** 지원하는 압축파일인지 확인 */
  public boolean isSupportedArchive(Path file) {
    String fileName = file.getFileName().toString().toLowerCase();

    for (String extension : config.getSupportedExtensions()) {
      if (fileName.endsWith("." + extension)) {
        return true;
      }
    }

    return false;
  }

  /** 파일 크기가 제한 범위 내인지 확인 */
  public boolean isFileSizeValid(Path file) {
    try {
      long fileSize = Files.size(file);
      boolean isValid = fileSize <= config.getMaxFileSize();

      if (!isValid) {
        log.warn(
            "파일 크기가 제한을 초과했습니다: {} ({}MB > {}MB)",
            file,
            fileSize / 1024 / 1024,
            config.getMaxFileSize() / 1024 / 1024);
      }

      return isValid;
    } catch (IOException e) {
      log.error("파일 크기 확인 실패: {}", file, e);
      return false;
    }
  }
}
