package api

import (
	"context"
	"github.com/stretchr/testify/assert"
	"go-nkode/internal/email"
	"go-nkode/internal/entities"
	"go-nkode/internal/models"
	"go-nkode/internal/repository"
	"go-nkode/internal/security"
	sqlite_queue "go-nkode/internal/sqlc"
	"log"
	"os"
	"testing"
)

func TestNKodeAPI(t *testing.T) {
	//db1 := NewInMemoryDb()
	//testNKodeAPI(t, &db1)

	dbPath := os.Getenv("TEST_DB")
	ctx := context.Background()
	sqliteDb, err := sqlite_queue.OpenSqliteDb(dbPath)
	assert.NoError(t, err)

	queue, err := sqlite_queue.NewQueue(ctx, sqliteDb)
	assert.NoError(t, err)
	queue.Start()
	defer func(queue *sqlite_queue.Queue) {
		if err := queue.Stop(); err != nil {
			log.Fatal(err)
		}
	}(queue)
	sqlitedb := repository.NewSqliteRepository(ctx, queue)
	testNKodeAPI(t, &sqlitedb)

	//if _, err := os.Stat(dbPath); err == nil {
	//	err = os.Remove(dbPath)
	//	assert.NoError(t, err)
	//} else {
	//	assert.NoError(t, err)
	//}
}

func testNKodeAPI(t *testing.T, db repository.CustomerUserRepository) {
	bufferSize := 100
	emailsPerSec := 14
	testClient := email.TestEmailClient{}
	queue := email.NewEmailQueue(bufferSize, emailsPerSec, &testClient)
	queue.Start()
	defer queue.Stop()
	attrsPerKey := 5
	numbOfKeys := 4
	for idx := 0; idx < 1; idx++ {
		userEmail := models.UserEmail("test_username" + security.GenerateRandomString(12) + "@example.com")
		passcodeLen := 4
		nkodePolicy := models.NewDefaultNKodePolicy()
		keypadSize := entities.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
		nkodeApi := NewNKodeAPI(db, queue)
		customerId, err := nkodeApi.CreateNewCustomer(nkodePolicy, nil)
		assert.NoError(t, err)
		signupResponse, err := nkodeApi.GenerateSignupResetInterface(userEmail, *customerId, keypadSize, false)
		assert.NoError(t, err)
		setInterface := signupResponse.UserIdxInterface
		sessionIdStr := signupResponse.SessionId
		sessionId, err := models.SessionIdFromString(sessionIdStr)
		assert.NoError(t, err)
		keypadSize = entities.KeypadDimension{AttrsPerKey: numbOfKeys, NumbOfKeys: numbOfKeys}
		userPasscode := setInterface[:passcodeLen]
		setKeySelect, err := entities.SelectKeyByAttrIdx(setInterface, userPasscode, keypadSize)
		assert.NoError(t, err)
		confirmInterface, err := nkodeApi.SetNKode(*customerId, sessionId, setKeySelect)
		assert.NoError(t, err)
		confirmKeySelect, err := entities.SelectKeyByAttrIdx(confirmInterface, userPasscode, keypadSize)
		err = nkodeApi.ConfirmNKode(*customerId, sessionId, confirmKeySelect)
		assert.NoError(t, err)

		keypadSize = entities.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
		loginInterface, err := nkodeApi.GetLoginInterface(userEmail, *customerId)
		assert.NoError(t, err)
		loginKeySelection, err := entities.SelectKeyByAttrIdx(loginInterface.UserIdxInterface, userPasscode, keypadSize)
		assert.NoError(t, err)
		_, err = nkodeApi.Login(*customerId, userEmail, loginKeySelection)
		assert.NoError(t, err)

		err = nkodeApi.RenewAttributes(*customerId)
		assert.NoError(t, err)

		loginInterface, err = nkodeApi.GetLoginInterface(userEmail, *customerId)
		assert.NoError(t, err)
		loginKeySelection, err = entities.SelectKeyByAttrIdx(loginInterface.UserIdxInterface, userPasscode, keypadSize)
		assert.NoError(t, err)
		_, err = nkodeApi.Login(*customerId, userEmail, loginKeySelection)
		assert.NoError(t, err)

		/// Reset nKode
		attrsPerKey = 6
		keypadSize = entities.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
		resetResponse, err := nkodeApi.GenerateSignupResetInterface(userEmail, *customerId, keypadSize, true)
		assert.NoError(t, err)
		setInterface = resetResponse.UserIdxInterface
		sessionIdStr = resetResponse.SessionId
		sessionId, err = models.SessionIdFromString(sessionIdStr)
		assert.NoError(t, err)
		keypadSize = entities.KeypadDimension{AttrsPerKey: numbOfKeys, NumbOfKeys: numbOfKeys}
		userPasscode = setInterface[:passcodeLen]
		setKeySelect, err = entities.SelectKeyByAttrIdx(setInterface, userPasscode, keypadSize)
		assert.NoError(t, err)
		confirmInterface, err = nkodeApi.SetNKode(*customerId, sessionId, setKeySelect)
		assert.NoError(t, err)
		confirmKeySelect, err = entities.SelectKeyByAttrIdx(confirmInterface, userPasscode, keypadSize)
		err = nkodeApi.ConfirmNKode(*customerId, sessionId, confirmKeySelect)
		assert.NoError(t, err)

		keypadSize = entities.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
		loginInterface2, err := nkodeApi.GetLoginInterface(userEmail, *customerId)
		assert.NoError(t, err)
		loginKeySelection, err = entities.SelectKeyByAttrIdx(loginInterface2.UserIdxInterface, userPasscode, keypadSize)
		assert.NoError(t, err)
		_, err = nkodeApi.Login(*customerId, userEmail, loginKeySelection)
		assert.NoError(t, err)
		signupResponse, err = nkodeApi.GenerateSignupResetInterface(userEmail, *customerId, keypadSize, false)
		assert.Error(t, err)
	}
}
