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   | 최초 등록
 *
 * 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 - 로그아웃 응답 결과
     *
     * 로그아웃
     */
    @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 loginType = loginModeService.getLoginMode(); // J or S

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

            if (loginType.equals("S")) {
                // 세션 방식: 세션 만료 + SessionMap에서 제거
                HttpSession session = req.getSession(false);
                if (session != null) session.invalidate();
                sessionUtil.removeSession(mbrId);

                Cookie cookie = new Cookie("JSESSIONID", null);
                cookie.setMaxAge(0); // 삭제
                cookie.setPath("/");
                res.addCookie(cookie);
            } else {
                // JWT 방식: Redis에서 삭제
                if (!loginPolicyService.getPolicy()) {
                    redisTemplate.delete("jwt:" + mbrId);
                }
                // 쿠키 제거
                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);
        }
    }
}
