package org.jboss.resteasy.reactive.server.jaxrs;

import java.net.URI;
import java.net.URISyntaxException;

import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.Response;

import org.jboss.resteasy.reactive.common.jaxrs.AbstractResponseBuilder;
import org.jboss.resteasy.reactive.server.core.CurrentRequestManager;
import org.jboss.resteasy.reactive.server.core.Deployment;
import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext;
import org.jboss.resteasy.reactive.server.spi.ServerHttpRequest;

public class ResponseBuilderImpl extends AbstractResponseBuilder {

    @Override
    public Response.ResponseBuilder location(URI location) {
        if (location == null) {
            metadata.remove(HttpHeaders.LOCATION);
            return this;
        }
        if (!location.isAbsolute()) {
            // FIXME: this leaks server stuff onto the client
            ResteasyReactiveRequestContext request = CurrentRequestManager.get();
            if (request != null) {
                ServerHttpRequest req = request.serverRequest();
                try {
                    String host = req.getRequestHost();
                    int port = -1;
                    int index = host.indexOf(":");
                    if (index > -1) {
                        port = Integer.parseInt(host.substring(index + 1));
                        host = host.substring(0, index);
                    }
                    String prefix = "";
                    Deployment deployment = request.getDeployment();
                    if (deployment != null) {
                        // prefix is already sanitised
                        prefix = deployment.getPrefix();
                    }
                    // Spec says relative to request, but TCK tests relative to Base URI, so we do that
                    String path = location.toString();
                    if (!path.startsWith("/")) {
                        path = "/" + path;
                    }
                    URI baseUri = new URI(req.getRequestScheme(), null, host, port, null, null, null);
                    location = baseUri.resolve(prefix + path);
                } catch (URISyntaxException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        metadata.putSingle(HttpHeaders.LOCATION, location);
        return this;
    }

    @Override
    public Response.ResponseBuilder contentLocation(URI location) {
        if (location == null) {
            metadata.remove(HttpHeaders.CONTENT_LOCATION);
            return this;
        }
        if (!location.isAbsolute()) {
            ResteasyReactiveRequestContext request = CurrentRequestManager.get();
            if (request != null) {
                // FIXME: this leaks server stuff onto the client
                ServerHttpRequest req = request.serverRequest();
                try {
                    String host = req.getRequestHost();
                    int port = -1;
                    int index = host.indexOf(":");
                    if (index > -1) {
                        port = Integer.parseInt(host.substring(index + 1));
                        host = host.substring(0, index);
                    }
                    String path = location.toString();
                    if (!path.startsWith("/")) {
                        path = "/" + path;
                    }
                    location = new URI(req.getRequestScheme(), null, host, port, null, null, null)
                            .resolve(path);
                } catch (URISyntaxException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        metadata.putSingle(HttpHeaders.CONTENT_LOCATION, location);
        return this;
    }

    @Override
    protected AbstractResponseBuilder doClone() {
        return new ResponseBuilderImpl();
    }

    //TODO: add the rest of static methods of Response if we need them

    public static Response.ResponseBuilder withStatus(Response.Status status) {
        return new ResponseBuilderImpl().status(status);
    }

    public static Response.ResponseBuilder ok() {
        return withStatus(Response.Status.OK);
    }

    public static Response.ResponseBuilder ok(Object entity) {
        return ok().entity(entity);
    }

    public static Response.ResponseBuilder noContent() {
        return withStatus(Response.Status.NO_CONTENT);
    }
}
