package controllers

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"

	"GoMembership/internal/config"
	"GoMembership/internal/constants"
	"GoMembership/internal/utils"

	"github.com/gin-gonic/gin"
)

type RelayContactRequestTest struct {
	Input        url.Values
	Name         string
	WantResponse int
	Assert       bool
}

func testContactController(t *testing.T) {

	tests := getContactData()
	for _, tt := range tests {
		t.Run(tt.Name, func(t *testing.T) {
			if err := runSingleTest(&tt); err != nil {
				t.Errorf("Test failed: %v", err.Error())
			}
		})
	}
}

func (rt *RelayContactRequestTest) SetupContext() (*gin.Context, *httptest.ResponseRecorder, *gin.Engine) {
	return GetMockedFormContext(rt.Input, "/contact")
}

func (rt *RelayContactRequestTest) RunHandler(c *gin.Context, router *gin.Engine) {
	router.POST("/contact", Cc.RelayContactRequest)
	router.ServeHTTP(c.Writer, c.Request)
	// Cc.RelayContactRequest(c)
}

func (rt *RelayContactRequestTest) ValidateResponse(w *httptest.ResponseRecorder) error {
	if w.Code != rt.WantResponse {
		return fmt.Errorf("Didn't get the expected response code: got: %v; expected: %v", w.Code, rt.WantResponse)
	}
	return nil
}

func (rt *RelayContactRequestTest) ValidateResult() error {

	messages := utils.SMTPGetMessages()

	for _, message := range messages {

		mail, err := utils.DecodeMail(message.MsgRequest())
		if err != nil {
			return err
		}
		if strings.Contains(mail.Subject, constants.MailContactSubject) {

			if err := checkContactRequestMail(mail, rt); err != nil {
				return err
			}
		} else {
			return fmt.Errorf("Subject not expected: %v", mail.Subject)
		}
	}
	return nil
}

func checkContactRequestMail(mail *utils.Email, rt *RelayContactRequestTest) error {

	if !strings.Contains(mail.To, config.Recipients.ContactForm) {
		return fmt.Errorf("Contact Information didn't reach the admin! Recipient was: %v instead of %v", mail.To, config.Recipients.ContactForm)
	}
	if !strings.Contains(mail.From, config.SMTP.User) {
		return fmt.Errorf("Contact Information was sent from unexpected address! Sender was: %v instead of %v", mail.From, config.SMTP.User)
	}

	//Check if all the relevant data has been passed to the mail.
	if !strings.Contains(mail.Body, rt.Input.Get("name")) {
		return fmt.Errorf("User name(%v) has not been rendered in contact mail.", rt.Input.Get("name"))
	}

	if !strings.Contains(mail.Body, rt.Input.Get("message")) {
		return fmt.Errorf("User message(%v) has not been rendered in contact mail.", rt.Input.Get("message"))
	}
	return nil
}

func getBaseRequest() *url.Values {
	return &url.Values{
		"username": {""},
		"name":     {"My-First and-Last-Name"},
		"REPLY_TO": {"name@domain.de"},
		"message":  {"My message to the world"},
	}
}

func customizeRequest(updates map[string]string) *url.Values {
	form := getBaseRequest()
	for key, value := range updates {
		form.Set(key, value)
	}
	return form
}

func getContactData() []RelayContactRequestTest {
	return []RelayContactRequestTest{
		{
			Name:         "mail empty, should fail",
			WantResponse: http.StatusNotAcceptable,
			Assert:       false,
			Input: *customizeRequest(
				map[string]string{
					"REPLY_TO": "",
				}),
		},
		{
			Name:         "mail invalid, should fail",
			WantResponse: http.StatusNotAcceptable,
			Assert:       false,
			Input: *customizeRequest(
				map[string]string{
					"REPLY_TO": "novalid#email.de",
				}),
		},
		{
			Name:         "No message should fail",
			WantResponse: http.StatusNotAcceptable,
			Assert:       true,
			Input: *customizeRequest(
				map[string]string{
					"message": "",
				}),
		},
		{
			Name:         "Honeypot set, should fail",
			WantResponse: http.StatusNotAcceptable,
			Assert:       true,
			Input: *customizeRequest(
				map[string]string{
					"username": "I'm a bot",
				}),
		},
		{
			Name:         "Correct message, should pass",
			WantResponse: http.StatusAccepted,
			Assert:       true,
			Input: *customizeRequest(
				map[string]string{}),
		},
	}
}
