package incheon.sgp.thm.web;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

// 3rdParty Import
// 프로젝트 공통 Import
// 서브 업무 그룹 공통 Import
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import incheon.sgp.thm.dto.SgpThmBiotopeGeomDto;
import incheon.sgp.thm.service.SgpThmService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * 인덱스 페이지 컨트롤러
 * 루트 URL(/)에서 로그인 테스트 페이지를 제공합니다.
 */
@Slf4j
@Controller
@RequestMapping("/sgp/thm")
@RequiredArgsConstructor
public class SgpThmController {
    private final SgpThmService sgpThmService;
    private final ObjectMapper objectMapper;

    /**
     * 루트 페이지 - 주제도 메인 페이지
     */
    @GetMapping("/main.do")
    public String index(Model model, @RequestParam(defaultValue = "none") String name) {
        log.info("주제도 페이지 접근");

        model.addAttribute("pageTitle", "맞춤형 정책지도");
        model.addAttribute("headerTitle", "맞춤형 정책지도");

        model.addAttribute("categories", sgpThmService.getThemeCategories());
        model.addAttribute("themeMap", sgpThmService.getThemeLayersByCategory());

        model.addAttribute("startTheme", name);

        return "/sgp/thm/thmMapMain";
    }

    @GetMapping("/trf/player")
    public String getTrafficCctvPlayer(@RequestParam(required = false) String ch,
            @RequestParam(required = false) String url) {
        return "/sgp/thm/thmTrafficCctvPlayer";
    }

    /**
     * 선거구 Geometry 조회 API
     *
     * @param poiId 주제도 POI ID (예: "incheon_elec_districts_28010_001")
     * @return GeoJSON 문자열
     *
     * @example
     *          GET /sgp/thm/elec/geom?poiId=incheon_elec_districts_28010_001
     *
     *          Response:
     *          {
     *          "type": "Polygon",
     *          "coordinates": [[[126.123, 37.456], [126.124, 37.457], ...]]
     *          }
     */
    @GetMapping("/elec/geom")
    @ResponseBody
    public ResponseEntity<String> getElectionGeom(@RequestParam String poiId) {
        try {
            log.debug("선거구 geometry 조회 요청: poiId={}", poiId);

            String geomJson = sgpThmService.getElectionGeomByPoiId(poiId);

            if (geomJson == null || geomJson.trim().isEmpty()) {
                log.warn("선거구 geometry 없음: poiId={}", poiId);
                return ResponseEntity.notFound().build();
            }

            return ResponseEntity.ok()
                    .contentType(MediaType.APPLICATION_JSON)
                    .cacheControl(CacheControl.maxAge(1, TimeUnit.HOURS))
                    .body(geomJson);

        } catch (IllegalArgumentException e) {
            log.error("잘못된 요청: {}", e.getMessage());
            return ResponseEntity.badRequest().build();

        } catch (Exception e) {
            log.error("선거구 geometry 조회 실패: poiId={}", poiId, e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    /**
     * 비오톱 전체 Geometry 및 bio_val 조회 API (한 번에 전체)
     *
     * @return JSON 응답 배열 [ { poi_id, geom, bio_val }, ... ]
     *
     * @example
     *          GET /sgp/thm/biotope/geoms
     *
     *          Response:
     *          [
     *          { "poi_id": "BIOTP_10_30485", "geom":
     *          "{\"type\":\"MultiPolygon\",...}", "bio_val": "Ⅳ" },
     *          { "poi_id": "BIOTP_10_30416", "geom":
     *          "{\"type\":\"MultiPolygon\",...}", "bio_val": "Ⅲ" },
     *          ...
     *          ]
     */
    @GetMapping("/biotope/geoms")
    @ResponseBody
    public ResponseEntity<List<SgpThmBiotopeGeomDto>> getAllBiotopeGeoms() {
        try {
            log.debug("비오톱 전체 geometry 조회 요청");

            List<SgpThmBiotopeGeomDto> results = sgpThmService.getAllBiotopeGeoms();

            log.info("비오톱 전체 geometry 조회 완료: {} 건", results.size());

            return ResponseEntity.ok()
                    .contentType(MediaType.APPLICATION_JSON)
                    .cacheControl(CacheControl.maxAge(1, TimeUnit.HOURS))
                    .body(results);

        } catch (Exception e) {
            log.error("비오톱 전체 geometry 조회 실패", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    /**
     * 비오톱 전체 Geometry NDJSON 스트리밍 API
     * 
     * 줄 단위 JSON 스트리밍으로 메모리 효율적인 데이터 전송
     * Content-Type: application/x-ndjson
     *
     * @return NDJSON 스트리밍 응답
     *
     * @example
     *          GET /sgp/thm/biotope/geoms.ndjson
     *
     *          Response (스트리밍):
     *          {"poi_id":"BIOTP_10_00001","geom":{...},"bio_val":"Ⅲ"}
     *          {"poi_id":"BIOTP_10_00002","geom":{...},"bio_val":"Ⅳ"}
     *          ...
     */
    @GetMapping(value = "/biotope/geoms.ndjson", produces = "application/x-ndjson")
    public ResponseEntity<StreamingResponseBody> getAllBiotopeGeomsNdjson() {
        log.debug("비오톱 전체 geometry NDJSON 스트리밍 요청");

        StreamingResponseBody body = outputStream -> {
            try {
                sgpThmService.streamAllBiotopeGeoms(outputStream, objectMapper);
            } finally {
                outputStream.flush();
            }
        };

        return ResponseEntity.ok()
                .header("Content-Type", "application/x-ndjson")
                .header("Transfer-Encoding", "chunked")
                .cacheControl(CacheControl.maxAge(1, TimeUnit.HOURS))
                .body(body);
    }

    /**
     * thm_wind 메타데이터 생성/갱신 API
     * filename 미입력 시 서버 기본 포맷으로 자동 생성
     * date 또는 year/month/day/time 분리 입력 지원
     */
    @PostMapping(value = "/wind", produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public ResponseEntity<Map<String, Object>> upsertWindMeta(
            @RequestParam(required = false) String date,
            @RequestParam(required = false) Integer year,
            @RequestParam(required = false) Integer month,
            @RequestParam(required = false) Integer day,
            @RequestParam(required = false) String time,
            @RequestParam(required = false) String filename) {
        try {
            Map<String, Object> saved = sgpThmService.upsertWindMeta(date, year, month, day, time, filename);
            return ResponseEntity.ok(saved);
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(Map.of("message", e.getMessage()));
        } catch (Exception e) {
            log.error("thm_wind 저장 실패", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(Map.of("message", "thm_wind 저장 중 오류가 발생했습니다."));
        }
    }

    /**
     * thm_wind 메타데이터 조회 API
     */
    @GetMapping(value = "/wind", produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public ResponseEntity<?> searchWindMeta(
            @RequestParam(required = false) String date,
            @RequestParam(required = false) String date2,
            @RequestParam(required = false) String filename) {
        try {
            return ResponseEntity.ok(sgpThmService.searchWindMeta(date, date2, filename));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().body(Map.of("message", e.getMessage()));
        } catch (Exception e) {
            log.error("thm_wind 조회 실패", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(Map.of("message", "thm_wind 조회 중 오류가 발생했습니다."));
        }
    }
}
