package incheon.ags.ias.role.web;

import incheon.ags.ias.role.service.RoleService;
import incheon.ags.ias.role.vo.RoleVO;
import incheon.ags.ias.role.web.dto.RoleRequestDTO;
import incheon.com.cmm.context.RequestContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequiredArgsConstructor
@Slf4j
public class RoleApiController {

    private final RoleService roleService;

    @PostMapping("/ags/ias/role/roleRegistAction.do")
    @ResponseBody
    public Map<String, Object> roleRegistAction(
            @ModelAttribute RoleRequestDTO roleRequestDTO,
            HttpServletRequest request) throws Exception {

        Map<String, Object> response = new HashMap<>();

        try {
            log.info("역할 등록 요청: {}", roleRequestDTO.toString());

            // 현재 접속한 사용자 ID 설정
            String loginUserId = RequestContext.getCurrentUserId();


            RoleVO roleVO = roleRequestDTO.toEntity();

            roleVO.setFrstRegId(loginUserId);
            roleVO.setLastMdfcnId(loginUserId);

            // upRoleCd 자동 설정
            if (roleVO.getUpRoleCd() == null || roleVO.getUpRoleCd().trim().isEmpty()) {
                // ROLTYP003 (업무사용자) → 해당 시스템의 업무관리자 코드를 upRoleCd로 설정
                if ("ROLTYP003".equals(roleVO.getRoleTypeCd()) && roleVO.getSysCd() != null) {
                    RoleVO adminRole = roleService.selectRoleBySysAndType(roleVO.getSysCd(), "ROLTYP002");
                    if (adminRole != null) {
                        roleVO.setUpRoleCd(adminRole.getRoleCd());
                        log.info("업무사용자의 상위 역할 자동 설정: {}", adminRole.getRoleCd());
                    } else {
                        log.warn("시스템({})의 업무관리자를 찾을 수 없습니다. 먼저 업무관리자를 등록해주세요.", roleVO.getSysCd());
                        response.put("success", false);
                        response.put("message", "해당 시스템의 업무관리자가 존재하지 않습니다. 먼저 업무관리자를 등록해주세요.");
                        response.put("errorCode", "MISSING_SYSTEM_ADMIN");
                        return response;
                    }
                }
                // ROLTYP002 (업무관리자) → 통합관리자를 upRoleCd로 설정
                else if ("ROLTYP002".equals(roleVO.getRoleTypeCd())) {
                    roleVO.setUpRoleCd("ROLE_SUPER_ADMIN");
                    log.info("업무관리자의 상위 역할 자동 설정: ROLE_SUPER_ADMIN");
                }
            }

            // 복합키 (ROLE_CD, SYS_CD) 중복 체크
            RoleVO checkRole = new RoleVO();
            checkRole.setRoleCd(roleVO.getRoleCd());
            checkRole.setSysCd(roleVO.getSysCd());
            RoleVO existingRole = roleService.selectRoleById(checkRole);

            if (existingRole != null) {
                response.put("success", false);
                response.put("message", "해당 시스템에 이미 존재하는 역할 코드입니다. (ROLE_CD, SYS_CD 복합키)");
                response.put("errorCode", "DUPLICATE_ROLE_CD");
                return response;
            }

            // 시스템별 업무관리자(ROLTYP002) 중복 체크
            if ("ROLTYP002".equals(roleVO.getRoleTypeCd()) && roleVO.getSysCd() != null) {
                RoleVO existingAdminRole = roleService.selectRoleBySysAndType(roleVO.getSysCd(), "ROLTYP002");
                if (existingAdminRole != null) {
                    response.put("success", false);
                    response.put("message", "해당 시스템에 이미 업무관리자가 존재합니다. 시스템당 업무관리자는 1개만 등록 가능합니다.");
                    response.put("errorCode", "DUPLICATE_SYSTEM_ADMIN");
                    response.put("existingRoleCd", existingAdminRole.getRoleCd());
                    response.put("existingRoleNm", existingAdminRole.getRoleNm());
                    return response;
                }
            }

            int result = roleService.insertRole(roleVO);

            if (result > 0) {
                log.info("역할 등록 성공 - 역할코드: {}", roleVO.getRoleCd());
                response.put("success", true);
                response.put("message", "역할이 성공적으로 등록되었습니다.");
                response.put("roleCd", roleVO.getRoleCd());
            } else {
                log.error("역할 등록 실패 - 역할코드: {}", roleVO.getRoleCd());
                response.put("success", false);
                response.put("message", "역할 등록에 실패했습니다.");
                response.put("errorCode", "INSERT_FAILED");
            }

        } catch (Exception e) {
            log.error("역할 등록 중 오류 발생", e);
            response.put("success", false);
            response.put("message", "역할 등록 중 오류가 발생했습니다: " + e.getMessage());
            response.put("errorCode", "INTERNAL_ERROR");
        }

        return response;
    }

