package Auth_test

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"testing"

	"git.tovijaeschke.xyz/tovi/Capsule/Backend/Api"
	"git.tovijaeschke.xyz/tovi/Capsule/Backend/Database"
	"git.tovijaeschke.xyz/tovi/Capsule/Backend/Database/Seeder"
	"git.tovijaeschke.xyz/tovi/Capsule/Backend/Models"
	"github.com/gorilla/mux"
)

func Test_Signup(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	Database.InitTest()

	r := mux.NewRouter()
	Api.InitAPIEndpoints(r)
	ts := httptest.NewServer(r)
	defer ts.Close()

	userKey, _ := Seeder.GenerateAesKey()

	pubKey := Seeder.GetPubKey()

	d := struct {
		Username        string `json:"username"`
		Password        string `json:"password"`
		ConfirmPassword string `json:"confirm_password"`
		PubKey          string `json:"asymmetric_public_key"`
		PrivKey         string `json:"asymmetric_private_key"`
		SymKey          string `json:"symmetric_key"`
	}{
		Username:        "test",
		Password:        "password",
		ConfirmPassword: "password",
		PubKey:          Seeder.PublicKey,
		PrivKey:         Seeder.EncryptedPrivateKey,
		SymKey: base64.StdEncoding.EncodeToString(
			Seeder.EncryptWithPublicKey(userKey.Key, pubKey),
		),
	}

	jsonStr, _ := json.Marshal(d)
	req, _ := http.NewRequest("POST", ts.URL+"/api/v1/signup", bytes.NewBuffer(jsonStr))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		t.Errorf("Expected nil, recieved %s", err.Error())
		return
	}

	if resp.StatusCode != http.StatusNoContent {
		t.Errorf("Expected %d, recieved %d", http.StatusNoContent, resp.StatusCode)
		return
	}

	var user Models.User

	err = Database.DB.First(&user, "username = ?", "test").Error

	if err != nil {
		t.Errorf("Expected user record, recieved %s", err.Error())
		return
	}
}

func Test_Signup_PasswordMismatchFails(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	Database.InitTest()

	r := mux.NewRouter()
	Api.InitAPIEndpoints(r)
	ts := httptest.NewServer(r)
	defer ts.Close()

	userKey, _ := Seeder.GenerateAesKey()

	pubKey := Seeder.GetPubKey()

	d := struct {
		Username        string `json:"username"`
		Password        string `json:"password"`
		ConfirmPassword string `json:"confirm_password"`
		PubKey          string `json:"asymmetric_public_key"`
		PrivKey         string `json:"asymmetric_private_key"`
		SymKey          string `json:"symmetric_key"`
	}{
		Username:        "test",
		Password:        "password",
		ConfirmPassword: "password1",
		PubKey:          Seeder.PublicKey,
		PrivKey:         Seeder.EncryptedPrivateKey,
		SymKey: base64.StdEncoding.EncodeToString(
			Seeder.EncryptWithPublicKey(userKey.Key, pubKey),
		),
	}

	jsonStr, _ := json.Marshal(d)
	req, _ := http.NewRequest("POST", ts.URL+"/api/v1/signup", bytes.NewBuffer(jsonStr))
	req.Header.Set("X-Custom-Header", "myvalue")
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		t.Errorf("Expected nil, recieved %s", err.Error())
		return
	}

	if resp.StatusCode != http.StatusUnprocessableEntity {
		t.Errorf("Expected %d, recieved %d", http.StatusUnprocessableEntity, resp.StatusCode)
		return
	}
}

func Test_Signup_MissingDataFails(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	Database.InitTest()

	r := mux.NewRouter()
	Api.InitAPIEndpoints(r)
	ts := httptest.NewServer(r)
	defer ts.Close()

	d := struct {
		Username        string `json:"username"`
		Password        string `json:"password"`
		ConfirmPassword string `json:"confirm_password"`
		PubKey          string `json:"asymmetric_public_key"`
		PrivKey         string `json:"asymmetric_private_key"`
		SymKey          string `json:"symmetric_key"`
	}{
		Username:        "test",
		Password:        "password",
		ConfirmPassword: "password",
		PubKey:          "",
		PrivKey:         "",
		SymKey:          "",
	}

	jsonStr, _ := json.Marshal(d)
	req, _ := http.NewRequest("POST", ts.URL+"/api/v1/signup", bytes.NewBuffer(jsonStr))
	req.Header.Set("X-Custom-Header", "myvalue")
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		t.Errorf("Expected nil, recieved %s", err.Error())
	}

	if resp.StatusCode != http.StatusUnprocessableEntity {
		t.Errorf("Expected %d, recieved %d", http.StatusUnprocessableEntity, resp.StatusCode)
	}
}
