package com.takensoft.cms.token.web;

import com.takensoft.cms.loginPolicy.service.LoginModeService;
import com.takensoft.cms.loginPolicy.service.LoginPolicyService;
import com.takensoft.cms.mber.vo.MberVO;
import com.takensoft.cms.token.service.RefreshTokenService;
import com.takensoft.cms.token.vo.RefreshTknVO;
import com.takensoft.common.message.MessageCode;
import com.takensoft.common.util.ResponseData;
import com.takensoft.common.util.ResponseUtil;
import com.takensoft.common.util.SessionUtil;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.nio.charset.Charset;

/**
 * @author takensoft
 * @since 2024.04.01
 * @modification
 *     since    |    author    | description
 *  2024.04.01  |  takensoft   | 최초 등록
 *  2025.06.02  |  takensoft   | 세션 모드 Redis 정보 삭제 추가
 *
 * RefreshToken 정보 관련 컨트롤러
 */
@RestController
@RequiredArgsConstructor
@Slf4j
public class RefreshTokenController {

    private final ResponseUtil resUtil;
    private final RefreshTokenService refreshTokenService;
    private final LoginPolicyService loginPolicyService;
    private final LoginModeService loginModeService;
    private final SessionUtil sessionUtil;
    private final RedisTemplate<String, String> redisTemplate;

    /**
     * @param req - HTTP 요청 객체
     * @param res - HTTP 응답 객체
     * @return ResponseEntity - 로그아웃 응답 결과
     *
     * 로그아웃 - 세션/JWT 모드 통합 처리
     */
    @PostMapping(value = "/mbr/logout.json")
    public ResponseEntity<?> logout(HttpServletRequest req, HttpServletResponse res){
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();

        if (auth != null && auth.getPrincipal() instanceof MberVO) {
            MberVO mber = (MberVO) auth.getPrincipal();
            String mbrId = mber.getMbrId();
            String loginMode = loginModeService.getLoginMode(); // J or S

            // Refresh 토큰 삭제 (DB)
            RefreshTknVO refresh = new RefreshTknVO();
            refresh.setMbrId(mbrId);
            int result = refreshTokenService.delete(req, refresh);

            if (loginMode.equals("S")) {
                HttpSession session = req.getSession(false);
                if (session != null) {
                    session.invalidate();
                }

                // SessionUtil에서 제거
                sessionUtil.removeSession(mbrId);

                // Redis에서 세션 정보 삭제 (중복로그인 관리용)
                String sessionKey = "session:" + mbrId;
                try {
                    redisTemplate.delete(sessionKey);
                } catch (Exception e) {
                }

                // JSESSIONID 쿠키 제거
                Cookie cookie = new Cookie("JSESSIONID", null);
                cookie.setMaxAge(0); // 삭제
                cookie.setPath("/");
                res.addCookie(cookie);

            } else {
                // JWT 방식: Redis에서 삭제
                if (!loginPolicyService.getPolicy()) {
                    try {
                        redisTemplate.delete("jwt:" + mbrId);
                    } catch (Exception e) {
                    }
                }

                // refresh 쿠키 제거
                Cookie cookie = new Cookie("refresh", null);
                cookie.setMaxAge(0);
                cookie.setHttpOnly(true);
                cookie.setPath("/");
                res.addCookie(cookie);
            }

            // SecurityContext 제거
            SecurityContextHolder.clearContext();

            return resUtil.successRes(result, MessageCode.LOGOUT_SUCCESS);
        }
        return resUtil.errorRes(MessageCode.COMMON_UNKNOWN_ERROR);
    }

    /**
     * @param req - HTTP 요청 객체
     * @param res - HTTP 응답 객체
     * @return ResponseEntity - 토큰 재발급 응답 결과
     *
     * 토큰 재발급
     */
    @PostMapping("/refresh/tokenReissue.json")
    public ResponseEntity<?> tokenReissue(HttpServletRequest req, HttpServletResponse res) {
        int result = refreshTokenService.tokenReissueProc(req, res);

        // 응답 처리
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));
        ResponseData responseData = new ResponseData();
        if(result > 0) {
            return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
        } else {
            responseData.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            responseData.setStatusText(HttpStatus.INTERNAL_SERVER_ERROR);
            responseData.setMessage("로그인을 다시해주시기 바랍니다.");
            return new ResponseEntity<>(responseData, headers, HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}