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

import com.kamco.cd.kamcoback.inference.dto.InferenceResultShpDto;
import com.kamco.cd.kamcoback.inference.dto.WriteCnt;
import com.kamco.cd.kamcoback.postgres.core.InferenceResultShpCoreService;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

  private final InferenceResultShpCoreService coreService;
  private final ShpWriter shpWriter;

  @Value("${mapsheet.shp.baseurl}")
  private String baseDir;

  /** inference_results 테이블을 기준으로 분석 결과 테이블과 도형 테이블을 최신 상태로 반영한다. */
  @Transactional
  public InferenceResultShpDto.InferenceCntDto saveInferenceResultData() {
    return coreService.buildInferenceData();
  }

  /**
   * 분석 데이터 단위로 SHP / GeoJSON 파일을 생성한다.
   *
   * <p>처리 흐름: 1. 파일 미생성 상태의 분석 데이터 조회 2. 재생성을 위한 상태 초기화 3. 도형 데이터 조회 4. SHP / GeoJSON 파일 생성 5. 파일
   * 생성 완료 상태 반영
   *
   * <p>중간 실패 시 다음 실행에서 전체 재생성된다.
   */
  @Transactional
  public InferenceResultShpDto.FileCntDto createShpFile() {

    // TODO 배치 실행으로 변경 필요
    int batchSize = 100;
    int geomLimit = 500_000;

    WriteCnt total = WriteCnt.zero();

    List<Long> dataUids = coreService.findPendingDataUids(batchSize);

    for (Long dataUid : dataUids) {

      // 재생성을 위한 생성 상태 초기화
      coreService.resetForRegenerate(dataUid);

      // 추론 데이터 조회
      List<InferenceResultShpDto.Basic> dtoList = coreService.loadGeomDtos(dataUid, geomLimit);
      if (dtoList.isEmpty()) {
        continue;
      }

      // 파일명 생성 (stage_mapSheet_compare_target)
      InferenceResultShpDto.Basic first = dtoList.get(0);
      String baseName =
          String.format(
              "%d_%d_%d_%d",
              first.getStage(), first.getMapId(), first.getInput1(), first.getInput2());

      String baseDir2 = "/" + first.getInput1() + "_" + first.getInput2() + "/" + first.getStage();
      String shpBasePath = baseDir + baseDir2 + "/shp/" + baseName;
      String geoJsonPath = baseDir + baseDir2 + "/geojson/" + baseName + ".geojson";

      try {
        // Writer가 "이번 호출에서 write한 개수"를 반환
        total = total.plus(shpWriter.writeShp(shpBasePath, dtoList));
        total = total.plus(shpWriter.writeGeoJson(geoJsonPath, dtoList));

        // 파일 생성 완료 상태 반영
        List<Long> geoUids = dtoList.stream().map(InferenceResultShpDto.Basic::getGeoUid).toList();
        coreService.markSuccess(dataUid, geoUids);

      } catch (Exception e) {
        // 실패 시 markSuccess 하지 않음 -> 다음 실행에서 재생성
        // log.warn("파일 생성 실패: dataUid={}, baseName={}", dataUid, baseName, e);
        continue;
      }
    }

    InferenceResultShpDto.FileCntDto fileCntDto = new InferenceResultShpDto.FileCntDto();
    fileCntDto.setShp(total.shp());
    fileCntDto.setShx(total.shx());
    fileCntDto.setDbf(total.dbf());
    fileCntDto.setPrj(total.prj());
    fileCntDto.setGeojson(total.geojson());

    return fileCntDto;
  }
}
