package go.kr.project.system.menu.controller;

import egovframework.constant.MessageConstants;
import egovframework.constant.TilesConstants;
import egovframework.util.ApiResponseUtil;
import egovframework.util.SessionUtil;
import go.kr.project.system.menu.model.MenuSearchVO;
import go.kr.project.system.menu.model.MenuVO;
import go.kr.project.system.menu.service.MenuService;
import io.swagger.v3.oas.annotations.Operation;
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 lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * packageName    : go.kr.project.system.menu.controller
 * fileName       : MenuController
 * author         : 개발자
 * date           : 2023-06-01
 * description    : 메뉴 관련 요청을 처리하는 컨트롤러
 * ===========================================================
 * DATE              AUTHOR             NOTE
 * -----------------------------------------------------------
 * 2023-06-01        개발자       최초 생성
 */
@RequestMapping("/system/menu")
@Controller
@RequiredArgsConstructor
@Slf4j
@Tag(name = "시스템: 메뉴 관리", description = "메뉴 관리 관련 API")
public class MenuController {

    private final MenuService menuService;

    /**
     * ROOT 메뉴 ID인지 확인합니다.
     * 
     * @param menuId 확인할 메뉴 ID
     * @return ROOT 메뉴 ID인 경우 true, 그렇지 않은 경우 false
     */
    private boolean isRootMenu(String menuId) {
        return "ROOT".equals(menuId);
    }

    /**
     * 메뉴 목록 페이지를 조회합니다.
     * 
     * @return 메뉴 목록 페이지 뷰 이름
     * @throws Exception 조회 중 발생할 수 있는 예외
     */
    @Operation(summary = "메뉴 목록 페이지 조회", description = "메뉴 목록 페이지를 조회합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "메뉴 목록 페이지 조회 성공")
    })
    @GetMapping("/list.do")
    public String menuList() {
        return "system/menu/list"+ TilesConstants.BASE;
    }

    /**
     * 메뉴 정보를 등록합니다.
     * 
     * @param menuVO 등록할 메뉴 정보를 담은 VO 객체
     * @return 등록 결과와 성공 상태를 담은 ResponseEntity 객체
     */
    @Operation(summary = "메뉴 정보 등록", description = "새로운 메뉴 정보를 등록합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "메뉴 등록 성공"),
        @ApiResponse(responseCode = "400", description = "메뉴 등록 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @PostMapping("/register.ajax")
    public ResponseEntity<?> registerMenuAjax(@ModelAttribute MenuVO menuVO) {
        // ROOT 메뉴 ID로 새 메뉴 등록 방지
        if (isRootMenu(menuVO.getMenuId())) {
            return ApiResponseUtil.error(MessageConstants.Menu.ROOT_REGISTER_ERROR);
        }

        menuVO.setRgtr(SessionUtil.getUserId());
        menuVO.setMdfr(SessionUtil.getUserId());

        // 상위 메뉴 ID 검증
        if (menuVO.getUpperMenuId() == null || menuVO.getUpperMenuId().isEmpty()) {
            return ApiResponseUtil.error(MessageConstants.Menu.UPPER_MENU_REQUIRED);
        }

        int result = menuService.insertMenu(menuVO);

        if (result > 0) {
            return ApiResponseUtil.success(MessageConstants.Menu.REGISTER_SUCCESS);
        } else {
            return ApiResponseUtil.error(MessageConstants.Menu.REGISTER_ERROR);
        }
    }

    /**
     * 메뉴 정보를 수정합니다.
     * 
     * @param menuVO 수정할 메뉴 정보를 담은 VO 객체
     * @return 수정 결과와 성공 상태를 담은 ResponseEntity 객체
     * @throws Exception 수정 중 발생할 수 있는 예외
     */
    @Operation(summary = "메뉴 정보 수정", description = "기존 메뉴 정보를 수정합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "메뉴 수정 성공"),
        @ApiResponse(responseCode = "400", description = "메뉴 수정 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @PostMapping("/edit.ajax")
    public ResponseEntity<?> editMenuAjax(@ModelAttribute MenuVO menuVO) {
        // ROOT 메뉴는 수정할 수 없음
        if (isRootMenu(menuVO.getMenuId())) {
            return ApiResponseUtil.error(MessageConstants.Menu.ROOT_EDIT_ERROR);
        }

        menuVO.setMdfr(SessionUtil.getUserId());

        int result = menuService.updateMenu(menuVO);

        if (result > 0) {
            return ApiResponseUtil.success(MessageConstants.Menu.EDIT_SUCCESS);
        } else {
            return ApiResponseUtil.error(MessageConstants.Menu.EDIT_ERROR);
        }
    }

    /**
     * 메뉴 정보를 삭제합니다.
     * 
     * @param menuId 삭제할 메뉴 ID
     * @return 삭제 결과와 성공 상태를 담은 ResponseEntity 객체
     * @throws Exception 삭제 중 발생할 수 있는 예외
     */
    @Operation(summary = "메뉴 정보 삭제", description = "메뉴 정보를 삭제합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "메뉴 삭제 성공"),
        @ApiResponse(responseCode = "400", description = "메뉴 삭제 실패")
    })
    @PostMapping("/delete.ajax")
    public ResponseEntity<?> deleteMenuAjax(@RequestParam String menuId) {
        // ROOT 메뉴는 삭제할 수 없음
        if (isRootMenu(menuId)) {
            return ApiResponseUtil.error(MessageConstants.Menu.ROOT_DELETE_ERROR);
        }

        // 하위 메뉴 존재 여부 확인
        int childCount = menuService.countChildMenus(menuId);

        if (childCount > 0) {
            return ApiResponseUtil.error(MessageConstants.Menu.CHILD_EXISTS_ERROR);
        }

        int result = menuService.deleteMenu(menuId);

        if (result > 0) {
            return ApiResponseUtil.success(MessageConstants.Menu.DELETE_SUCCESS);
        } else {
            return ApiResponseUtil.error(MessageConstants.Menu.DELETE_ERROR);
        }
    }

    /**
     * 메뉴 목록을 트리 구조로 조회하는 AJAX 메소드
     * 
     * @param paramVO 검색 조건을 담은 VO 객체
     * @return 트리 구조의 메뉴 목록과 성공 상태를 담은 ResponseEntity 객체
     */
    @Operation(summary = "메뉴 트리 목록 조회", description = "메뉴 목록을 트리 구조로 조회합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "메뉴 트리 조회 성공"),
        @ApiResponse(responseCode = "400", description = "메뉴 트리 조회 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @PostMapping("/tree.ajax")
    public ResponseEntity<?> getMenuTreeAjax(@ModelAttribute MenuSearchVO paramVO) {
        List<MenuVO> menuTreeList = menuService.selectMenuTreeList(paramVO);
        return ApiResponseUtil.success(menuTreeList);
    }
}
