package com.kamco.cd.kamcoback.config.api;

import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity;
import com.kamco.cd.kamcoback.postgres.repository.log.AuditLogRepository;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Optional;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import org.springframework.web.util.ContentCachingRequestWrapper;

/**
 * ApiResponseDto의 내장된 HTTP 상태 코드를 실제 HTTP 응답에 적용하는 Advice
 *
 * <p>createOK() → 201 CREATED ok() → 200 OK deleteOk() → 204 NO_CONTENT
 */
@RestControllerAdvice
public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {

  private final AuditLogRepository auditLogRepository;

  public ApiResponseAdvice(AuditLogRepository auditLogRepository) {
    this.auditLogRepository = auditLogRepository;
  }

  @Override
  public boolean supports(
      MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    // ApiResponseDto를 반환하는 경우에만 적용
    return returnType.getParameterType().equals(ApiResponseDto.class);
  }

  @Override
  public Object beforeBodyWrite(
      Object body,
      MethodParameter returnType,
      MediaType selectedContentType,
      Class<? extends HttpMessageConverter<?>> selectedConverterType,
      ServerHttpRequest request,
      ServerHttpResponse response) {

    HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
    ContentCachingRequestWrapper contentWrapper = (ContentCachingRequestWrapper) servletRequest;

    if (body instanceof ApiResponseDto<?> apiResponse) {
      // ApiResponseDto에 설정된 httpStatus를 실제 HTTP 응답에 적용
      response.setStatusCode(apiResponse.getHttpStatus());

      String ip = ApiLogFunction.getClientIp(servletRequest);
      // TODO : userid 가 계정명인지, uid 인지 확인 후 로직 수정 필요함
      Long userid =
          Long.valueOf(Optional.ofNullable(ApiLogFunction.getUserId(servletRequest)).orElse("1"));

      // TODO: menuUid 를 동적으로 가져오게끔 해야함
      AuditLogEntity log =
          new AuditLogEntity(
              userid,
              ApiLogFunction.getEventType(servletRequest),
              ApiLogFunction.isSuccessFail(apiResponse),
              "MU_01_01",
              ip,
              servletRequest.getRequestURI(),
              ApiLogFunction.getRequestBody(servletRequest, contentWrapper),
              apiResponse.getErrorLogUid());

      // tb_audit_log 테이블 저장
      auditLogRepository.save(log);
    }

    return body;
  }
}
