package dnsimple

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"testing"
)

var (
	// mux is the HTTP request multiplexer used with the test server.
	mux *http.ServeMux

	// client is the DNSimple client being tested.
	client *Client

	// server is a test HTTP server used to provide mock API responses.
	server *httptest.Server
)

// This method of testing http client APIs is borrowed from
// Will Norris's work in go-github @ https://github.com/google/go-github
func setup() {
	mux = http.NewServeMux()
	server = httptest.NewServer(mux)

	client = NewClient("mytoken", "me@example.com")
	client.BaseURL = server.URL + "/"
}

func teardown() {
	server.Close()
}

func testMethod(t *testing.T, r *http.Request, want string) {
	if want != r.Method {
		t.Errorf("Request method = %v, want %v", r.Method, want)
	}
}

func testRequestJSON(t *testing.T, r *http.Request, values map[string]interface{}) {
	var dat map[string]interface{}

	body, _ := ioutil.ReadAll(r.Body)

	if err := json.Unmarshal(body, &dat); err != nil {
		t.Errorf("Could not decode json body: %v", err)
	}

	if !reflect.DeepEqual(values, dat) {
		t.Errorf("Request parameters = %v, want %v", dat, values)
	}
}

type values map[string]string

func testFormValues(t *testing.T, r *http.Request, values values) {
	want := url.Values{}
	for k, v := range values {
		want.Add(k, v)
	}

	r.ParseForm()
	if !reflect.DeepEqual(want, r.Form) {
		t.Errorf("Request parameters = %v, want %v", r.Form, want)
	}
}

func testString(t *testing.T, test, value, want string) {
	if value != want {
		t.Errorf("%s returned %+v, want %+v", test, value, want)
	}
}

func TestNewClient(t *testing.T) {
	c := NewClient("mytoken", "me@example.com")

	if c.BaseURL != baseURL {
		t.Errorf("NewClient BaseURL = %v, want %v", c.BaseURL, baseURL)
	}
}

func TestNewAuthenticatedClient(t *testing.T) {
	c := NewAuthenticatedClient(NewApiTokenCredentials("me@example.com", "mytoken"))

	if c.BaseURL != baseURL {
		t.Errorf("NewClient BaseURL = %v, want %v", c.BaseURL, baseURL)
	}
}

func TestNewRequest(t *testing.T) {
	c := NewClient("mytoken", "me@example.com")
	c.BaseURL = "https://go.example.com/"

	inURL, outURL := "foo", "https://go.example.com/v1/foo"
	req, _ := c.NewRequest("GET", inURL, nil)

	// test that relative URL was expanded with the proper BaseURL
	if req.URL.String() != outURL {
		t.Errorf("makeRequest(%v) URL = %v, want %v", inURL, req.URL, outURL)
	}

	// test that default user-agent is attached to the request
	userAgent := req.Header.Get("User-Agent")
	if c.UserAgent != userAgent {
		t.Errorf("makeRequest() User-Agent = %v, want %v", userAgent, c.UserAgent)
	}
}

type badObject struct {
}

func (o *badObject) MarshalJSON() ([]byte, error) {
	return nil, errors.New("Bad object is bad")
}

func TestNewRequestWithBody(t *testing.T) {
	c := NewClient("mytoken", "me@example.com")
	c.BaseURL = "https://go.example.com/"

	inURL, _ := "foo", "https://go.example.com/v1/foo"
	badObject := badObject{}
	_, err := c.NewRequest("GET", inURL, &badObject)

	if err == nil {
		t.Errorf("NewRequest with body expected error with blank string")
	}
}
