package com.erp.controller;

import com.erp.dto.ApiResponse;
import com.erp.service.CommonCodeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Common Code Controller — 마스터-디테일 패턴.
 *
 *   /info             : code_info  (1레벨 그룹 마스터)
 *   /detail           : code_detail (2레벨~ 트리)
 *
 * NOTE: Spring MVC 는 리터럴 세그먼트를 경로변수보다 우선하므로
 *       /check-duplicate 는 /{codeInfo} / /{id} 보다 먼저 매칭된다.
 */
@RestController
@RequestMapping("/api/common-codes")
@RequiredArgsConstructor
@Slf4j
public class CommonCodeController {

    private final CommonCodeService service;

    // ════════════════════════════════════════════════════════════════
    // CODE_INFO — 그룹 마스터
    // ════════════════════════════════════════════════════════════════

    /** 그룹 목록 (페이징/검색) */
    @GetMapping("/info")
    public ResponseEntity<Map<String, Object>> getCodeInfoList(
            @RequestAttribute("company_code") String companyCode,
            @RequestParam Map<String, Object> params) {

        params.put("company_code", companyCode);
        Map<String, Object> svc = service.getCodeInfoList(params);

        Map<String, Object> response = new LinkedHashMap<>();
        response.put("success", true);
        response.put("data",    svc.get("data"));
        response.put("total",   svc.get("total"));
        response.put("message", "코드 그룹 목록 조회 성공");
        return ResponseEntity.ok(response);
    }

    /** 그룹 중복 체크 — /{codeInfo} 보다 먼저 선언 */
    @GetMapping("/info/check-duplicate")
    public ResponseEntity<ApiResponse<Map<String, Object>>> checkCodeInfoDuplicate(
            @RequestAttribute("company_code") String companyCode,
            @RequestParam(defaultValue = "code_info") String field,
            @RequestParam String value,
            @RequestParam(required = false) String excludeCode) {

        return ResponseEntity.ok(
                ApiResponse.success(service.checkCodeInfoDuplicate(field, value, excludeCode, companyCode)));
    }

    /** 그룹 단건 */
    @GetMapping("/info/{codeInfo}")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getCodeInfoInfo(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String codeInfo) {

        Map<String, Object> info = service.getCodeInfoInfo(codeInfo, companyCode);
        if (info == null) {
            return ResponseEntity.status(404).body(ApiResponse.error("코드 그룹을 찾을 수 없습니다."));
        }
        return ResponseEntity.ok(ApiResponse.success(info));
    }

    /** 그룹 생성 */
    @PostMapping("/info")
    public ResponseEntity<ApiResponse<Map<String, Object>>> insertCodeInfo(
            @RequestAttribute("company_code") String companyCode,
            @RequestAttribute("user_id") String userId,
            @RequestBody Map<String, Object> body) {

        if (body.get("code_info") == null || body.get("code_name") == null) {
            return ResponseEntity.status(400)
                    .body(ApiResponse.error("필수 필드가 누락되었습니다. (code_info, code_name)"));
        }
        try {
            Map<String, Object> created = service.insertCodeInfo(body, companyCode, userId);
            return ResponseEntity.status(201)
                    .body(ApiResponse.success(created, "코드 그룹이 성공적으로 생성되었습니다."));
        } catch (Exception e) {
            log.error("코드 그룹 생성 실패", e);
            return ResponseEntity.status(500)
                    .body(ApiResponse.error("코드 그룹 생성에 실패했습니다."));
        }
    }

    /** 그룹 수정 */
    @PutMapping("/info/{codeInfo}")
    public ResponseEntity<ApiResponse<Map<String, Object>>> updateCodeInfo(
            @RequestAttribute("company_code") String companyCode,
            @RequestAttribute("user_id") String userId,
            @PathVariable String codeInfo,
            @RequestBody Map<String, Object> body) {

        try {
            Map<String, Object> updated = service.updateCodeInfo(codeInfo, body, companyCode, userId);
            if (updated == null) {
                return ResponseEntity.status(404)
                        .body(ApiResponse.error("코드 그룹을 찾을 수 없습니다."));
            }
            return ResponseEntity.ok(ApiResponse.success(updated, "코드 그룹이 성공적으로 수정되었습니다."));
        } catch (Exception e) {
            log.error("코드 그룹 수정 실패", e);
            return ResponseEntity.status(500)
                    .body(ApiResponse.error("코드 그룹 수정에 실패했습니다."));
        }
    }

    /** 그룹 삭제 (CASCADE 로 code_detail 자식 자동 삭제) */
    @DeleteMapping("/info/{codeInfo}")
    public ResponseEntity<ApiResponse<Void>> deleteCodeInfo(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable String codeInfo) {

        try {
            service.deleteCodeInfo(codeInfo, companyCode);
            return ResponseEntity.ok(ApiResponse.success(null, "코드 그룹이 성공적으로 삭제되었습니다."));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
        } catch (Exception e) {
            log.error("코드 그룹 삭제 실패", e);
            return ResponseEntity.status(500)
                    .body(ApiResponse.error("코드 그룹 삭제에 실패했습니다."));
        }
    }

    // ════════════════════════════════════════════════════════════════
    // CODE_DETAIL — 디테일 트리
    // ════════════════════════════════════════════════════════════════

