package study.gateway.proxywebflux;

import java.net.URI;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.webflux.ProxyExchange;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@SpringBootApplication
@RestController
public class ProxyWebfluxApplication {
    private final URI upstream;

    public ProxyWebfluxApplication(@Value("${lab.upstream}") URI upstream) { this.upstream = upstream; }

    public static void main(String[] args) { SpringApplication.run(ProxyWebfluxApplication.class, args); }

    @RequestMapping(path = "/proxy/**", method = {RequestMethod.GET, RequestMethod.POST})
    Mono<ResponseEntity<byte[]>> proxy(ProxyExchange<byte[]> proxy, ServerWebExchange exchange) {
        // WebFlux forward() dispatches the incoming verb to this REMOTE URI.
        return proxy.uri(target(proxy.path("/proxy/"), exchange.getRequest().getURI().getRawQuery()))
                .header("X-Before", "proxy-webflux").forward(this::response);
    }

    @PostMapping("/replace/**")
    Mono<ResponseEntity<byte[]>> replace(ProxyExchange<byte[]> proxy, @RequestBody String body) {
        return proxy.uri(target(proxy.path("/replace/"), null))
                .header("Content-Type", "application/json")
                .body(Map.of("message", "new:" + body)).post(this::response);
    }

    @GetMapping("/bad-prefix/**")
    String badPrefix(ProxyExchange<byte[]> proxy) { return proxy.path("/different/"); }

    @ExceptionHandler(IllegalArgumentException.class)
    ResponseEntity<String> badInput() { return ResponseEntity.badRequest().body("Invalid proxy path"); }

    private String target(String tail, String query) {
        if (!tail.matches("[A-Za-z0-9/_-]+")) {
            throw new IllegalArgumentException("Only simple fixture paths are accepted");
        }
        return upstream + "/api/" + tail + (query == null ? "" : "?" + query);
    }

    private ResponseEntity<byte[]> response(ResponseEntity<byte[]> result) {
        return ResponseEntity.status(result.getStatusCode()).headers(result.getHeaders())
                .header("X-Proxy", "proxy-webflux").body(result.getBody());
    }
}
