package incheon.product.geoview2d.layer.web;

import incheon.com.cmm.api.DefaultApiResponse;
import incheon.com.cmm.exception.BusinessException;
import incheon.com.security.vo.LoginVO;
import incheon.product.geoview2d.layer.service.LayerEditService;
import incheon.product.geoview2d.layer.service.TaskLayerService;
import incheon.product.geoview2d.layer.vo.LayerEditRequestVO;
import incheon.product.geoview2d.layer.vo.LayerEditResultVO;
import incheon.product.geoview2d.layer.vo.TaskLayerSearchVO;
import incheon.product.geoview2d.layer.vo.TaskLayerVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
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;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 레이어 REST API 컨트롤러.
 * 레이어 편집과 업무 레이어 조회를 통합 제공한다.
 *
 * 엔드포인트:
 *   - /api/v1/product/g2d/layers/edit  (편집)
 *   - /api/v1/product/g2d/layers/task  (업무 레이어 조회)
 *   - /api/v1/product/g2d/layers/task/{id}  (업무 레이어 상세)
 */
@Slf4j
@RestController
@RequestMapping("/api/v1/product/g2d/layers")
public class ProductLayerApiController {

    @Resource(name = "productLayerEditService")
    private LayerEditService layerEditService;

    @Resource(name = "productTaskLayerService")
    private TaskLayerService taskLayerService;

    /**
     * 레이어 편집 (Added/Modified/Deleted 통합 처리).
     */
    @PostMapping("/edit")
    public ResponseEntity<DefaultApiResponse<LayerEditResultVO>> editLayer(@Valid @RequestBody LayerEditRequestVO request) {
        log.debug("레이어 편집 요청 - layerId: {}, layerType: {}", request.getLayerId(), request.getLayerType());

        String currentUserId = getCurrentUserId();
        LayerEditResultVO result = layerEditService.editLayer(request, currentUserId);

        return ResponseEntity.ok(DefaultApiResponse.success(result, "레이어 편집이 완료되었습니다."));
    }

    /**
     * 업무 레이어 목록 조회 (페이징/검색).
     */
    @GetMapping("/task")
    public ResponseEntity<DefaultApiResponse<Map<String, Object>>> getTaskLayerList(TaskLayerSearchVO searchVO) {
        if (searchVO.getPageIndex() < 1) {
            searchVO.setPageIndex(1);
        }

        List<TaskLayerVO> content = taskLayerService.getTaskLayerList(searchVO, Collections.emptySet());

        Map<String, Object> response = new HashMap<>();
        response.put("content", content);
        if (searchVO.getPageSize() > 1) {
            response.put("page", searchVO.getPageIndex());
            response.put("size", searchVO.getPageSize());
            long total = taskLayerService.getTaskLayerListTotCnt(searchVO, Collections.emptySet());
            response.put("totalElements", total);
            response.put("totalPages", (int) Math.ceil((double) total / searchVO.getPageSize()));
        }

        return ResponseEntity.ok(DefaultApiResponse.success(response));
    }

    /**
     * 업무 레이어 전체 목록.
     */
    @GetMapping("/task/all")
    public ResponseEntity<DefaultApiResponse<List<TaskLayerVO>>> getAllTaskLayers() {
        List<TaskLayerVO> list = taskLayerService.getAll();
        return ResponseEntity.ok(DefaultApiResponse.success(list));
    }

    /**
     * 업무 레이어 상세 조회.
     */
    @GetMapping("/task/{taskLyrId}")
    public ResponseEntity<DefaultApiResponse<TaskLayerVO>> getTaskLayer(@PathVariable Integer taskLyrId) {
        TaskLayerVO layer = taskLayerService.getById(taskLyrId);
        if (layer == null) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(DefaultApiResponse.error(404, "업무 레이어를 찾을 수 없습니다: " + taskLyrId, "Not Found"));
        }
        return ResponseEntity.ok(DefaultApiResponse.success(layer));
    }

    /**
     * 업무 레이어 생성.
     */
    @PostMapping("/task")
    public ResponseEntity<DefaultApiResponse<Void>> createTaskLayer(@Valid @RequestBody TaskLayerVO taskLayer) {
        String userId = getCurrentUserId();
        taskLayer.setCrtId(userId);
        taskLayerService.create(taskLayer);
        return ResponseEntity.ok(DefaultApiResponse.success(null, "업무 레이어가 생성되었습니다."));
    }

    /**
     * 업무 레이어 수정.
     */
    @PutMapping("/task/{taskLyrId}")
    public ResponseEntity<DefaultApiResponse<Void>> updateTaskLayer(@PathVariable Integer taskLyrId, @Valid @RequestBody TaskLayerVO taskLayer) {
        String userId = getCurrentUserId();
        taskLayer.setTaskLyrId(taskLyrId);
        taskLayer.setChgId(userId);
        taskLayerService.update(taskLayer);
        return ResponseEntity.ok(DefaultApiResponse.success(null, "업무 레이어가 수정되었습니다."));
    }

    /**
     * 업무 레이어 삭제.
     */
    @DeleteMapping("/task/{taskLyrId}")
    public ResponseEntity<DefaultApiResponse<Void>> deleteTaskLayer(@PathVariable Integer taskLyrId) {
        taskLayerService.delete(taskLyrId);
        return ResponseEntity.ok(DefaultApiResponse.success(null, "업무 레이어가 삭제되었습니다."));
    }

    /**
     * 레이어 그룹 코드 목록.
     */
    @GetMapping("/group-codes")
    public ResponseEntity<DefaultApiResponse<List<Map<String, Object>>>> getGroupCodes() {
        return ResponseEntity.ok(DefaultApiResponse.success(taskLayerService.getGroupCodes()));
    }

    /**
     * 레이어 물리명 검증.
     */
    @GetMapping("/verify")
    public ResponseEntity<DefaultApiResponse<Map<String, Object>>> verifyPhysicalName(
            @RequestParam String schema,
            @RequestParam String tableNm,
            @RequestParam String lyrSrvcNm,
            @RequestParam String lyrPhysNm) {
        Map<String, Object> result = taskLayerService.verifyGeometryTable(schema, tableNm, lyrSrvcNm, lyrPhysNm);
        return ResponseEntity.ok(DefaultApiResponse.success(result));
    }

    private String getCurrentUserId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() instanceof LoginVO) {
            LoginVO loginVO = (LoginVO) authentication.getPrincipal();
            return loginVO.getUserId();
        }
        throw new BusinessException("인증 정보가 없습니다. 로그인이 필요합니다.", HttpStatus.UNAUTHORIZED);
    }
}
