package models

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestAddOrUpdateBook(t *testing.T) {
	// Create test database
	assert.NoError(t, PrepareTestDatabase())

	// Create a new author for testing purposes
	testauthor1 := Author{Forename: "Testauthor wich", Lastname: "already exists"}
	testauthorin1, err := AddOrUpdateAuthor(testauthor1)
	assert.NoError(t, err)

	// Bootstrap our test book
	testbook := Book{
		Title:       "Test",
		Description: "Lorem Ipsum",
		Isbn:        "9999999999-999-99",
		Year:        2018,
		Price:       9.99,
		Status:      0,
		Quantity:    10,

		Publisher: Publisher{
			Name: "TestPublisherWhich does not exist",
		},

		Authors: []Author{
			{
				Forename: "Test1",
				Lastname: "Lorm",
			},
			{
				Forename: "Test3",
				Lastname: "Lorm",
			},
			{
				ID: testauthorin1.ID,
			},
		},
	}

	// Insert one new Testbook
	book1, err := AddOrUpdateBook(testbook)
	assert.NoError(t, err)

	// Check if everything was inserted correctly
	assert.Equal(t, testbook.Title, book1.Title)
	assert.Equal(t, testbook.Description, book1.Description)
	assert.Equal(t, testbook.Isbn, book1.Isbn)
	assert.Equal(t, testbook.Year, book1.Year)
	assert.Equal(t, testbook.Price, book1.Price)
	assert.Equal(t, testbook.Status, book1.Status)
	assert.Equal(t, testbook.Quantity, book1.Quantity)

	// Check if the publisher was inserted corectly
	_, exists, err := GetPublisherByID(book1.Publisher.ID)
	assert.NoError(t, err)
	assert.True(t, exists)

	// Check if the authors are there
	assert.Equal(t, book1.Authors[0].Forename, testbook.Authors[0].Forename)
	assert.Equal(t, book1.Authors[1].Forename, testbook.Authors[1].Forename)
	assert.Equal(t, book1.Authors[2].Forename, testauthor1.Forename)

	// And anotherone
	book2, err := AddOrUpdateBook(testbook)
	assert.NoError(t, err)
	assert.Equal(t, testbook.Title, book2.Title) // If this works, the rest should work too so we don't need to recheck everythin again

	// As of now, we should have 2 books in total. Get the list and check.
	allbooks, err := ListBooks("")
	assert.NoError(t, err)

	for _, book := range allbooks {
		assert.Equal(t, book.Title, testbook.Title)
	}

	// Search
	allbooks, err = ListBooks("est")
	assert.NoError(t, err)

	for _, book := range allbooks {
		assert.Equal(t, book.Title, testbook.Title)
	}

	// Get the new book
	gotBook, exists, err := GetBookByID(book1.ID)
	assert.NoError(t, err)
	assert.True(t, exists)
	assert.Equal(t, testbook.Title, gotBook.Title)

	// Pass an empty Book to see if it fails
	_, err = AddOrUpdateBook(Book{})
	assert.Error(t, err)
	assert.True(t, IsErrBookTitleCannotBeEmpty(err))

	// Update the book
	testbook.ID = book1.ID
	testbook.Title = "LormIspmus"
	book1updated, err := AddOrUpdateBook(testbook)
	assert.NoError(t, err)
	assert.Equal(t, testbook.Title, book1updated.Title)

	// Get the authors for that book
	authorsbybook, err := GetAuthorsByBook(book1)
	assert.NoError(t, err)

	// Check if they are the right ones
	// Yes I know, this is not a good way to do this. But as we get additional information when selecting from the database
	// (ID, Created, Updated), this would fail if we'd just directly compared authorsbybook and testbook.Authors
	assert.Equal(t, len(authorsbybook), len(testbook.Authors))

	// Test Quantity
	qty1, err := book1.getQuantity()
	assert.NoError(t, err)
	assert.Equal(t, book1.Quantity, qty1)

	// Update the quantity and check again
	err = book1.setQuantity(int64(99))
	assert.NoError(t, err)

	qty2, err := book1.getQuantity()
	assert.NoError(t, err)
	assert.Equal(t, int64(99), qty2)

	// Delete the book
	err = DeleteBookByID(book1.ID)
	assert.NoError(t, err)

	// Check if its gone
	_, exists, err = GetBookByID(book1.ID)
	assert.NoError(t, err)
	assert.False(t, exists)

	// Try deleting one with ID = 0
	err = DeleteBookByID(0)
	assert.Error(t, err)
	assert.True(t, IsErrIDCannotBeZero(err))
}
