package gc.mda.signal_batch.domain.gis.controller;

import gc.mda.signal_batch.domain.gis.dto.AreaSearchRequest;
import gc.mda.signal_batch.domain.gis.dto.AreaSearchResponse;
import gc.mda.signal_batch.domain.gis.dto.VesselContactRequest;
import gc.mda.signal_batch.domain.gis.dto.VesselContactResponse;
import gc.mda.signal_batch.domain.gis.service.AreaSearchService;
import gc.mda.signal_batch.domain.gis.service.VesselContactService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
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 jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/api/v2/tracks")
@RequiredArgsConstructor
@Tag(name = "항적 조회 API V2", description = "해구/영역별 선박 항적 조회 API (WebSocket 호환 CompactVesselTrack 응답)")
public class AreaSearchController {

    private final AreaSearchService areaSearchService;
    private final VesselContactService vesselContactService;

    @PostMapping("/area-search")
    @Operation(
        summary = "다중 폴리곤 영역 내 선박 탐색",
        description = """
            인메모리 캐시(D-1~D-7)를 활용하여 사용자 지정 다중 폴리곤 영역 내 선박을 탐색합니다.

            **검색 모드 (폴리곤 2개 이상 시):**
            - **ANY**: 합집합 - 어느 한 영역이라도 통과한 선박 (개별 방문 분리)
            - **ALL**: 교집합 - 모든 영역을 통과한 선박 (개별 방문 분리)
            - **SEQUENTIAL**: 순차 통과 - 모든 영역을 지정된 순서대로 통과한 선박 (유효 체인만 반환)

            **폴리곤 1개일 때:** mode는 무시되며, 해당 영역 히트 선박 + 전체 트랙 반환

            **개별 방문(trip) 분리:**
            - 동일 구역을 여러 번 진입/진출하면 각각 별도 PolygonHitDetail로 반환
            - visitIndex: 해당 구역의 방문 순번 (1-based)
            - hitDetails 배열은 entryTimestamp 오름차순 정렬 (배열 인덱스 = 전체 방문 순서)
            - SEQUENTIAL 모드: 순서가 성립하는 체인만 반환, visitIndex=1로 재설정

            **경계 보간 타임스탬프:**
            - entryTimestamp/exitTimestamp는 폴리곤 경계 통과 시각을 거리 비율로 보간
            - outside↔inside 전환 포인트 사이의 경계 교차점 기준

            **응답 구조:**
            - `tracks`: 기존 V2 API와 동일한 CompactVesselTrack 배열 (프론트엔드 렌더링 호환)
            - `hitDetails`: 선박별 영역 히트 메타데이터 (방문별 진입/진출 시간, 히트 포인트 수, visitIndex)
            - `summary`: 검색 요약 (선박 수, 포인트 수, 처리 시간 등)

            **제약사항:**
            - 캐시된 날짜 범위만 조회 가능 (D-1 ~ D-7, 오늘 제외)
            - 폴리곤 최대 10개
            - 폴리곤 좌표는 닫힌 형태 (첫점 == 끝점)
            - 캐시 미준비 시 503 반환
            """
    )
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "탐색 성공",
            content = @Content(
                mediaType = "application/json",
                schema = @Schema(implementation = AreaSearchResponse.class)
            )),
        @ApiResponse(responseCode = "400", description = "잘못된 요청 (날짜 범위 초과, 잘못된 폴리곤 등)",
            content = @Content(
                mediaType = "application/json",
                examples = @ExampleObject(value = "{\"error\": \"폴리곤 'zone_A'이 유효하지 않습니다 (자기 교차 등)\"}")
            )),
        @ApiResponse(responseCode = "503", description = "캐시 미준비 (LOADING 상태)",
            content = @Content(
                mediaType = "application/json",
                examples = @ExampleObject(value = "{\"error\": \"캐시가 아직 준비되지 않았습니다 (상태: LOADING)\"}")
            ))
    })
    public ResponseEntity<AreaSearchResponse> searchArea(
            @io.swagger.v3.oas.annotations.parameters.RequestBody(
                description = "다중 폴리곤 영역 탐색 요청",
                required = true,
                content = @Content(
                    schema = @Schema(implementation = AreaSearchRequest.class),
                    examples = @ExampleObject(
                        name = "순차 통과 예시",
                        value = """
                            {
                              "startTime": "2026-02-01T00:00:00",
                              "endTime": "2026-02-07T23:59:59",
                              "mode": "SEQUENTIAL",
                              "polygons": [
                                {
                                  "id": "zone_A", "name": "대한해협 서수도",
                                  "coordinates": [[128.5,34.0],[129.5,34.0],[129.5,35.0],[128.5,35.0],[128.5,34.0]]
                                },
                                {
                                  "id": "zone_B", "name": "제주해협",
                                  "coordinates": [[126.0,33.0],[127.0,33.0],[127.0,34.0],[126.0,34.0],[126.0,33.0]]
                                }
                              ]
                            }
                            """
                    )
                )
            )
            @Valid @RequestBody AreaSearchRequest request) {

        log.info("Area search request: mode={}, polygons={}, timeRange={} ~ {}",
                request.getMode(), request.getPolygons().size(),
                request.getStartTime(), request.getEndTime());

        return ResponseEntity.ok(areaSearchService.search(request));
    }

    @PostMapping("/vessel-contacts")
    @Operation(
        summary = "비정상 접촉 선박 탐색",
        description = """
            인메모리 캐시(D-1~D-7)를 활용하여 지정 폴리곤 영역 내에서
            일정 시간 이상, 일정 거리 이내에 머문 선박 쌍을 탐색합니다.

            **접촉 판정 조건:**
            - 두 선박 모두 폴리곤 **내부**에 있을 때만 접촉으로 간주
            - 대상: AIS 수집 선박끼리만 비교
            - 접촉 구간의 **평균 거리** <= maxContactDistanceMeters
            - 접촉 지속 시간 >= minContactDurationMinutes

            **파라미터 범위:**
            - minContactDurationMinutes: 30분 ~ 360분 (6시간)
            - maxContactDistanceMeters: 50m ~ 5,000m (5km)

            **알고리즘:**
            - Two-pointer 시간 동기화 (허용 오차 10분)
            - 연속 세그먼트 분리 (갭 > 20분 시 분리)
            - 세그먼트별 평균 거리로 판정 (일시적 초과 허용)

            **다중 매칭:** A, B, C 3척이 모두 기준 충족 시 AB, AC, BC 3쌍 각각 반환

            **환적 의심 지표:**
            - lowSpeedContact: 양 선박 < 3 knots (정박/표류 중 접촉)
            - differentVesselTypes: 이종 선박 접촉 (어선↔화물선 등)
            - differentNationalities: 외국선 간 접촉
            - nightTimeContact: 야간 접촉 (22:00~06:00 KST)

            **제약사항:**
            - 캐시된 날짜 범위만 조회 가능 (D-1 ~ D-7, 오늘 제외)
            - 폴리곤 좌표는 닫힌 형태 (첫점 == 끝점)
            - 캐시 미준비 시 503 반환
            """
    )
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "탐색 성공",
            content = @Content(
                mediaType = "application/json",
                schema = @Schema(implementation = VesselContactResponse.class)
            )),
        @ApiResponse(responseCode = "400", description = "잘못된 요청",
            content = @Content(
                mediaType = "application/json",
                examples = @ExampleObject(value = "{\"error\": \"최소 접촉 지속 시간은 30분 이상이어야 합니다\"}")
            )),
        @ApiResponse(responseCode = "503", description = "캐시 미준비 (LOADING 상태)",
            content = @Content(
                mediaType = "application/json",
                examples = @ExampleObject(value = "{\"error\": \"캐시가 아직 준비되지 않았습니다 (상태: LOADING)\"}")
            ))
    })
    public ResponseEntity<VesselContactResponse> searchVesselContacts(
            @io.swagger.v3.oas.annotations.parameters.RequestBody(
                description = "비정상 접촉 선박 탐색 요청",
                required = true,
                content = @Content(
                    schema = @Schema(implementation = VesselContactRequest.class),
                    examples = @ExampleObject(
                        name = "접촉 탐색 예시",
                        value = """
                            {
                              "startTime": "2026-02-01T00:00:00",
                              "endTime": "2026-02-07T23:59:59",
                              "polygon": {
                                "id": "zone_A", "name": "동해 남부 해역",
                                "coordinates": [[129.0,34.5],[130.0,34.5],[130.0,35.5],[129.0,35.5],[129.0,34.5]]
                              },
                              "minContactDurationMinutes": 60,
                              "maxContactDistanceMeters": 1000
                            }
                            """
                    )
                )
            )
            @Valid @RequestBody VesselContactRequest request) {

        log.info("Vessel contact search request: polygon={}, duration={}min, distance={}m, timeRange={} ~ {}",
                request.getPolygon().getId(), request.getMinContactDurationMinutes(),
                request.getMaxContactDistanceMeters(), request.getStartTime(), request.getEndTime());

        return ResponseEntity.ok(vesselContactService.search(request));
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<Map<String, String>> handleBadRequest(IllegalArgumentException e) {
        log.warn("Area search bad request: {}", e.getMessage());
        return ResponseEntity.badRequest()
                .body(Map.of("error", e.getMessage()));
    }

    @ExceptionHandler(AreaSearchService.CacheNotReadyException.class)
    public ResponseEntity<Map<String, String>> handleCacheNotReady(AreaSearchService.CacheNotReadyException e) {
        log.warn("Area search cache not ready: {}", e.getMessage());
        return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
                .body(Map.of("error", e.getMessage()));
    }
}
