package Messages_test

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"testing"

	"git.tovijaeschke.xyz/tovi/Capsule/Backend/Database"
	"git.tovijaeschke.xyz/tovi/Capsule/Backend/Database/Seeder"
	"git.tovijaeschke.xyz/tovi/Capsule/Backend/Models"
	"git.tovijaeschke.xyz/tovi/Capsule/Backend/Tests"
)

func Test_ConversationsList(t *testing.T) {
	client, ts, err := Tests.InitTestEnv()
	if err != nil {
		t.Errorf("Expected nil, recieved %s", err.Error())
		return
	}

	u, err := Database.GetUserByUsername("test")

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

	nameCiphertext, err := key.AesEncrypt([]byte("Test conversation"))
	if err != nil {
		t.Errorf("Expected nil, recieved %s", err.Error())
		return
	}

	twoUserCiphertext, err := key.AesEncrypt([]byte("false"))
	if err != nil {
		t.Errorf("Expected nil, recieved %s", err.Error())
		return
	}

	messageThread := Models.ConversationDetail{
		Name:    base64.StdEncoding.EncodeToString(nameCiphertext),
		TwoUser: base64.StdEncoding.EncodeToString(twoUserCiphertext),
	}

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

	conversationDetailIDCiphertext, err := key.AesEncrypt([]byte(messageThread.ID.String()))
	if err != nil {
		t.Errorf("Expected nil, recieved %s", err.Error())
		return
	}

	adminCiphertext, err := key.AesEncrypt([]byte("true"))
	if err != nil {
		t.Errorf("Expected nil, recieved %s", err.Error())
		return
	}

	pubKey := Seeder.GetPubKey()

	messageThreadUser := Models.UserConversation{
		UserID:               u.ID,
		ConversationDetailID: base64.StdEncoding.EncodeToString(conversationDetailIDCiphertext),
		Admin:                base64.StdEncoding.EncodeToString(adminCiphertext),
		SymmetricKey: base64.StdEncoding.EncodeToString(
			Seeder.EncryptWithPublicKey(key.Key, pubKey),
		),
	}

	err = Database.CreateUserConversation(&messageThreadUser)

	req, _ := http.NewRequest("GET", ts.URL+"/api/v1/auth/conversations", nil)

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

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

	requestBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
		return
	}

	var conversations []Models.UserConversation

	json.Unmarshal(requestBody, &conversations)

	if len(conversations) != 1 {
		t.Errorf("Expected %d, recieved %d", 1, len(conversations))
		return
	}

	conv := conversations[0]

	decodedId, err := base64.StdEncoding.DecodeString(conv.ConversationDetailID)
	if err != nil {
		t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
		return
	}
	decrypedId, err := key.AesDecrypt(decodedId)
	if err != nil {
		t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
		return
	}

	req, _ = http.NewRequest(
		"GET",
		ts.URL+"/api/v1/auth/conversation_details?conversation_detail_ids="+string(decrypedId),
		nil,
	)

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

	var conversationDetails []Models.ConversationDetail

	requestBody, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
		return
	}

	json.Unmarshal(requestBody, &conversationDetails)

	if len(conversationDetails) != 1 {
		t.Errorf("Expected %d, recieved %d", 1, len(conversations))
	}

	decodedName, err := base64.StdEncoding.DecodeString(conversationDetails[0].Name)
	if err != nil {
		t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
		return
	}
	decrypedName, err := key.AesDecrypt(decodedName)
	if err != nil {
		t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
		return
	}

	if string(decrypedName) != "Test conversation" {
		t.Errorf("Expected %s, recieved %s", "Test converation", string(decrypedName))
	}
}

func Test_ConversationsListPagination(t *testing.T) {
	client, ts, err := Tests.InitTestEnv()
	if err != nil {
		t.Errorf("Expected nil, recieved %s", err.Error())
		return
	}

	u, err := Database.GetUserByUsername("test")

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

	for i := 0; i < 40; i++ {
		nameCiphertext, err := key.AesEncrypt([]byte(
			fmt.Sprintf("Test conversation %d", i),
		))
		if err != nil {
			t.Errorf("Expected nil, recieved %s", err.Error())
			return
		}

		twoUserCiphertext, err := key.AesEncrypt([]byte("false"))
		if err != nil {
			t.Errorf("Expected nil, recieved %s", err.Error())
			return
		}

		messageThread := Models.ConversationDetail{
			Name:    base64.StdEncoding.EncodeToString(nameCiphertext),
			TwoUser: base64.StdEncoding.EncodeToString(twoUserCiphertext),
		}

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

		conversationDetailIDCiphertext, err := key.AesEncrypt([]byte(messageThread.ID.String()))
		if err != nil {
			t.Errorf("Expected nil, recieved %s", err.Error())
			return
		}

		adminCiphertext, err := key.AesEncrypt([]byte("true"))
		if err != nil {
			t.Errorf("Expected nil, recieved %s", err.Error())
			return
		}

		pubKey := Seeder.GetPubKey()

		messageThreadUser := Models.UserConversation{
			UserID:               u.ID,
			ConversationDetailID: base64.StdEncoding.EncodeToString(conversationDetailIDCiphertext),
			Admin:                base64.StdEncoding.EncodeToString(adminCiphertext),
			SymmetricKey: base64.StdEncoding.EncodeToString(
				Seeder.EncryptWithPublicKey(key.Key, pubKey),
			),
		}

		err = Database.CreateUserConversation(&messageThreadUser)
	}

	req, _ := http.NewRequest("GET", ts.URL+"/api/v1/auth/conversations?page=0", nil)

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

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

	requestBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode)
		return
	}

	var conversations []Models.UserConversation

	json.Unmarshal(requestBody, &conversations)

	if len(conversations) != 20 {
		t.Errorf("Expected %d, recieved %d", 1, len(conversations))
	}
}
