package com.kamco.cd.kamcoback.inference;

import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto;
import com.kamco.cd.kamcoback.inference.dto.LearningModelResultDto;
import com.kamco.cd.kamcoback.inference.service.InferenceResultService;
import com.kamco.cd.kamcoback.inference.service.LearningModelResultProcessor;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "추론관리 분석결과", description = "추론관리 분석결과")
@RequestMapping({"/api/inf/res"})
@RequiredArgsConstructor
@RestController
public class InferenceResultApiController {

  private static final Logger logger = LoggerFactory.getLogger(InferenceResultApiController.class);

  private final InferenceResultService inferenceResultService;
  private final LearningModelResultProcessor learningModelResultProcessor;

  @Operation(summary = "추론관리 분석결과 목록 조회", description = "분석상태, 제목으로 분석결과를 조회 합니다.")
  @ApiResponses(
      value = {
        @ApiResponse(
            responseCode = "200",
            description = "검색 성공",
            content =
                @Content(
                    mediaType = "application/json",
                    schema = @Schema(implementation = Page.class))),
        @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
        @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
      })
  @GetMapping("/list")
  public ApiResponseDto<Page<InferenceResultDto.AnalResList>> getInferenceResultList(
      @Parameter(description = "분석상태", example = "0002") @RequestParam(required = false)
          String statCode,
      @Parameter(description = "제목", example = "변화탐지") @RequestParam(required = false) String title,
      @Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0")
          int page,
      @Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20")
          int size) {
    InferenceResultDto.SearchReq searchReq =
        new InferenceResultDto.SearchReq(statCode, title, page, size);
    Page<InferenceResultDto.AnalResList> analResList =
        inferenceResultService.getInferenceResultList(searchReq);
    return ApiResponseDto.ok(analResList);
  }

  @Operation(summary = "추론관리 분석결과 요약정보", description = "분석결과 요약정보를 조회합니다.")
  @ApiResponses(
      value = {
        @ApiResponse(
            responseCode = "200",
            description = "검색 성공",
            content =
                @Content(
                    mediaType = "application/json",
                    schema = @Schema(implementation = InferenceResultDto.AnalResSummary.class))),
        @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
        @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
      })
  @GetMapping("/summary/{id}")
  public ApiResponseDto<InferenceResultDto.AnalResSummary> getInferenceResultSummary(
      @Parameter(description = "목록 id", example = "1") @PathVariable Long id) {
    return ApiResponseDto.ok(inferenceResultService.getInferenceResultSummary(id));
  }

  @Operation(summary = "추론관리 분석결과 상세", description = "분석결과 상제 정보 Summary, DashBoard")
  @ApiResponses(
      value = {
        @ApiResponse(
            responseCode = "200",
            description = "검색 성공",
            content =
                @Content(
                    mediaType = "application/json",
                    schema = @Schema(implementation = InferenceResultDto.Detail.class))),
        @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
        @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
      })
  @GetMapping("/detail/{id}")
  public ApiResponseDto<InferenceResultDto.Detail> getInferenceDetail(
      @Parameter(description = "목록 id", example = "1") @PathVariable Long id) {
    return ApiResponseDto.ok(inferenceResultService.getDetail(id));
  }

  @Operation(summary = "추론관리 분석결과 상세 목록", description = "추론관리 분석결과 상세 목록 geojson 데이터 조회")
  @ApiResponses(
      value = {
        @ApiResponse(
            responseCode = "200",
            description = "검색 성공",
            content =
                @Content(
                    mediaType = "application/json",
                    schema = @Schema(implementation = Page.class))),
        @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
        @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
      })
  @GetMapping("/geom/{id}")
  public ApiResponseDto<Page<InferenceResultDto.Geom>> getInferenceResultGeomList(
      @Parameter(description = "분석결과 id", example = "1") @PathVariable Long id,
      @Parameter(description = "기준년도 분류", example = "land") @RequestParam(required = false)
          String targetClass,
      @Parameter(description = "비교년도 분류", example = "waste") @RequestParam(required = false)
          String compareClass,
      @Parameter(description = "5000:1 도협번호 37801011,37801012") @RequestParam(required = false)
          List<Long> mapSheetNum,
      @Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0")
          int page,
      @Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20")
          int size,
      @Parameter(description = "정렬 조건 (형식: 필드명,방향)", example = "name,asc")
          @RequestParam(required = false)
          String sort) {
    InferenceResultDto.SearchGeoReq searchGeoReq =
        new InferenceResultDto.SearchGeoReq(
            targetClass, compareClass, mapSheetNum, page, size, sort);
    Page<InferenceResultDto.Geom> geomList =
        inferenceResultService.getInferenceResultGeomList(id, searchGeoReq);
    return ApiResponseDto.ok(geomList);
  }

