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

import com.kamco.cd.kamcoback.log.dto.EventStatus;
import com.kamco.cd.kamcoback.log.dto.EventType;
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
import jakarta.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.web.util.ContentCachingRequestWrapper;

public class ApiLogFunction {

  // 클라이언트 IP 추출
  public static String getClientIp(HttpServletRequest request) {
    String[] headers = {
      "X-Forwarded-For",
      "Proxy-Client-IP",
      "WL-Proxy-Client-IP",
      "HTTP_CLIENT_IP",
      "HTTP_X_FORWARDED_FOR"
    };
    for (String header : headers) {
      String ip = request.getHeader(header);
      if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
        return ip.split(",")[0];
      }
    }
    String ip = request.getRemoteAddr();
    if ("0:0:0:0:0:0:0:1".equals(ip)) { // local 일 때
      ip = "127.0.0.1";
    }
    return ip;
  }

  // 사용자 ID 추출 예시 (Spring Security 기준)
  public static String getUserId(HttpServletRequest request) {
    try {
      return request.getUserPrincipal() != null ? request.getUserPrincipal().getName() : null;
    } catch (Exception e) {
      return null;
    }
  }

  public static EventType getEventType(HttpServletRequest request) {
    String method = request.getMethod().toUpperCase();
    String uri = request.getRequestURI().toLowerCase();

    // URL 기반 DOWNLOAD/PRINT 분류
    if (uri.contains("/download") || uri.contains("/export")) {
      return EventType.DOWNLOAD;
    }
    if (uri.contains("/print")) {
      return EventType.PRINT;
    }

    // 일반 CRUD
    return switch (method) {
      case "POST" -> EventType.CREATE;
      case "GET" -> EventType.READ;
      case "DELETE" -> EventType.DELETE;
      case "PUT", "PATCH" -> EventType.UPDATE;
      default -> EventType.OTHER;
    };
  }

  public static String getRequestBody(
      HttpServletRequest servletRequest, ContentCachingRequestWrapper contentWrapper) {
    StringBuilder resultBody = new StringBuilder();
    // GET, form-urlencoded POST 파라미터
    Map<String, String[]> paramMap = servletRequest.getParameterMap();

    String queryParams =
        paramMap.entrySet().stream()
            .map(e -> e.getKey() + "=" + String.join(",", e.getValue()))
            .collect(Collectors.joining("&"));

    resultBody.append(queryParams.isEmpty() ? "" : queryParams);

    // JSON Body
    if ("POST".equalsIgnoreCase(servletRequest.getMethod())
        && servletRequest.getContentType() != null
        && servletRequest.getContentType().contains("application/json")) {
      try {
        // json인 경우는 Wrapper를 통해 가져오기
        resultBody.append(getBodyData(contentWrapper));

      } catch (Exception e) {
        resultBody.append("cannot read JSON body ").append(e.toString());
      }
    }

    // Multipart form-data
    if ("POST".equalsIgnoreCase(servletRequest.getMethod())
        && servletRequest.getContentType() != null
        && servletRequest.getContentType().startsWith("multipart/form-data")) {
      resultBody.append("multipart/form-data request");
    }

    return resultBody.toString();
  }

  // JSON Body 읽기
  public static String getBodyData(ContentCachingRequestWrapper request) {
    byte[] buf = request.getContentAsByteArray();
    if (buf.length == 0) {
      return null;
    }
    try {
      return new String(buf, request.getCharacterEncoding());
    } catch (UnsupportedEncodingException e) {
      return new String(buf);
    }
  }

  // ApiResponse 의 Status가 2xx 범위이면 SUCCESS, 아니면 FAILED
  public static EventStatus isSuccessFail(ApiResponseDto<?> apiResponse) {
    return apiResponse.getHttpStatus().is2xxSuccessful() ? EventStatus.SUCCESS : EventStatus.FAILED;
  }

  public static String getUriMenuInfo(List<MenuDto.Basic> menuList, String uri) {

    MenuDto.Basic m =
        menuList.stream()
            .filter(menu -> menu.getMenuApiUrl() != null && uri.contains(menu.getMenuApiUrl()))
            .findFirst()
            .orElse(null);

    return m != null ? m.getMenuUid() : "SYSTEM";
  }
}