    @PutMapping("/ags/ias/role/roleModifyAction.do/{originalRoleCd}/{sysCd}")
    @ResponseBody
    public Map<String, Object> roleModifyAction(
            @PathVariable String originalRoleCd,
            @PathVariable String sysCd,
            @ModelAttribute RoleRequestDTO roleRequestDTO,
            @RequestParam(required = false) String roleCdChanged,
            HttpServletRequest request) throws Exception {

        Map<String, Object> response = new HashMap<>();

        try {
            log.info("역할 수정 요청 - 원본코드: ({}, {}), 신규코드: {}, 변경여부: {}",
                     originalRoleCd, sysCd, roleRequestDTO.getRoleCd(), roleCdChanged);

            // 현재 접속한 사용자 ID 설정
            String loginUserId = RequestContext.getCurrentUserId();

            RoleVO roleVO = roleRequestDTO.toEntity();
            roleVO.setLastMdfcnId(loginUserId);

            if (originalRoleCd == null || originalRoleCd.trim().isEmpty() || sysCd == null) {
                response.put("success", false);
                response.put("message", "수정할 역할 코드가 없습니다. (ROLE_CD, SYS_CD 필수)");
                response.put("errorCode", "MISSING_ROLE_CD");
                return response;
            }

            RoleVO existingRole = new RoleVO();
            existingRole.setRoleCd(originalRoleCd);
            existingRole.setSysCd(sysCd);
            RoleVO foundRole = roleService.selectRoleById(existingRole);

            if (foundRole == null) {
                response.put("success", false);
                response.put("message", "수정할 역할을 찾을 수 없습니다. (ROLE_CD: " + originalRoleCd + ", SYS_CD: " + sysCd + ")");
                response.put("errorCode", "ROLE_NOT_FOUND");
                return response;
            }

            // ROLE_CD 변경 여부 확인
            boolean isRoleCdChanged = "Y".equals(roleCdChanged) &&
                                      !originalRoleCd.equals(roleRequestDTO.getRoleCd());

            if (isRoleCdChanged) {
                // ROLE_CD 변경 - 모든 연관 테이블 일괄 수정
                String newRoleCd = roleRequestDTO.getRoleCd();
                log.warn("⚠️ ROLE_CD 변경 요청 - ({}, {}) → {}", sysCd, originalRoleCd, newRoleCd);

                int cascadeResult = roleService.updateRoleCodeCascadeWithSys(sysCd, originalRoleCd, newRoleCd);

                if (cascadeResult > 0) {
                    log.info("ROLE_CD 일괄 변경 성공 - {} 건 업데이트", cascadeResult);

                    // 변경 후 나머지 필드 업데이트
                    roleVO.setRoleCd(newRoleCd);
                    roleVO.setSysCd(sysCd);
                    roleService.updateRole(roleVO);

                    response.put("success", true);
                    response.put("message", "권한그룹 코드가 변경되었습니다. (연관 테이블 " + cascadeResult + "건 일괄 수정)");
                    response.put("roleCd", newRoleCd);
                    response.put("sysCd", sysCd);
                    response.put("cascadeUpdated", cascadeResult);
                } else {
                    log.error("❌ ROLE_CD 일괄 변경 실패");
                    response.put("success", false);
                    response.put("message", "권한그룹 코드 변경에 실패했습니다.");
                    response.put("errorCode", "CASCADE_UPDATE_FAILED");
                }
            } else {
                // 일반 수정 (복합키 그대로 유지)
                roleVO.setRoleCd(originalRoleCd);
                roleVO.setSysCd(sysCd);
                int result = roleService.updateRole(roleVO);

                if (result > 0) {
                    log.info("역할 수정 성공 - 역할코드: ({}, {})", originalRoleCd, sysCd);
                    response.put("success", true);
                    response.put("message", "역할이 성공적으로 수정되었습니다.");
                    response.put("roleCd", originalRoleCd);
                    response.put("sysCd", sysCd);
                } else {
                    log.error("역할 수정 실패 - 역할코드: ({}, {})", originalRoleCd, sysCd);
                    response.put("success", false);
                    response.put("message", "역할 수정에 실패했습니다.");
                    response.put("errorCode", "UPDATE_FAILED");
                }
            }

        } catch (IllegalArgumentException e) {
            log.error("역할 수정 검증 오류", e);
            response.put("success", false);
            response.put("message", e.getMessage());
            response.put("errorCode", "VALIDATION_ERROR");
        } catch (Exception e) {
            log.error("역할 수정 중 오류 발생", e);
            response.put("success", false);
            response.put("message", "역할 수정 중 오류가 발생했습니다: " + e.getMessage());
            response.put("errorCode", "INTERNAL_ERROR");
        }

        return response;
    }