    /**
     * 디테일 트리.
     *  - code_info 필수 (어느 그룹)
     *  - parent_detail_id (optional): 지정 시 해당 부모의 자식만, 미지정 시 그룹 전체 트리 (재귀 CTE)
     *  - flat=true 인 경우 동일 (트리는 평탄화된 depth+sort_order 순)
     */
    @GetMapping("/detail")
    public ResponseEntity<Map<String, Object>> getCodeDetail(
            @RequestAttribute("company_code") String companyCode,
            @RequestParam("code_info") String codeInfo,
            @RequestParam Map<String, Object> params) {

        params.put("company_code", companyCode);

        Object parentRaw = params.get("parent_detail_id");
        Map<String, Object> response = new LinkedHashMap<>();
        response.put("success", true);

        if (parentRaw != null && !parentRaw.toString().isEmpty()) {
            // 특정 부모 직속 자식만
            Map<String, Object> svc = service.getCodeDetailList(codeInfo, params);
            response.put("data",  svc.get("data"));
            response.put("total", svc.get("total"));
        } else {
            // 그룹 전체 트리 (재귀 CTE 로 평탄화)
            List<Map<String, Object>> tree = service.getCodeDetailTree(codeInfo, companyCode);
            response.put("data",  tree);
            response.put("total", tree.size());
        }
        response.put("message", "코드 디테일 조회 성공");
        return ResponseEntity.ok(response);
    }

    /** 디테일 중복 체크 — /{id} 보다 먼저 선언 */
    @GetMapping("/detail/check-duplicate")
    public ResponseEntity<ApiResponse<Map<String, Object>>> checkCodeDetailDuplicate(
            @RequestAttribute("company_code") String companyCode,
            @RequestParam("code_info") String codeInfo,
            @RequestParam("code_value") String codeValue,
            @RequestParam(value = "exclude_id", required = false) Long excludeId) {

        return ResponseEntity.ok(
                ApiResponse.success(service.checkCodeDetailDuplicate(codeInfo, codeValue, excludeId, companyCode)));
    }

    /** 디테일 단건 */
    @GetMapping("/detail/{id}")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getCodeDetailInfo(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable("id") Long codeDetailId) {

        Map<String, Object> info = service.getCodeDetailInfo(codeDetailId, companyCode);
        if (info == null) {
            return ResponseEntity.status(404).body(ApiResponse.error("코드를 찾을 수 없습니다."));
        }
        return ResponseEntity.ok(ApiResponse.success(info));
    }

    /** 디테일 자식 존재 여부 */
    @GetMapping("/detail/{id}/has-children")
    public ResponseEntity<ApiResponse<Map<String, Object>>> hasCodeDetailChildren(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable("id") Long codeDetailId) {

        return ResponseEntity.ok(
                ApiResponse.success(service.hasCodeDetailChildren(codeDetailId, companyCode)));
    }

    /** 디테일 생성 */
    @PostMapping("/detail")
    public ResponseEntity<ApiResponse<Map<String, Object>>> insertCodeDetail(
            @RequestAttribute("company_code") String companyCode,
            @RequestAttribute("user_id") String userId,
            @RequestBody Map<String, Object> body) {

        Object codeInfoRaw = body.get("code_info");
        if (codeInfoRaw == null || body.get("code_value") == null || body.get("code_name") == null) {
            return ResponseEntity.status(400)
                    .body(ApiResponse.error("필수 필드가 누락되었습니다. (code_info, code_value, code_name)"));
        }
        try {
            Map<String, Object> created = service.insertCodeDetail(codeInfoRaw.toString(), body, companyCode, userId);
            return ResponseEntity.status(201)
                    .body(ApiResponse.success(created, "코드가 성공적으로 생성되었습니다."));
        } catch (Exception e) {
            log.error("코드 생성 실패", e);
            return ResponseEntity.status(500)
                    .body(ApiResponse.error("코드 생성에 실패했습니다."));
        }
    }

    /** 디테일 수정 */
    @PutMapping("/detail/{id}")
    public ResponseEntity<ApiResponse<Map<String, Object>>> updateCodeDetail(
            @RequestAttribute("company_code") String companyCode,
            @RequestAttribute("user_id") String userId,
            @PathVariable("id") Long codeDetailId,
            @RequestBody Map<String, Object> body) {

        try {
            Map<String, Object> updated = service.updateCodeDetail(codeDetailId, body, companyCode, userId);
            if (updated == null) {
                return ResponseEntity.status(404).body(ApiResponse.error("코드를 찾을 수 없습니다."));
            }
            return ResponseEntity.ok(ApiResponse.success(updated, "코드가 성공적으로 수정되었습니다."));
        } catch (Exception e) {
            log.error("코드 수정 실패", e);
            return ResponseEntity.status(500)
                    .body(ApiResponse.error("코드 수정에 실패했습니다."));
        }
    }

    /** 디테일 삭제 (CASCADE 로 자식 자동 삭제) */
    @DeleteMapping("/detail/{id}")
    public ResponseEntity<ApiResponse<Void>> deleteCodeDetail(
            @RequestAttribute("company_code") String companyCode,
            @PathVariable("id") Long codeDetailId) {

        try {
            service.deleteCodeDetail(codeDetailId, companyCode);
            return ResponseEntity.ok(ApiResponse.success(null, "코드가 성공적으로 삭제되었습니다."));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.status(404).body(ApiResponse.error(e.getMessage()));
        } catch (Exception e) {
            log.error("코드 삭제 실패", e);
            return ResponseEntity.status(500)
                    .body(ApiResponse.error("코드 삭제에 실패했습니다."));
        }
    }
}
