package testutils

import (
	"github.com/stretchr/testify/assert"
	"github.com/valyala/fasthttp"
	"io/ioutil"
	"testing"
)

func TestNewMockRequest(t *testing.T) {
	t.Run("should make new request", func(t *testing.T) {
		req := NewMockRequest("http://foo.bar/test", "some body")

		body, err := ioutil.ReadAll(req.Body)
		if err != nil {
			t.Fatal(err)
		}

		assert.Equal(t, "some body", string(body))
		assert.Equal(t, "http://foo.bar/test", req.URL.String())
	})

	t.Run("should not set body", func(t *testing.T) {
		req := NewMockRequest("http://foo.bar/test", "")

		assert.Nil(t, req.Body)
	})

	t.Run("should set default url", func(t *testing.T) {
		req := NewMockRequest("", "")

		assert.Equal(t, "http://foo.bar/", req.URL.String())
	})

	t.Run("should panic with bad url", func(t *testing.T) {
		assert.Panics(t, func() {
			NewMockRequest("{", "")
		})
	})
}

func TestMockServe(t *testing.T) {
	t.Run("should serve", func(t *testing.T) {
		req := NewMockRequest("", "")

		proceed := false
		_, _ = MockServe(req, func(ctx *fasthttp.RequestCtx) {
			proceed = true
		})

		assert.True(t, proceed, "handler not processed")
	})

	t.Run("should pass request info", func(t *testing.T) {
		req := NewMockRequest("http://foo.bar/", "hi")

		_, _ = MockServe(req, func(ctx *fasthttp.RequestCtx) {
			assert.Equal(t, "http://foo.bar/", ctx.URI().String(), "request uri not matched")
			assert.Equal(t, "hi", string(ctx.Request.Body()))
		})
	})

	t.Run("should return error", func(t *testing.T) {
		_, err := MockServe(NewMockRequest("", ""), func(ctx *fasthttp.RequestCtx) {
			ctx.Response.SetStatusCode(301)
		})
		assert.NotNil(t, err)
	})
}

func TestAssertMockServe(t *testing.T) {
	t.Run("should not failed", func(t *testing.T) {
		t0 := &testing.T{}
		req := NewMockRequest("", "")

		_ = AssertMockServe(t0, req, func(ctx *fasthttp.RequestCtx) {
		})

		assert.False(t, t0.Failed(), "should not failed")
	})

	t.Run("should failed", func(t *testing.T) {
		t0 := &testing.T{}
		req := NewMockRequest("", "")

		defer func() {
			recover()
			assert.True(t, t0.Failed(), "should failed")
		}()

		_ = AssertMockServe(t0, req, func(ctx *fasthttp.RequestCtx) {
			ctx.Response.SetStatusCode(301)
		})
	})
}

func TestAssertResponse(t *testing.T) {
	t.Run("should succeed", func(t *testing.T) {
		t0 := &testing.T{}

		res := AssertMockServe(t, NewMockRequest("", ""), func(ctx *fasthttp.RequestCtx) {
			ctx.Response.SetBodyString("foo.bar")
			ctx.Response.SetStatusCode(201)
		})

		AssertResponse(t0, res, 201, "foo.bar")

		assert.False(t, t0.Failed())
	})

	t.Run("should failed with wrong status", func(t *testing.T) {
		t0 := &testing.T{}

		res := AssertMockServe(t, NewMockRequest("", ""), func(ctx *fasthttp.RequestCtx) {
			ctx.Response.SetBodyString("foo.bar")
			ctx.Response.SetStatusCode(201)
		})

		AssertResponse(t0, res, 200, "foo.bar")

		assert.True(t, t0.Failed())
	})

	t.Run("should failed with wrong body", func(t *testing.T) {
		t0 := &testing.T{}

		res := AssertMockServe(t, NewMockRequest("", ""), func(ctx *fasthttp.RequestCtx) {
			ctx.Response.SetBodyString("foo.bar")
			ctx.Response.SetStatusCode(201)
		})

		AssertResponse(t0, res, 201, "bar.foo")

		assert.True(t, t0.Failed())
	})
}