    @DeleteMapping("/ags/ias/role/roleDeleteAction.do/{roleCd}/{sysCd}")
    @ResponseBody
    public Map<String, Object> roleDeleteAction(
            @PathVariable String roleCd,
            @PathVariable String sysCd) throws Exception {

        Map<String, Object> response = new HashMap<>();

        try {
            log.info("역할 삭제 요청 - 역할코드: ({}, {})", roleCd, sysCd);

            if (roleCd == null || roleCd.trim().isEmpty() || sysCd == null) {
                response.put("success", false);
                response.put("message", "삭제할 역할 코드가 없습니다. (ROLE_CD, SYS_CD 필수)");
                response.put("errorCode", "MISSING_ROLE_CD");
                return response;
            }

            RoleVO checkRole = new RoleVO();
            checkRole.setRoleCd(roleCd);
            checkRole.setSysCd(sysCd);
            RoleVO foundRole = roleService.selectRoleById(checkRole);

            if (foundRole == null) {
                response.put("success", false);
                response.put("message", "삭제할 역할을 찾을 수 없습니다. (ROLE_CD: " + roleCd + ", SYS_CD: " + sysCd + ")");
                response.put("errorCode", "ROLE_NOT_FOUND");
                return response;
            }

            RoleVO deleteRole = new RoleVO();
            deleteRole.setRoleCd(roleCd);
            deleteRole.setSysCd(sysCd);
            int result = roleService.deleteRole(deleteRole);

            if (result > 0) {
                log.info("역할 삭제 성공 - 역할코드: ({}, {})", roleCd, sysCd);
                response.put("success", true);
                response.put("message", "역할이 성공적으로 삭제되었습니다.");
                response.put("deletedRoleCd", roleCd);
                response.put("deletedSysCd", sysCd);
            } else {
                log.error("역할 삭제 실패 - 역할코드: ({}, {})", roleCd, sysCd);
                response.put("success", false);
                response.put("message", "역할 삭제에 실패했습니다.");
                response.put("errorCode", "DELETE_FAILED");
            }

        } catch (Exception e) {
            log.error("역할 삭제 중 오류 발생", e);
            response.put("success", false);
            response.put("message", "역할 삭제 중 오류가 발생했습니다: " + e.getMessage());
            response.put("errorCode", "INTERNAL_ERROR");
        }

        return response;
    }

    /**
     * 규칙명(IP접근제어) 조회
     */
    @GetMapping("/ags/ias/role/selectRulNm.do")
    @ResponseBody
    public Map<String, Object> selectRulNm(
            @RequestParam("roleCd") String roleCd,
            @RequestParam("sysCd") String sysCd) {

        Map<String, Object> response = new HashMap<>();

        try {
            log.info("규칙명 조회 요청 - 역할코드: ({}, {})", roleCd, sysCd);

            RoleVO roleVO = new RoleVO();
            roleVO.setRoleCd(roleCd);
            roleVO.setSysCd(sysCd);

            String rulNm = roleService.selectRulNm(roleVO);

            response.put("success", true);
            response.put("rulNm", rulNm != null ? rulNm : "");
            response.put("message", "규칙명 조회 성공");

        } catch (Exception e) {
            log.error("규칙명 조회 중 오류 발생", e);
            response.put("success", false);
            response.put("message", "규칙명 조회 중 오류가 발생했습니다: " + e.getMessage());
            response.put("errorCode", "INTERNAL_ERROR");
        }

        return response;
    }

    /**
     * 규칙명(IP접근제어) 수정
     */
    @PutMapping("/ags/ias/role/updateRulNm.do")
    @ResponseBody
    public Map<String, Object> updateRulNm(@RequestBody Map<String, String> params) {

        Map<String, Object> response = new HashMap<>();

        try {
            String roleCd = params.get("roleCd");
            String sysCd = params.get("sysCd");
            String rulNm = params.get("rulNm");

            log.info("규칙명 수정 요청 - 역할코드: ({}, {}), 규칙명: {}", roleCd, sysCd, rulNm);

            RoleVO roleVO = new RoleVO();
            roleVO.setRoleCd(roleCd);
            roleVO.setSysCd(sysCd);
            roleVO.setRulNm(rulNm);

            int result = roleService.updateRulNm(roleVO);

            if (result > 0) {
                response.put("success", true);
                response.put("message", "규칙명이 저장되었습니다.");
            } else {
                response.put("success", false);
                response.put("message", "규칙명 저장에 실패했습니다.");
                response.put("errorCode", "UPDATE_FAILED");
            }

        } catch (Exception e) {
            log.error("규칙명 수정 중 오류 발생", e);
            response.put("success", false);
            response.put("message", "규칙명 수정 중 오류가 발생했습니다: " + e.getMessage());
            response.put("errorCode", "INTERNAL_ERROR");
        }

        return response;
    }
}