  //  @Operation(summary = "학습모델 결과 처리", description = "실제 학습모델 GeoJSON 파일을 처리하여 데이터베이스에 저장합니다.")
  //  @ApiResponses(
  //      value = {
  //        @ApiResponse(
  //            responseCode = "200",
  //            description = "처리 성공",
  //            content =
  //                @Content(
  //                    mediaType = "application/json",
  //                    schema =
  //                        @Schema(implementation =
  // LearningModelResultDto.ProcessResponse.class))),
  //        @ApiResponse(responseCode = "400", description = "잘못된 요청", content = @Content),
  //        @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
  //      })
  //  @PostMapping("/learning-model/process")
  public ApiResponseDto<LearningModelResultDto.ProcessResponse> processLearningModelResult(
      @RequestBody LearningModelResultDto.ProcessRequest request) {
    try {
      logger.info("Processing learning model result file: {}", request.getFilePath());

      Path filePath = Paths.get(request.getFilePath());
      int processedFeatures = learningModelResultProcessor.processLearningModelResult(filePath);

      LearningModelResultDto.ProcessResponse response =
          LearningModelResultDto.ProcessResponse.builder()
              .success(true)
              .message("학습모델 결과 처리가 완료되었습니다.")
              .processedFeatures(processedFeatures)
              .filePath(request.getFilePath())
              .build();

      logger.info(
          "Successfully processed {} features from file: {}",
          processedFeatures,
          request.getFilePath());
      return ApiResponseDto.ok(response);

    } catch (Exception e) {
      logger.error("Failed to process learning model result: {}", request.getFilePath(), e);

      LearningModelResultDto.ProcessResponse response =
          LearningModelResultDto.ProcessResponse.builder()
              .success(false)
              .message("학습모델 결과 처리 중 오류가 발생했습니다: " + e.getMessage())
              .processedFeatures(0)
              .filePath(request.getFilePath())
              .build();

      return ApiResponseDto.ok(response);
    }
  }

  //  @Operation(summary = "학습모델 결과 일괄 처리", description = "여러 학습모델 GeoJSON 파일을 일괄 처리하여 데이터베이스에
  // 저장합니다.")
  //  @ApiResponses(
  //      value = {
  //        @ApiResponse(
  //            responseCode = "200",
  //            description = "처리 성공",
  //            content =
  //                @Content(
  //                    mediaType = "application/json",
  //                    schema =
  //                        @Schema(
  //                            implementation =
  // LearningModelResultDto.BatchProcessResponse.class))),
  //        @ApiResponse(responseCode = "400", description = "잘못된 요청", content = @Content),
  //        @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
  //      })
  //  @PostMapping("/learning-model/process-batch")
  public ApiResponseDto<LearningModelResultDto.BatchProcessResponse>
      processBatchLearningModelResults(
          @RequestBody LearningModelResultDto.BatchProcessRequest request) {
    try {
      logger.info("Processing {} learning model result files", request.getFilePaths().size());

      List<Path> filePaths = new ArrayList<>();
      for (String filePath : request.getFilePaths()) {
        filePaths.add(Paths.get(filePath));
      }

      int totalProcessedFeatures =
          learningModelResultProcessor.processMultipleLearningModelResults(filePaths);

      LearningModelResultDto.BatchProcessResponse response =
          LearningModelResultDto.BatchProcessResponse.builder()
              .success(true)
              .message("일괄 학습모델 결과 처리가 완료되었습니다.")
              .totalProcessedFeatures(totalProcessedFeatures)
              .processedFileCount(request.getFilePaths().size())
              .filePaths(request.getFilePaths())
              .build();

      logger.info(
          "Successfully processed {} features from {} files",
          totalProcessedFeatures,
          request.getFilePaths().size());
      return ApiResponseDto.ok(response);

    } catch (Exception e) {
      logger.error("Failed to process batch learning model results", e);

      LearningModelResultDto.BatchProcessResponse response =
          LearningModelResultDto.BatchProcessResponse.builder()
              .success(false)
              .message("일괄 학습모델 결과 처리 중 오류가 발생했습니다: " + e.getMessage())
              .totalProcessedFeatures(0)
              .processedFileCount(0)
              .filePaths(request.getFilePaths())
              .build();

      return ApiResponseDto.ok(response);
    }
  }

  //  @Operation(summary = "기본 학습모델 파일 처리", description = "미리 준비된 학습모델 파일을 처리합니다.")
  //  @ApiResponses(
  //      value = {
  //        @ApiResponse(
  //            responseCode = "200",
  //            description = "처리 성공",
  //            content =
  //                @Content(
  //                    mediaType = "application/json",
  //                    schema =
  //                        @Schema(
  //                            implementation =
  // LearningModelResultDto.BatchProcessResponse.class))),
  //        @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
  //      })
  //  @PostMapping("/learning-model/process-default")
  public ApiResponseDto<LearningModelResultDto.BatchProcessResponse>
      processDefaultLearningModelResults() {
    try {
      logger.info("Processing default learning model result files");

      // Process the two default learning model files from upload directory
      List<String> defaultFilePaths =
          List.of(
              "/Users/deniallee/geojson/upload/캠코_2021_2022_35813023.geojson",
              "/Users/deniallee/geojson/upload/캠코_2023_2024_35810049.geojson");

      List<Path> filePaths = new ArrayList<>();
      for (String filePath : defaultFilePaths) {
        filePaths.add(Paths.get(filePath));
      }

      int totalProcessedFeatures =
          learningModelResultProcessor.processMultipleLearningModelResults(filePaths);

      LearningModelResultDto.BatchProcessResponse response =
          LearningModelResultDto.BatchProcessResponse.builder()
              .success(true)
              .message("기본 학습모델 결과 파일 처리가 완료되었습니다.")
              .totalProcessedFeatures(totalProcessedFeatures)
              .processedFileCount(defaultFilePaths.size())
              .filePaths(defaultFilePaths)
              .build();

      logger.info(
          "Successfully processed {} features from {} default files",
          totalProcessedFeatures,
          defaultFilePaths.size());
      return ApiResponseDto.ok(response);

    } catch (Exception e) {
      logger.error("Failed to process default learning model results", e);

      LearningModelResultDto.BatchProcessResponse response =
          LearningModelResultDto.BatchProcessResponse.builder()
              .success(false)
              .message("기본 학습모델 결과 처리 중 오류가 발생했습니다: " + e.getMessage())
              .totalProcessedFeatures(0)
              .processedFileCount(0)
              .filePaths(List.of())
              .build();

      return ApiResponseDto.ok(response);
    }
  }
}
