package benefactorkindboxreqhandler_test

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"git.gocasts.ir/ebhomengo/niki/delivery/http_server/middleware"
	"git.gocasts.ir/ebhomengo/niki/entity"
	"git.gocasts.ir/ebhomengo/niki/param/benefactor/address"
	benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactore"
	benefactorkindboxreqparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/kind_box_req"
	testutils "git.gocasts.ir/ebhomengo/niki/test"
	"git.gocasts.ir/ebhomengo/niki/test/seed"
	"github.com/brianvoe/gofakeit/v6"
	"github.com/labstack/echo/v4"
	"github.com/stretchr/testify/assert"
)

func TestAdd(t *testing.T) {
	testutils.SetupEnd2EndTest(t)
	respSendOTP := testutils.SendOTP(t)

	loginOrRegisterRequest := benefactoreparam.LoginOrRegisterRequest{
		PhoneNumber:      respSendOTP.PhoneNumber,
		VerificationCode: respSendOTP.Code,
	}
	benefactor, cleanupBenefactor := testutils.CreateBenefactorWithSvc(t, loginOrRegisterRequest)
	defer cleanupBenefactor()
	benefactorAddAddressRequest := addressparam.BenefactorAddAddressRequest{
		PostalCode:   gofakeit.Address().Zip,
		Address:      gofakeit.Address().Address,
		Lat:          float32(gofakeit.Address().Latitude),
		Lon:          float32(gofakeit.Address().Longitude),
		CityID:       gofakeit.UintRange(1, 100),
		ProvinceID:   gofakeit.UintRange(1, 31),
		BenefactorID: benefactor.BenefactorInfo.ID,
	}
	address, cleanupAddress := testutils.CreateAddressWithSvc(t, benefactorAddAddressRequest)
	defer cleanupAddress()
	kindboxreqResponse, _ := json.Marshal(entity.KindBoxReq{
		ID:             1,
		KindBoxType:    entity.KindBoxCylindrical,
		CountRequested: gofakeit.UintRange(1, 100),
		CountAccepted:  0,
		BenefactorID:   benefactor.BenefactorInfo.ID,
		Status:         entity.KindBoxReqPendingStatus,
		Description:    "",
		ReferDate:      time.Time{},
		AddressID:      address.Address.ID,
	})

	type testCase struct {
		name           string
		requestBody    interface{}
		expectedStatus int
		expectedBody   string
		err            bool
		token          string
	}

	testCases := []testCase{
		{
			name:           "invalid payload",
			requestBody:    `invalid payload`,
			expectedStatus: http.StatusBadRequest,
			expectedBody:   `{"message": "Bad request"}`,
			err:            true,
			token:          "Bearer " + benefactor.Tokens.AccessToken,
		},
		{
			name: "invalid or expired jwt",
			requestBody: benefactorkindboxreqparam.KindBoxReqAddRequest{
				TypeID:         1,
				AddressID:      address.Address.ID,
				ReferDate:      time.Now(),
				CountRequested: 1,
			},
			token:          "Bearer 12" + benefactor.Tokens.AccessToken,
			expectedStatus: http.StatusUnauthorized,
			err:            true,
			expectedBody:   `{"message":"invalid or expired jwt"}`,
		},
		{
			name: "Validation Failed",
			requestBody: benefactorkindboxreqparam.KindBoxReqAddRequest{
				AddressID:      address.Address.ID,
				ReferDate:      time.Now(),
				CountRequested: 2,
			},
			err:            true,
			token:          "Bearer " + benefactor.Tokens.AccessToken,
			expectedStatus: http.StatusUnprocessableEntity,
			expectedBody: `{
				"errors":{
					"type_id":"cannot be blank"
				},
				"message":"invalid input"
			}`,
		},
		{
			name: "Added successfully",
			requestBody: benefactorkindboxreqparam.KindBoxReqAddRequest{
				TypeID:         2,
				AddressID:      address.Address.ID,
				ReferDate:      time.Now(),
				CountRequested: 2,
			},
			token:          "Bearer " + benefactor.Tokens.AccessToken,
			expectedStatus: http.StatusCreated,
			expectedBody:   string(kindboxreqResponse),
		},
	}

	e := echo.New()
	r := e.Group("/benefactor/kindboxreqs")

	r.POST("/", testutils.BenefactorkindBoxReqHandler.Add, middleware.Auth(testutils.AuthSvc, testutils.AuthConfig),
		middleware.BenefactorAuthorization(entity.UserBenefactorRole))

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			requestBody, _ := json.Marshal(tc.requestBody)
			req := httptest.NewRequest(http.MethodPost, "/benefactor/kindboxreqs/", bytes.NewBuffer(requestBody))

			req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
			req.Header.Set(echo.HeaderAuthorization, tc.token)

			rec := httptest.NewRecorder()

			e.ServeHTTP(rec, req)

			// Assertion
			assert.Equal(t, tc.expectedStatus, rec.Code)

			if tc.err {
				assert.JSONEq(t, tc.expectedBody, rec.Body.String())
				return
			}
			response := &benefactorkindboxreqparam.KindBoxReqAddResponse{}
			err := json.Unmarshal(
				rec.Body.Bytes(),
				response,
			)
			assert.Nil(t, err, "error in deserializing the request")
			seed.DeleteBenefactor(t, testutils.MysqlRepo, response.KindBoxReq.ID)
			assert.NotEmpty(t, response.KindBoxReq)
		})
	}
}
