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

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.Basic;
import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastReq;
import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.DetectMastSearch;
import com.kamco.cd.kamcoback.Innopam.dto.DetectMastDto.FeaturePnuDto;
import com.kamco.cd.kamcoback.Innopam.postgres.core.DetectMastCoreService;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

  @Value("${spring.profiles.active:local}")
  private String profile;

  private final DetectMastCoreService detectMastCoreService;
  private final JsonFactory jsonFactory = new JsonFactory();

  @Transactional
  public void saveDetectMast(DetectMastReq detectMast) {
    detectMastCoreService.saveDetectMast(detectMast);
    //
    //    String dirPath =
    //      "local".equals(profile)
    //        ? "/Users/bokmin/detect/result/2023_2024/4"
    //        : detectMast.getPathNm();
    //
    //    List<FeaturePnuDto> list = this.extractFeaturePnusRandom(dirPath);
  }

  public List<Basic> selectDetectMast(DetectMastSearch detectMast) {
    return detectMastCoreService.selectDetectMast(detectMast);
  }

  public Basic selectDetectMast(Long id) {
    return detectMastCoreService.selectDetectMast(id);
  }

  /** GeoJSON → polygon_id + 랜덤 PNU */
  public List<FeaturePnuDto> findPnuData(DetectMastSearch detectMast) {

    String dirPath =
        "local".equals(profile)
            ? "/Users/bokmin/detect/result/2023_2024/4"
            : detectMastCoreService.findPnuData(detectMast);

    return extractFeaturePnusRandom(dirPath);
  }

  /** 하위 폴더까지 .geojson 파일들에서 polygon_id만 뽑음 병렬처리(parallel) 제거: IO + parallel은 거의 항상 느려짐 */
  private List<FeaturePnuDto> extractFeaturePnusRandom(String dirPath) {

    Path basePath = Paths.get(dirPath);
    if (!Files.isDirectory(basePath)) {
      System.err.println("유효하지 않은 디렉터리: " + dirPath);
      return List.of();
    }

    List<FeaturePnuDto> out = new ArrayList<>(4096);

    try (Stream<Path> stream = Files.walk(basePath)) {
      stream
          .filter(Files::isRegularFile)
          .filter(p -> p.toString().toLowerCase().endsWith(".geojson"))
          .forEach(
              p -> {
                try (InputStream in = Files.newInputStream(p);
                    JsonParser parser = jsonFactory.createParser(in)) {

                  while (parser.nextToken() != null) {
                    if (parser.currentToken() == JsonToken.FIELD_NAME
                        && "polygon_id".equals(parser.getCurrentName())) {

                      JsonToken next = parser.nextToken(); // 값으로 이동
                      if (next == JsonToken.VALUE_STRING) {
                        String polygonId = parser.getValueAsString();
                        out.add(new FeaturePnuDto(polygonId, randomPnu()));
                      }
                    }
                  }

                } catch (Exception e) {
                  // 파일 단위 실패는 최소 로그
                  System.err.println("GeoJSON 파싱 실패: " + p.getFileName() + " / " + e.getMessage());
                }
              });

    } catch (Exception e) {
      System.err.println("디렉터리 탐색 실패: " + e.getMessage());
      return List.of();
    }

    return out;
  }

  /** 랜덤 PNU 생성 (임시) - 법정동코드(5) + 산구분(1) + 본번(4) + 부번(4) = 14자리 */
  private String randomPnu() {
    ThreadLocalRandom r = ThreadLocalRandom.current();

    String dongCode = String.format("%05d", r.nextInt(10000, 99999));
    String san = r.nextBoolean() ? "1" : "2";
    String bon = String.format("%04d", r.nextInt(1, 10000));
    String bu = String.format("%04d", r.nextInt(0, 10000));

    return dongCode + san + bon + bu;
  }
}
