package com.takensoft.cms.loginPolicy.web;

import com.takensoft.cms.loginPolicy.service.Email2ndAuthService;
import com.takensoft.cms.loginPolicy.service.LoginModeService;
import com.takensoft.cms.loginPolicy.service.LoginPolicyService;
import com.takensoft.cms.loginPolicy.service.StorageModeService;
import com.takensoft.cms.loginPolicy.vo.Email2ndAuthVO;
import com.takensoft.cms.loginPolicy.vo.LoginModeVO;
import com.takensoft.cms.loginPolicy.vo.LoginPolicyVO;
import com.takensoft.cms.loginPolicy.vo.StorageModeVO;
import com.takensoft.cms.mber.vo.MberVO;
import com.takensoft.cms.token.service.RefreshTokenService;
import com.takensoft.common.message.MessageCode;
import com.takensoft.common.util.JWTUtil;
import com.takensoft.common.util.ResponseUtil;
import com.takensoft.common.util.SessionUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import java.util.Set;


/**
 * @author 김혜민
 * @since 2025.03.22
 * @modification
 *     since    |    author    | description
 *  2025.03.22  |    김혜민     | 최초 등록
 *  2025.05.27  |    하석형     | findByEmail2ndAuth, saveEmail2ndAuth 추가
 *  2025.05.30  |    하석형     | findByStorageMode, saveStorageMode 추가
 *
 * 로그인정책 관련 컨트롤러
 */
@RestController
@RequiredArgsConstructor
@Slf4j
@RequestMapping(value = {"/sys/loginPolicy", "/admin/loginPolicy"})
public class LoginPolicyController {

    private final LoginPolicyService loginPolicyService;
    private final LoginModeService loginModeService;
    private final ResponseUtil resUtil;
    private final JWTUtil jwtUtil;
    private final SessionUtil sessionUtil;
    private final RedisTemplate<String, String> redisTemplate;
    private final RefreshTokenService refreshTokenService;
    private final Email2ndAuthService email2ndAuth;
    private final StorageModeService storageMode;

    /**
     *
     * @return ResponseEntity - 중복로그인 조회 결과를 포함하는 응답
     *
     * 중복로그인 조회
     */
    @PostMapping(value ="/getLoginPolicy.json")
    public ResponseEntity<?> getLoginPolicy() {
        Boolean result = loginPolicyService.getPolicy();
        return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
    }

    /**
     * @param loginPolicyVO - 중복로그인 정보
     * @return ResponseEntity - 중복로그인 결과를 포함하는 응답
     *
     * 중복로그인 수정
     */
    @PostMapping(value ="/saveLoginPolicy.json")
    public ResponseEntity<?> saveLoginPolicy(@RequestBody LoginPolicyVO loginPolicyVO, HttpServletRequest request) {
        try {
            String token = request.getHeader("Authorization");

            String loginMode = loginModeService.getLoginMode();
            String mbrId = null;

            if ("J".equals(loginMode)) {
                if (token == null || token.isBlank()) {
                    return resUtil.errorRes(MessageCode.COMMON_BAD_REQUEST); // JWT인데 토큰 없음
                }
                mbrId = (String) jwtUtil.getClaim(token, "mbrId");
            } else {

                Authentication auth = SecurityContextHolder.getContext().getAuthentication();
                if (auth != null && auth.getPrincipal() instanceof MberVO) {
                    mbrId = ((MberVO) auth.getPrincipal()).getMbrId();
                }
            }

            if (mbrId == null || mbrId.isBlank()) {
                return resUtil.errorRes(MessageCode.COMMON_BAD_REQUEST);
            }

            loginPolicyVO.setRgtr(mbrId);

            int result = loginPolicyService.insertPolicy(loginPolicyVO);
            if (result > 0) {
                return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
            } else {
                return resUtil.errorRes(MessageCode.COMMON_INSERT_FAIL);
            }

        } catch (DuplicateKeyException e) {
            return resUtil.errorRes(MessageCode.COMMON_DUPLICATION_DATA); // 중복 저장
        } catch (Exception e) {
            return resUtil.errorRes(MessageCode.COMMON_UNKNOWN_ERROR); // 기타 예외
        }
    }

