package com.mosquito.project.sdk;

import org.mockito.Mockito;

import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

class TestHttpClient {

    private static final class ResponseSpec {
        private final int status;
        private final Object body;

        private ResponseSpec(int status, Object body) {
            this.status = status;
            this.body = body;
        }
    }

    private final HttpClient client;
    private final Map<String, ResponseSpec> responses = new ConcurrentHashMap<>();

    TestHttpClient() {
        this.client = Mockito.mock(HttpClient.class);
        try {
            Mockito.when(client.send(Mockito.any(HttpRequest.class), Mockito.any(HttpResponse.BodyHandler.class)))
                .thenAnswer(invocation -> {
                    HttpRequest request = invocation.getArgument(0);
                    String key = key(request.method(), request.uri().getPath());
                    ResponseSpec spec = responses.get(key);
                    if (spec == null) {
                        throw new RuntimeException("No stubbed response for " + key);
                    }
                    return buildResponse(spec);
                });
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException("Failed to stub HttpClient", e);
        }
    }

    HttpClient client() {
        return client;
    }

    void register(String method, String path, int status, Object body) {
        responses.put(key(method, path), new ResponseSpec(status, body));
    }

    private String key(String method, String path) {
        return method + " " + path;
    }

    @SuppressWarnings("unchecked")
    private <T> HttpResponse<T> buildResponse(ResponseSpec spec) {
        HttpResponse<T> response = (HttpResponse<T>) Mockito.mock(HttpResponse.class);
        Mockito.when(response.statusCode()).thenReturn(spec.status);
        Mockito.when(response.body()).thenReturn((T) spec.body);
        return response;
    }
}
