package gin

import (
	"context"
	errors2 "errors"
	"github.com/UpmeshLTD/urus-aio/infrastructure/server/endpoint"
	"github.com/UpmeshLTD/urus-aio/infrastructure/server/endpoint/errors"
	"net/http"
	"net/http/httptest"

	"github.com/gin-gonic/gin"
	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
)

var _ = Describe("NewHandler", func() {
	type Response struct {
		Value string `json:"value"`
	}

	type Expectation struct {
		Status int
		Body   string
	}

	newEndpoint := func(resp interface{}, err error) endpoint.Endpoint {
		return endpoint.NewEndpoint(func(ctx context.Context, request interface{}) (interface{}, error) {
			return resp, err
		})
	}

	newDecoder := func(req interface{}, err error) RequestDecoderFunc {
		return func(c *gin.Context) (interface{}, error) {
			return req, err
		}
	}

	newEncoder := func(status int, err error) ResponseEncoderFunc {
		return func(c *gin.Context, response interface{}) error {
			c.JSON(status, response)
			return err
		}
	}

	DescribeTable("HandlerFunc should respond properly", func(e endpoint.Endpoint, decoderFunc RequestDecoderFunc, encoderFunc ResponseEncoderFunc, expectation Expectation) {
		w := httptest.NewRecorder()

		h := NewHandler(e, decoderFunc, encoderFunc)
		router := gin.Default()
		router.GET("/test", h)

		req, _ := http.NewRequest("GET", "/test", nil)
		router.ServeHTTP(w, req)

		Expect(w.Code).Should(Equal(expectation.Status))
		Expect(w.Body.String()).Should(Equal(expectation.Body))
	},
		Entry("case 0",
			newEndpoint(&Response{Value: "aaa"}, nil),
			newDecoder(nil, nil),
			newEncoder(http.StatusOK, nil),
			Expectation{
				Status: http.StatusOK,
				Body:   "{\"value\":\"aaa\"}",
			},
		),
		Entry("case 1",
			newEndpoint(nil, errors.ErrNotFound),
			newDecoder(nil, nil),
			newEncoder(http.StatusOK, nil),
			Expectation{
				Status: http.StatusNotFound,
				Body:   "{\"message\":\"not found\"}",
			},
		),
		Entry("case 2",
			newEndpoint(nil, errors2.New("some error")),
			newDecoder(nil, nil),
			newEncoder(http.StatusOK, nil),
			Expectation{
				Status: http.StatusInternalServerError,
				Body:   "{\"message\":\"some error\"}",
			},
		),
		Entry("case 3",
			newEndpoint(&Response{Value: "aaa"}, nil),
			newDecoder(nil, errors.ErrInvalidArgument),
			newEncoder(http.StatusOK, nil),
			Expectation{
				Status: http.StatusBadRequest,
				Body:   "{\"message\":\"invalid argument\"}",
			},
		),
		Entry("case 4",
			newEndpoint(&Response{Value: "aaa"}, nil),
			newDecoder(nil, errors.ErrUnimplemented),
			newEncoder(http.StatusOK, nil),
			Expectation{
				Status: http.StatusNotImplemented,
				Body:   "{\"message\":\"unimplemented\"}",
			},
		),
	)

})