    /**
     *
     * @return ResponseEntity - 로그인 방식 조회 결과를 포함하는 응답
     *
     * 로그인 방식 조회
     */
    @PostMapping(value ="/getLoginMode.json")
    public Object getLoginMode() {
           String loginMode = loginModeService.getLoginMode();
        return resUtil.successRes(loginMode, MessageCode.COMMON_SUCCESS);
    }

    /**
     *
     * @return ResponseEntity - 로그인 방식 저장 결과를 포함하는 응답
     *
     * 로그인 방식 저장
     */
    @PostMapping(value ="/saveLoginMode.json")
    public ResponseEntity<?> saveLoginMode(@RequestBody LoginModeVO loginModeVO, HttpServletRequest request) {
        try {
            String token = request.getHeader("Authorization");
            String mbrId = (String) jwtUtil.getClaim(token, "mbrId");

            if (mbrId == null || mbrId.isBlank()) {
                return resUtil.errorRes(MessageCode.COMMON_BAD_REQUEST);
            }
            loginModeVO.setRgtr(mbrId);

            int result = loginModeService.insertLoginMode(loginModeVO);

            if (loginModeVO.getLgnMth().equals("J")) {
                // JWT 전체 로그아웃
                Set<String> keys = redisTemplate.keys("jwt:*");
                if (keys != null && !keys.isEmpty()) redisTemplate.delete(keys);
                refreshTokenService.deleteAll();
            } else {
                // 세션 전체 로그아웃
                sessionUtil.invalidateAllSessions();
            }

            if (result > 0) {
                return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
            } else {
                return resUtil.errorRes(MessageCode.COMMON_INSERT_FAIL); // 저장 실패
            }

        } catch (DuplicateKeyException e) {
            return resUtil.errorRes(MessageCode.COMMON_DUPLICATION_DATA); // 중복 저장
        } catch (Exception e) {
            return resUtil.errorRes(MessageCode.COMMON_UNKNOWN_ERROR); // 기타 예외
        }
    }

    /**
     * @return ResponseEntity - 이메일 2차 인증 조회 결과를 포함하는 응답
     *
     * 이메일 2차 인증 조회
     */
    @PostMapping("/findByEmail2ndAuth.json")
    public ResponseEntity<?> findByEmail2ndAuth() {
        boolean result = email2ndAuth.findByEmail2ndAuth();

        return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
    }

    /**
     * @param email2ndAuthVO - 이메일 2차 인증 정보
     * @return ResponseEntity - 이메일 2차 인증 등록 결과를 포함하는 응답
     *
     * 이메일 2차 인증 등록
     */
    @PostMapping("/saveEmail2ndAuth.json")
    public ResponseEntity<?> saveEmail2ndAuth(@RequestBody Email2ndAuthVO email2ndAuthVO) {
        int result = email2ndAuth.email2ndAuthSave(email2ndAuthVO);

        return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
    }

    /**
     * @return ResponseEntity - 스토리지 방식 조회 결과를 포함하는 응답
     *
     * 스토리지 방식 조회
     */
    @PostMapping("/findByStorageMode.json")
    public ResponseEntity<?> findByStorageMode() {
        String result = storageMode.findByStorageMode();

        return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
    }

    /**
     * @param storageModeVO - 스토리지 방식 정보
     * @return ResponseEntity - 스토리지 방식 등록 결과를 포함하는 응답
     *
     * 스토리지 방식 등록
     */
    @PostMapping("/saveStorageMode.json")
    public ResponseEntity<?> saveStorageMode(@RequestBody StorageModeVO storageModeVO) {
        int result = storageMode.storageModeSave(storageModeVO);

        return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
    }

}
