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

import egovframework.constant.MessageConstants;
import egovframework.constant.TilesConstants;
import egovframework.util.ApiResponseUtil;
import egovframework.util.EgovFileScrty;
import egovframework.util.SessionUtil;
import go.kr.project.system.group.model.GroupSearchVO;
import go.kr.project.system.group.model.GroupVO;
import go.kr.project.system.user.model.SystemUserSearchVO;
import go.kr.project.system.user.model.SystemUserVO;
import go.kr.project.system.user.service.UserService;
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.core.env.Environment;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/**
 * packageName    : go.kr.project.system.user.controller
 * fileName       : UserController
 * author         : 박성영
 * date           : 25. 5. 7.
 * description    : 사용자 관리 컨트롤러
 * ===========================================================
 * DATE              AUTHOR             NOTE
 * -----------------------------------------------------------
 * 25. 5. 7.        박성영       최초 생성
 */
@RequestMapping("/system/user")
@Controller
@RequiredArgsConstructor
@Slf4j
@Tag(name = "시스템: 사용자 관리", description = "사용자 관리 관련 API")
public class UserController {

    private final UserService userService;

    @Resource
    private Environment env;

    /**
     * 페이징 처리된 사용자 목록 페이지를 조회합니다.
     * 
     * @param paramVO 검색 조건 및 페이징 정보를 담은 VO 객체
     * @param model 뷰에 전달할 데이터를 담는 모델 객체
     * @return 사용자 목록 페이지 뷰 이름
     * @throws Exception 조회 중 발생할 수 있는 예외
     */
    @Operation(summary = "사용자 목록 페이지 조회", description = "사용자 목록 페이지를 조회합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "사용자 목록 페이지 조회 성공")
    })
    @GetMapping("/list.do")
    public String userList(SystemUserVO paramVO, Model model) {

        return "system/user/list"+ TilesConstants.BASE;
    }

    /**
     * 사용자 목록을 조회하는 AJAX 메소드
     * 공통 응답 형식(ApiResponse)을 사용하여 응답합니다.
     * 
     * @param paramVO 검색 조건을 담은 VO 객체
     * @return 사용자 목록과 성공 상태를 담은 ResponseEntity 객체
     * @throws Exception 조회 중 발생할 수 있는 예외
     */
    @Operation(summary = "사용자 목록 조회 (AJAX)", description = "사용자 목록을 조회하고 JSON 형식으로 반환합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "사용자 목록 조회 성공"),
        @ApiResponse(responseCode = "400", description = "사용자 목록 조회 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @PostMapping("/list.ajax")
    public ResponseEntity<?> getUserListAjax(@ModelAttribute SystemUserSearchVO paramVO) {

        // 총 사용자 수 조회
        int totalCount = userService.selectUserListTotalCount(paramVO);
        paramVO.setTotalCount(totalCount);

        // 페이징 처리를 위한 설정
        paramVO.setPagingYn("Y");

        // 페이징 처리된 사용자 목록 조회
        List<SystemUserVO> userList = userService.selectUserList(paramVO);
        return ApiResponseUtil.successWithGrid(userList, paramVO);
    }

    /**
     * 사용자 계정 중복 확인
     *
     * @param userAcnt 등록할 사용자 계정
     * @return 중복 결과와 성공 상태를 담은 ResponseEntity 객체
     * @throws Exception 등록 중 발생할 수 있는 예외
     */
    @Operation(summary = "사용자 계정 중복 확인", description = "사용자 계정 중복 확인합니다.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "사용자 계정 중복 확인 성공"),
            @ApiResponse(responseCode = "400", description = "사용자 계정 중복 확인 실패"),
            @ApiResponse(description = "오류로 인한 실패")
    })
    @PostMapping("/duplicateCheck.ajax")
    public ResponseEntity<?> duplicateCheckAjax(@RequestParam String userAcnt){
        int result = userService.selectUserAcntDuplicateCheck(userAcnt);
        return ApiResponseUtil.success(result);
    }

    /**
     * 사용자 등록 페이지를 조회합니다.
     * 
     * @param model 뷰에 전달할 데이터를 담는 모델 객체
     * @return 사용자 등록 페이지 뷰 이름
     * @throws Exception 조회 중 발생할 수 있는 예외
     */
    @Operation(summary = "사용자 등록 페이지 조회", description = "사용자 등록 페이지를 조회합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "사용자 등록 페이지 조회 성공")
    })
    @GetMapping("/register.do")
    public String registerUser(Model model) {

        model.addAttribute("user", new SystemUserVO());
        return "system/user/form"+ TilesConstants.BASE;
    }

    /**
     * 사용자 정보를 등록합니다.
     * 
     * @param userVO 등록할 사용자 정보를 담은 VO 객체
     * @return 등록 결과와 성공 상태를 담은 ResponseEntity 객체
     * @throws Exception 등록 중 발생할 수 있는 예외
     */
    @Operation(summary = "사용자 등록", description = "새로운 사용자 정보를 등록합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "사용자 등록 성공"),
        @ApiResponse(responseCode = "400", description = "사용자 등록 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @PostMapping("/register.ajax")
    public ResponseEntity<?> registerUserAjax(@ModelAttribute SystemUserVO userVO) throws Exception {
        userVO.setRgtr(SessionUtil.getUserId());
        userVO.setMdfr(SessionUtil.getUserId());

        // 사용자 ID 자동 생성
        String userId = userService.generateUserId();
        userVO.setUserId(userId);

        // 기본 비밀번호 설정
        String defaultPassword = env.getProperty("login.DefaultPassword", "vipspassword");
        userVO.setPasswd(EgovFileScrty.encryptPassword(defaultPassword, userId));

        // 비밀번호 초기화 여부 설정
        userVO.setPasswdInitYn("Y");

        // 기본값 설정
        if (userVO.getLockYn() == null) userVO.setLockYn("N");
        if (userVO.getLockCnt() == null) userVO.setLockCnt(0);
        if (userVO.getUserStatusCd() == null) userVO.setUserStatusCd("ACTIVE"); // 활성 상태
        if (userVO.getUseYn() == null) userVO.setUseYn("Y");

        int result = userService.insertUser(userVO);

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

    /**
     * 사용자 수정 페이지를 조회합니다.
     * 
     * @param selectUserId 수정할 사용자의 ID
     * @param model 뷰에 전달할 데이터를 담는 모델 객체
     * @return 사용자 수정 페이지 뷰 이름
     * @throws Exception 조회 중 발생할 수 있는 예외
     */
    @Operation(summary = "사용자 수정 페이지 조회", description = "특정 사용자의 수정 페이지를 조회합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "사용자 수정 페이지 조회 성공")
    })
    @GetMapping("/edit.do")
    public String editUser(@RequestParam String selectUserId, Model model) {
        SystemUserVO user = userService.selectUser(selectUserId);
        model.addAttribute("user", user);
        return "system/user/form"+ TilesConstants.BASE;
    }

    /**
     * 사용자 정보를 수정합니다.
     * 
     * @param userVO 수정할 사용자 정보를 담은 VO 객체
     * @return 수정 결과와 성공 상태를 담은 ResponseEntity 객체
     */
    @Operation(summary = "사용자 정보 수정", description = "사용자 정보를 수정합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "사용자 정보 수정 성공"),
        @ApiResponse(responseCode = "400", description = "사용자 정보 수정 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @PostMapping("/edit.ajax")
    public ResponseEntity<?> editUserAjax(@ModelAttribute SystemUserVO userVO) {
        userVO.setMdfr(SessionUtil.getUserId());

        int result = userService.updateUser(userVO);

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

    /**
     * 사용자 비밀번호를 초기화합니다.
     * 
     * @param userId 비밀번호를 초기화할 사용자의 ID
     * @return 초기화 결과와 성공 상태를 담은 ResponseEntity 객체
     * @throws Exception 초기화 중 발생할 수 있는 예외
     */
    @Operation(summary = "비밀번호 초기화", description = "사용자의 비밀번호를 기본값으로 초기화합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "비밀번호 초기화 성공"),
        @ApiResponse(responseCode = "400", description = "비밀번호 초기화 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @PostMapping("/resetPassword.ajax")
    public ResponseEntity<?> resetPasswordAjax(@RequestParam String userId) throws Exception {
        // 사용자 정보 조회
        SystemUserVO userVO = userService.selectUser(userId);

        if (userVO == null) {
            return ApiResponseUtil.error(MessageConstants.User.NOT_FOUND);
        }

        // 비밀번호를 SHA-256으로 암호화된 기본 비밀번호로 설정
        userVO.setPasswd(EgovFileScrty.encryptPassword(env.getProperty("login.DefaultPassword", "vipspassword"), userVO.getUserId()));
        userVO.setPasswdInitYn("Y"); // 비밀번호 초기화 여부 설정
        userVO.setMdfr(SessionUtil.getUserId());

        int result = userService.updatePassword(userVO);

        if (result > 0) {
            return ApiResponseUtil.success(MessageConstants.User.PASSWORD_RESET_SUCCESS);
        } else {
            return ApiResponseUtil.error(MessageConstants.User.PASSWORD_RESET_ERROR);
        }
    }

    /**
     * 사용자 잠금을 해제합니다.
     * 
     * @param userId 잠금을 해제할 사용자의 ID
     * @return 잠금 해제 결과와 성공 상태를 담은 ResponseEntity 객체
     */
    @Operation(summary = "사용자 잠금 해제", description = "사용자의 잠금 상태를 해제하고 잠금 카운트를 0으로 초기화합니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "잠금 해제 성공"),
        @ApiResponse(responseCode = "400", description = "잠금 해제 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @PostMapping("/unlock.ajax")
    public ResponseEntity<?> unlockUserAjax(@RequestParam String userId) {
        // 사용자 정보 조회
        SystemUserVO userVO = userService.selectUser(userId);

        if (userVO == null) {
            return ApiResponseUtil.error(MessageConstants.User.NOT_FOUND);
        }

        int result = userService.unlockUser(userId);

        if (result > 0) {
            return ApiResponseUtil.success(MessageConstants.User.UNLOCK_SUCCESS);
        } else {
            return ApiResponseUtil.error(MessageConstants.User.UNLOCK_ERROR);
        }
    }

    /**
     * 그룹 목록을 조회하는 AJAX 메소드
     * 로그인한 유저의 그룹이 SYSTEM이 아닐경우 GROUP_SYSTEM을 제외하고 조회
     * 
     * @return 그룹 목록과 성공 상태를 담은 ResponseEntity 객체
     * @throws Exception 조회 중 발생할 수 있는 예외
     */
    @Operation(summary = "그룹 목록 조회", description = "사용 중인 그룹 목록을 조회합니다. SYSTEM 그룹이 아닌 사용자는 GROUP_SYSTEM을 제외하고 조회됩니다.")
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "그룹 목록 조회 성공"),
        @ApiResponse(responseCode = "400", description = "그룹 목록 조회 실패"),
        @ApiResponse(description = "오류로 인한 실패")
    })
    @GetMapping("/getGroupList.ajax")
    public ResponseEntity<?> getGroupListAjax() throws Exception {
        GroupSearchVO paramVO = new GroupSearchVO();
        paramVO.setSearchUseYn("Y"); // 사용 중인 그룹만 조회
        
        // 로그인한 사용자의 그룹 확인
        GroupVO userGroup = SessionUtil.getUserGroup();
        
        // 로그인한 유저의 그룹이 SYSTEM이 아닐경우 GROUP_SYSTEM을 제외하고 조회
        if (userGroup != null && !"GROUP_SYSTEM".equals(userGroup.getGroupId())) {
            paramVO.setExcludeGroupId("GROUP_SYSTEM");
        }
        
        List<GroupVO> groupList = userService.selectGroupList(paramVO);
        return ApiResponseUtil.success(groupList);
    }

}
