package incheon.uis.uld.web;

import incheon.com.cmm.api.DefaultApiResponse;
import incheon.uis.uld.service.LayerSyncException;
import incheon.uis.uld.service.LayerSyncService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * 레이어 동기화 API Controller
 * 업로드된 레이어 데이터를 DB에 동기화 (INSERT/UPDATE/DELETE)
 *
 * 변경사항 (2025-01-30):
 * - 기존 upsert 방식을 순수 INSERT/UPDATE/DELETE로 변경
 * - 에러 유효성 검사 추가 (에러 발생 시 전체 rollback)
 * - 이력 테이블에 원본 데이터(프론트에서 넘어온 값) 직접 INSERT
 */
@RestController
@RequestMapping("/api/uis/uld/sync")
@RequiredArgsConstructor
@Slf4j
public class LayerSyncApiController {

    private final LayerSyncService layerSyncService;

    /**
     * 레이어 UPDATE 동기화
     *
     * 에러 체크:
     * - 에러C: PK 값 없음 -> "pk에 값이 없습니다."
     * - 에러D: 수정할 데이터 없음 -> "수정할 데이터가 없습니다."
     *
     * @param requestBody 요청 데이터
     *   - schemaName: 스키마명 (예: icuis)
     *   - tableName: 테이블명 (예: swl_pipe_l)
     *   - pkColumn: PK 컬럼명 (복합키는 콤마 구분, 예: ftc,idn)
     *   - srid: 대상 SRID (예: 5186) - DB에 저장될 좌표계
     *   - sourceSrid: 소스 SRID (예: 4326) - 전송된 GeoJSON의 좌표계
     *   - features: 피처 목록
     *     - geometryString: GeoJSON geometry 문자열
     *     - properties: 속성 Map (PK 값 포함)
     */
    @PostMapping("/update.do")
    public ResponseEntity<DefaultApiResponse<Map<String, Object>>> updateSync(
            @RequestBody Map<String, Object> requestBody) {
        try {
            Map<String, Object> resultData = layerSyncService.updateSync(requestBody);

            return ResponseEntity.ok(
                    DefaultApiResponse.success(resultData, "DB 업데이트가 완료되었습니다.")
            );

        } catch (LayerSyncException e) {
            log.warn("[LayerSync] UPDATE 유효성 검사 실패: {}", e.getErrors());
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("errors", e.getErrors());
            return ResponseEntity.badRequest().body(
                    DefaultApiResponse.<Map<String, Object>>builder()
                            .code(400)
                            .message("유효성 검사 실패")
                            .data(errorData)
                            .error("VALIDATION_ERROR")
                            .timestamp(java.time.LocalDateTime.now())
                            .build()
            );
        } catch (Exception e) {
            log.error("[LayerSync] UPDATE 실패", e);
            return ResponseEntity.internalServerError().body(
                    DefaultApiResponse.error(500, "DB 업데이트 실패: " + e.getMessage(), "INTERNAL_SERVER_ERROR")
            );
        }
    }

    /**
     * 레이어 DELETE 동기화 (Soft Delete: use_yn = 'N')
     *
     * 에러 체크:
     * - 에러E: PK 값 없음 -> "pk값이 없습니다."
     * - 에러F: 삭제할 데이터 없음 -> "삭제할 데이터가 없습니다."
     *
     * @param requestBody 요청 데이터
     *   - schemaName: 스키마명 (예: icuis)
     *   - tableName: 테이블명 (예: swl_pipe_l)
     *   - pkColumn: PK 컬럼명 (복합키는 콤마 구분, 예: ftc,idn)
     *   - features: 피처 목록
     *     - properties: 속성 Map (PK 값 포함)
     */
    @PostMapping("/delete.do")
    public ResponseEntity<DefaultApiResponse<Map<String, Object>>> deleteSync(
            @RequestBody Map<String, Object> requestBody) {
        try {
            Map<String, Object> resultData = layerSyncService.deleteSync(requestBody);

            return ResponseEntity.ok(
                    DefaultApiResponse.success(resultData, "삭제가 완료되었습니다.")
            );

        } catch (LayerSyncException e) {
            log.warn("[LayerSync] DELETE 유효성 검사 실패: {}", e.getErrors());
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("errors", e.getErrors());
            return ResponseEntity.badRequest().body(
                    DefaultApiResponse.<Map<String, Object>>builder()
                            .code(400)
                            .message("유효성 검사 실패")
                            .data(errorData)
                            .error("VALIDATION_ERROR")
                            .timestamp(java.time.LocalDateTime.now())
                            .build()
            );
        } catch (Exception e) {
            log.error("[LayerSync] DELETE 실패", e);
            return ResponseEntity.internalServerError().body(
                    DefaultApiResponse.error(500, "삭제 실패: " + e.getMessage(), "INTERNAL_SERVER_ERROR")
            );
        }
    }

    /**
     * 레이어 INSERT 동기화
     *
     * 에러 체크:
     * - 에러A: ftc(첫 번째 PK) 값 없음 -> "ftc 값이 없는 데이터가 있습니다."
     * - 에러B: PK 중복 -> "pk값이 중복이 있습니다."
     *
     * @param requestBody 요청 데이터
     *   - schemaName: 스키마명
     *   - tableName: 테이블명
     *   - pkColumn: PK 컬럼명 (복합키는 콤마 구분)
     *   - srid: 대상 SRID (DB 저장용)
     *   - sourceSrid: 소스 SRID (GeoJSON 좌표계)
     *   - features: 피처 목록
     */
    @PostMapping("/insert.do")
    public ResponseEntity<DefaultApiResponse<Map<String, Object>>> insertSync(
            @RequestBody Map<String, Object> requestBody) {
        try {
            Map<String, Object> resultData = layerSyncService.insertSync(requestBody);

            return ResponseEntity.ok(
                    DefaultApiResponse.success(resultData, "등록이 완료되었습니다.")
            );

        } catch (LayerSyncException e) {
            log.warn("[LayerSync] INSERT 유효성 검사 실패: {}", e.getErrors());
            Map<String, Object> errorData = new HashMap<>();
            errorData.put("errors", e.getErrors());
            return ResponseEntity.badRequest().body(
                    DefaultApiResponse.<Map<String, Object>>builder()
                            .code(400)
                            .message("유효성 검사 실패")
                            .data(errorData)
                            .error("VALIDATION_ERROR")
                            .timestamp(java.time.LocalDateTime.now())
                            .build()
            );
        } catch (Exception e) {
            log.error("[LayerSync] INSERT 실패", e);
            return ResponseEntity.internalServerError().body(
                    DefaultApiResponse.error(500, "등록 실패: " + e.getMessage(), "INTERNAL_SERVER_ERROR")
            );
        }
    }
}
