content: package shop.kkeujeok.kkeujeokbackend.global.oauth;
  
  import com.fasterxml.jackson.core.JsonProcessingException;
  import com.fasterxml.jackson.databind.JsonNode;
  import com.fasterxml.jackson.databind.ObjectMapper;
  import lombok.extern.slf4j.Slf4j;
  import org.springframework.beans.factory.annotation.Value;
  import org.springframework.http.HttpEntity;
  import org.springframework.http.HttpHeaders;
  import org.springframework.http.HttpMethod;
  import org.springframework.http.ResponseEntity;
  import org.springframework.stereotype.Service;
  import org.springframework.transaction.annotation.Transactional;
  import org.springframework.util.LinkedMultiValueMap;
  import org.springframework.util.MultiValueMap;
  import org.springframework.web.client.RestTemplate;
  import shop.kkeujeok.kkeujeokbackend.auth.api.dto.response.IdTokenResDto;
  import shop.kkeujeok.kkeujeokbackend.auth.api.dto.response.UserInfo;
  import shop.kkeujeok.kkeujeokbackend.auth.application.AuthService;
  import shop.kkeujeok.kkeujeokbackend.global.oauth.exception.OAuthException;
  import shop.kkeujeok.kkeujeokbackend.member.domain.SocialType;
  
  import java.nio.charset.StandardCharsets;
  import java.util.Base64;
  
  @Slf4j
  @Service
  @Transactional(readOnly = true)
  public class KakaoAuthService implements AuthService {
  
      private static final String KAKAO_TOKEN_URL = "https://kauth.kakao.com/oauth/token";
      private static final String JWT_DELIMITER = "\\.";
      private final ObjectMapper objectMapper;
      private final RestTemplate restTemplate;
      @Value("${oauth.kakao.rest-api-key}")
      private String restApiKey;
      @Value("${oauth.kakao.redirect-url}")
      private String redirectUri;
  
      public KakaoAuthService(ObjectMapper objectMapper, RestTemplate restTemplate) {
          this.objectMapper = objectMapper;
          this.restTemplate = restTemplate;
      }
  
      @Override
      public IdTokenResDto getIdToken(String code) {
          HttpHeaders headers = new HttpHeaders();
          headers.add("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
  
          MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
          params.add("grant_type", "authorization_code");
          params.add("client_id", restApiKey);
          params.add("redirect_uri", redirectUri);
          params.add("code", code);
  
          HttpEntity<MultiValueMap<String, String>> kakaoTokenRequest = new HttpEntity<>(params, headers);
  
          ResponseEntity<String> response = restTemplate.exchange(
                  KAKAO_TOKEN_URL,
                  HttpMethod.POST,
                  kakaoTokenRequest,
                  String.class
          );
  
          if (response.getStatusCode().is2xxSuccessful()) {
              String responseBody = response.getBody();
              try {
                  JsonNode jsonNode = objectMapper.readTree(responseBody);
                  JsonNode idToken = jsonNode.get("id_token");
  
                  return new IdTokenResDto(idToken);
              } catch (Exception e) {
                  throw new RuntimeException("ID 토큰을 파싱하는데 실패했습니다.", e);
              }
          }
          throw new RuntimeException("구글 엑세스 토큰을 가져오는데 실패했습니다.");
      }
  
      @Override
      public String getProvider() {
          return String.valueOf(SocialType.KAKAO).toLowerCase();
      }
  
      @Transactional
      @Override
      public UserInfo getUserInfo(String idToken) {
          String decodePayload = getDecodePayload(idToken);
  
          try {
              return objectMapper.readValue(decodePayload, UserInfo.class);
          } catch (JsonProcessingException e) {
              throw new OAuthException("id 토큰을 읽을 수 없습니다.");
          }
      }
  
      private String getDecodePayload(String idToken) {
          String payload = getPayload(idToken);
  
          return new String(Base64.getUrlDecoder().decode(payload), StandardCharsets.UTF_8);
      }
  
      private String getPayload(String idToken) {
          return idToken.split(JWT_DELIMITER)[1];
      }
  
  }
  