package com.arms.api.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;

@Slf4j
@Component
@RequiredArgsConstructor
public class RequestBodyExtractor {

    private final ObjectMapper objectMapper;

    /**
     * HTTP Request Body 추출 (Content-Type에 따라 JSON으로 변환)
     *
     * - application/x-www-form-urlencoded: URL 디코딩 후 JSON으로 변환
     * - application/json: 그대로 반환
     */
    public Mono<String> extract(ServerHttpRequest request) {
        MediaType contentType = request.getHeaders().getContentType();

        return request.getBody()
                .map(dataBuffer -> {
                    byte[] bytes = new byte[dataBuffer.readableByteCount()];
                    dataBuffer.read(bytes);
                    return new String(bytes, StandardCharsets.UTF_8);
                })
                .reduce(String::concat)
                .defaultIfEmpty("")
                .flatMap(body -> {
                    // Content-Type이 form-urlencoded인 경우 JSON으로 변환
                    if (contentType != null &&
                            MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)) {
                        log.debug("📝 Converting form-urlencoded to JSON");
                        return convertFormDataToJson(body);
                    }
                    // 이미 JSON이면 그대로 반환
                    return Mono.just(body);
                });
    }

    /**
     * URL-encoded form data를 JSON으로 변환
     *
     * 변환 예시:
     * Input:  ref=2&c_title=%5BARMS-REQ%5D+test&c_type=default
     * Output: {"ref":"2","c_title":"[ARMS-REQ] test","c_type":"default"}
     *
     * @param formData URL-encoded form data 문자열
     * @return JSON 문자열
     */
    private Mono<String> convertFormDataToJson(String formData) {
        return Mono.fromCallable(() -> {
            if (formData == null || formData.isEmpty()) {
                return "{}";
            }

            Map<String, Object> jsonMap = new LinkedHashMap<>();
            String[] pairs = formData.split("&");

            for (String pair : pairs) {
                int idx = pair.indexOf("=");
                if (idx > 0) {
                    String key = URLDecoder.decode(pair.substring(0, idx), StandardCharsets.UTF_8);
                    String value = idx < pair.length() - 1
                            ? URLDecoder.decode(pair.substring(idx + 1), StandardCharsets.UTF_8)
                            : "";
                    jsonMap.put(key, value);
                }
            }

            String json = objectMapper.writeValueAsString(jsonMap);
            log.debug("📝 Converted form data to JSON: {}", json);
            return json;
        }).onErrorResume(e -> {
            log.error("❌ Failed to convert form data to JSON: {}", e.getMessage(), e);
            return Mono.just("{}");
        });
    }
}
