package dev.lions.unionflow.server.service;

import com.sun.net.httpserver.HttpServer;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

/**
 * QuarkusTestResourceLifecycleManager that starts a lightweight HTTP server simulating
 * the Wave Checkout API at {@code /v1/checkout/sessions}.
 *
 * <p>Tests can change the response mode via {@link #setResponseMode(ResponseMode)} before
 * calling the service.
 */
public class MockWaveApiResource implements QuarkusTestResourceLifecycleManager {

    /** Modes the mock server can operate in. */
    public enum ResponseMode {
        /** HTTP 200 with valid session JSON. */
        SUCCESS,
        /** HTTP 400 error response. */
        HTTP_ERROR,
        /** HTTP 200 with empty JSON (missing id / wave_launch_url). */
        INVALID_JSON
    }

    private static final AtomicReference<ResponseMode> MODE =
            new AtomicReference<>(ResponseMode.SUCCESS);

    private HttpServer server;

    /** Base URL (e.g. {@code http://localhost:PORT}) — set after {@link #start()}. */
    public static volatile String serverBaseUrl;

    /** Convenience setter called by tests before exercising the service. */
    public static void setResponseMode(ResponseMode mode) {
        MODE.set(mode);
    }

    @Override
    public Map<String, String> start() {
        try {
            server = HttpServer.create(new InetSocketAddress(0), 0);

            server.createContext("/v1/checkout/sessions", exchange -> {
                // Consume the request body
                exchange.getRequestBody().readAllBytes();

                ResponseMode current = MODE.get();
                switch (current) {
                    case HTTP_ERROR -> {
                        byte[] body = "{\"error\":\"Bad Request\"}".getBytes(StandardCharsets.UTF_8);
                        exchange.sendResponseHeaders(400, body.length);
                        try (OutputStream os = exchange.getResponseBody()) { os.write(body); }
                    }
                    case INVALID_JSON -> {
                        byte[] body = "{}".getBytes(StandardCharsets.UTF_8);
                        exchange.getResponseHeaders().set("Content-Type", "application/json");
                        exchange.sendResponseHeaders(200, body.length);
                        try (OutputStream os = exchange.getResponseBody()) { os.write(body); }
                    }
                    default -> { // SUCCESS
                        String json = "{\"id\":\"cos-real-0001\","
                                + "\"wave_launch_url\":\"https://pay.wave.com/m/cos-real-0001\"}";
                        byte[] body = json.getBytes(StandardCharsets.UTF_8);
                        exchange.getResponseHeaders().set("Content-Type", "application/json");
                        exchange.sendResponseHeaders(200, body.length);
                        try (OutputStream os = exchange.getResponseBody()) { os.write(body); }
                    }
                }
            });

            server.start();
            int port = server.getAddress().getPort();
            serverBaseUrl = "http://localhost:" + port;

            Map<String, String> config = new HashMap<>();
            // WaveCheckoutService line 70: strips trailing slashes, then appends "/v1" if missing.
            // Using a trailing slash triggers the baseUrl.endsWith("/") branch (instruction coverage).
            // With "http://host:port/v1/", the service strips the slash → "http://host:port/v1"
            // then skips the "/v1" append (already ends with "/v1"), giving URL:
            //   "http://host:port/v1/checkout/sessions" — matches our server context.
            config.put("wave.api.base.url", serverBaseUrl + "/v1/");
            config.put("wave.mock.enabled", "false");
            config.put("wave.api.key", "test-real-api-key");
            config.put("wave.api.secret", "test-signing-secret");
            config.put("wave.redirect.base.url", "http://localhost:8080");
            return config;
        } catch (IOException e) {
            throw new RuntimeException("Failed to start mock Wave API server", e);
        }
    }

    @Override
    public void stop() {
        if (server != null) {
            server.stop(0);
        }
    }
}
