package client

import (
	"encoding/json"
	"io"
	"net/http"
	"testing"

	"github.com/nexuscrm/tests/contract/internal/liveapi"
)

type Config = liveapi.Config

type Client struct {
	inner *liveapi.Client
	cfg   Config
}

func New(t testing.TB) *Client {
	t.Helper()

	return &Client{
		inner: liveapi.NewAuthenticatedClient(t),
		cfg:   liveapi.LoadConfig(t),
	}
}

func LoadConfigForTest(t testing.TB) Config {
	t.Helper()
	return liveapi.LoadConfig(t)
}

func (c *Client) Config() Config {
	return c.cfg
}

func (c *Client) Get(path string) (*http.Response, error) {
	return c.inner.Do(http.MethodGet, path, "", nil)
}

func (c *Client) Do(method, path, contentType string, body []byte) (*http.Response, error) {
	return c.inner.Do(method, path, contentType, body)
}

func (c *Client) DoWithHeaders(method, path, contentType string, body []byte, headers map[string]string) (*http.Response, error) {
	return c.inner.DoWithHeaders(method, path, contentType, body, headers)
}

func (c *Client) DoJSON(method, path string, body any) (*http.Response, error) {
	return c.inner.DoJSON(method, path, body)
}

func (c *Client) DoJSONWithHeaders(method, path string, body any, headers map[string]string) (*http.Response, error) {
	return c.inner.DoJSONWithHeaders(method, path, body, headers)
}

func (c *Client) PostJSON(path string, body any) (*http.Response, error) {
	return c.DoJSON(http.MethodPost, path, body)
}

func (c *Client) PatchJSON(path string, body any) (*http.Response, error) {
	return c.DoJSON(http.MethodPatch, path, body)
}

func (c *Client) PutJSON(path string, body any) (*http.Response, error) {
	return c.DoJSON(http.MethodPut, path, body)
}

func (c *Client) Delete(path string) (*http.Response, error) {
	return c.inner.Do(http.MethodDelete, path, "", nil)
}

func DecodeJSON[T any](t testing.TB, resp *http.Response) T {
	t.Helper()
	defer resp.Body.Close()

	var out T
	if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
		body, _ := io.ReadAll(resp.Body)
		t.Fatalf("decode response: %v body=%s", err, string(body))
	}
	return out
}

func RequireStatus(t testing.TB, resp *http.Response, want int) {
	t.Helper()
	if resp.StatusCode == want {
		return
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	t.Fatalf("status = %d, want %d, body=%s", resp.StatusCode, want, string(body))
}
