package de.frigosped.dc.client;

import jakarta.annotation.Priority;
import jakarta.ws.rs.client.ClientRequestContext;
import jakarta.ws.rs.client.ClientRequestFilter;
import jakarta.ws.rs.client.ClientResponseContext;
import jakarta.ws.rs.client.ClientResponseFilter;
import jakarta.ws.rs.ext.Provider;
import org.jboss.logging.Logger;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

/**
 * Loggt jede HTTP-Anfrage und -Antwort des ORDS REST Clients:
 *   - Vollständige URL (Methode + URI)
 *   - Request-Body
 *   - Response-Status + Body
 */
@Provider
@Priority(jakarta.ws.rs.Priorities.AUTHENTICATION + 1)
public class OrdsLoggingFilter implements ClientRequestFilter, ClientResponseFilter {

    private static final Logger LOG = Logger.getLogger(OrdsLoggingFilter.class);

    @Override
    public void filter(ClientRequestContext ctx) throws IOException {
        String method = ctx.getMethod();
        String uri = ctx.getUri().toString();
        String entity = readRequest(ctx);

        LOG.infof("=== ORDS %s %s ===", method, uri);
        if (entity != null && !entity.isBlank()) {
            LOG.infof("REQUEST: %s", entity);
        }
    }

    @Override
    public void filter(ClientRequestContext requestCtx, ClientResponseContext responseCtx) throws IOException {
        String body = readResponse(responseCtx);
        LOG.infof("RESPONSE: HTTP %d%s",
                responseCtx.getStatus(),
                body != null ? " " + body : "");
        LOG.infof("=== ORDS %s %s END ===", requestCtx.getMethod(), requestCtx.getUri());
    }

    private static final int MAX_BODY_LOG = 500;

    private String readRequest(ClientRequestContext ctx) {
        Object entity = ctx.getEntity();
        if (entity == null) return null;

        String body;
        if (entity instanceof byte[] bytes) {
            body = new String(bytes, StandardCharsets.UTF_8);
        } else if (entity instanceof String str) {
            body = str;
        } else if (entity instanceof List<?> list) {
            body = list.toString();
        } else if (entity instanceof Object[] arr) {
            body = Arrays.toString(arr);
        } else {
            body = entity.toString();
        }
        if (body.isBlank()) return null;
        if (body.length() > MAX_BODY_LOG) {
            return body.substring(0, MAX_BODY_LOG) + String.format(" ... [%d Zeichen gesamt]", body.length());
        }
        return body;
    }

    private String readResponse(ClientResponseContext ctx) throws IOException {
        if (ctx.getEntityStream() == null) return null;

        byte[] raw = ctx.getEntityStream().readAllBytes();
        if (raw.length == 0) return null;

        // Stream neu setzen für nachfolgende Consumer (z.B. Response.readEntity)
        ctx.setEntityStream(new ByteArrayInputStream(raw));

        if (raw.length > 4000) {
            return String.format("[%d bytes, trunc. zu 4000]", raw.length);
        }

        String mediaType = ctx.getMediaType() != null ? ctx.getMediaType().toString() : "";
        if (mediaType.contains("application/json") || mediaType.contains("text/") || mediaType.isEmpty()) {
            return new String(raw, StandardCharsets.UTF_8);
        }
        return String.format("[%d bytes binary]", raw.length);
    }
}
