package tests

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"testing"

	"github.com/golang-jwt/jwt/v5"
	"github.com/joho/godotenv"
	"github.com/stretchr/testify/assert"
)

type JWTClient struct {
	token  *jwt.Token
	client http.Client
}

func (jc *JWTClient) Get(url string, body io.Reader) (resp *http.Response, err error) {
	return jc.request(http.MethodGet, url, body, nil)
}

func (jc *JWTClient) Post(url string, body io.Reader) (resp *http.Response, err error) {
	return jc.request(http.MethodPost, url, body, nil)
}

func (jc *JWTClient) Patch(url string, body io.Reader) (resp *http.Response, err error) {
	return jc.request(http.MethodPatch, url, body, nil)
}

func (jc *JWTClient) Delete(url string, body io.Reader) (resp *http.Response, err error) {
	return jc.request(http.MethodDelete, url, body, nil)
}

func (jc *JWTClient) request(method, url string, body io.Reader, callback func(*http.Request)) (resp *http.Response, err error) {
	req, err := http.NewRequest(method, url, body)
	if err != nil {
		panic(err)
	}

	if callback != nil {
		callback(req)
	} else if method == http.MethodPost {
		req.Header.Set("Content-Type", "application/json")
	}

	req.Header.Set("Authorization", "Bearer "+jc.token.Raw)

	return jc.client.Do(req)
}

func (jc *JWTClient) GetExpect(t *testing.T, url string, code int, data interface{}) {
	t.Helper()
	jc.expect(t, http.MethodGet, url, code, data)
}

func (jc *JWTClient) PostExpect(t *testing.T, url string, code int, data interface{}) {
	t.Helper()
	jc.expect(t, http.MethodPost, url, code, data)
}

func (jc *JWTClient) PatchExpect(t *testing.T, url string, code int, data interface{}) {
	t.Helper()
	jc.expect(t, http.MethodPatch, url, code, data)
}

func (jc *JWTClient) expect(t *testing.T, method, url string, code int, data interface{}) {
	t.Helper()
	request, err := json.Marshal(&data)
	assert.NoError(t, err)
	body := bytes.NewBuffer(request)
	r, err := jc.request(method, url, body, nil)
	assert.NoError(t, err)
	assert.Equal(t, code, r.StatusCode)
}

func registerUser(login string) *jwt.Token {
	client := &http.Client{}

	err := godotenv.Load("../deployments/test/auth.env.test")
	if err != nil {
		panic(err)
	}

	publicKey := os.Getenv("PUBLIC_ACCESS_SECRET_KEY")
	if publicKey == "" {
		panic("no public key found")
	}

	payload, err := json.Marshal(map[string]string{
		"login":       login,
		"email":       login + "@mail.ru",
		"password":    "887",
		"phoneNumber": "+9008007766",
	})
	if err != nil {
		panic(err)
	}

	req, err := http.NewRequest("POST", "http://localhost:8000/auth/register", bytes.NewBuffer(payload))
	if err != nil {
		panic(err)
	}

	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer func() {
		if derr := resp.Body.Close(); derr != nil {
			fmt.Printf("error close response body in registerUser: %v", derr)
		}
	}()

	bytes, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	var response struct {
		AccessToken  string `json:"accessToken"`
		RefreshToken string `json:"refreshToken"`
	}

	err = json.Unmarshal(bytes, &response)
	if err != nil {
		panic(err)
	}

	token, err := jwt.Parse(response.AccessToken, func(token *jwt.Token) (any, error) {
		return jwt.ParseRSAPublicKeyFromPEM([]byte(publicKey))
	})
	fmt.Println(token)
	if err != nil {
		panic(err)
	}

	return token
}
