package sql_test

import (
	"context"
	"testing"
	"tercul/internal/data/sql"
	"tercul/internal/domain"
	"tercul/internal/platform/config"
	"tercul/internal/testutil"

	"github.com/stretchr/testify/suite"
)

type AuthorRepositoryTestSuite struct {
	testutil.IntegrationTestSuite
	AuthorRepo domain.AuthorRepository
}

func (s *AuthorRepositoryTestSuite) SetupSuite() {
	s.IntegrationTestSuite.SetupSuite(testutil.DefaultTestConfig())
	cfg, err := config.LoadConfig()
	s.Require().NoError(err)
	s.AuthorRepo = sql.NewAuthorRepository(s.DB, cfg)
}

func (s *AuthorRepositoryTestSuite) SetupTest() {
	s.IntegrationTestSuite.SetupTest()
	s.DB.Exec("DELETE FROM work_authors")
	s.DB.Exec("DELETE FROM authors")
	s.DB.Exec("DELETE FROM works")
	s.DB.Exec("DELETE FROM books")
	s.DB.Exec("DELETE FROM book_authors")
	s.DB.Exec("DELETE FROM countries")
	s.DB.Exec("DELETE FROM translations")
}

func (s *AuthorRepositoryTestSuite) createAuthor(name string) *domain.Author {
	author := &domain.Author{
		Name: name,
		TranslatableModel: domain.TranslatableModel{
			Language: "en",
		},
	}
	err := s.AuthorRepo.Create(context.Background(), author)
	s.Require().NoError(err)
	return author
}

func (s *AuthorRepositoryTestSuite) createBook(title string) *domain.Book {
	book := &domain.Book{Title: title, TranslatableModel: domain.TranslatableModel{Language: "en"}}
	err := s.DB.Create(book).Error
	s.Require().NoError(err)
	return book
}

func (s *AuthorRepositoryTestSuite) TestListByWorkID() {
	s.Run("should return all authors for a given work", func() {
		// Arrange
		work := s.CreateTestWork(s.AdminCtx, "Test Work", "en", "Test content")
		author1 := s.createAuthor("Author 1")
		author2 := s.createAuthor("Author 2")
		s.Require().NoError(s.DB.Model(&work).Association("Authors").Append([]*domain.Author{author1, author2}))

		// Act
		authors, err := s.AuthorRepo.ListByWorkID(context.Background(), work.ID)

		// Assert
		s.Require().NoError(err)
		s.Len(authors, 3)
		var authorNames []string
		for _, a := range authors {
			authorNames = append(authorNames, a.Name)
		}
		s.ElementsMatch([]string{"admin", "Author 1", "Author 2"}, authorNames)
	})
}

func (s *AuthorRepositoryTestSuite) TestListByBookID() {
	s.Run("should return all authors for a given book", func() {
		// Arrange
		book := s.createBook("Test Book")
		author1 := s.createAuthor("Book Author 1")
		author2 := s.createAuthor("Book Author 2")
		s.Require().NoError(s.DB.Model(&book).Association("Authors").Append([]*domain.Author{author1, author2}))

		// Act
		authors, err := s.AuthorRepo.ListByBookID(context.Background(), book.ID)

		// Assert
		s.Require().NoError(err)
		s.Len(authors, 2)
		s.ElementsMatch([]string{"Book Author 1", "Book Author 2"}, []string{authors[0].Name, authors[1].Name})
	})
}

func (s *AuthorRepositoryTestSuite) TestListByCountryID() {
	s.Run("should return all authors for a given country", func() {
		// Arrange
		country1 := &domain.Country{Name: "Country 1", Code: "C1"}
		country2 := &domain.Country{Name: "Country 2", Code: "C2"}
		s.Require().NoError(s.DB.Create(country1).Error)
		s.Require().NoError(s.DB.Create(country2).Error)

		author1 := s.createAuthor("Author C1")
		author1.CountryID = &country1.ID
		s.Require().NoError(s.DB.Save(author1).Error)

		author2 := s.createAuthor("Author C2")
		author2.CountryID = &country2.ID
		s.Require().NoError(s.DB.Save(author2).Error)

		// Act
		authors, err := s.AuthorRepo.ListByCountryID(context.Background(), country1.ID)

		// Assert
		s.Require().NoError(err)
		s.Len(authors, 1)
		s.Equal("Author C1", authors[0].Name)
	})
}

func (s *AuthorRepositoryTestSuite) TestGetWithTranslations() {
	s.Run("should return author with preloaded translations", func() {
		// Arrange
		author := s.createAuthor("Translated Author")
		translation := &domain.Translation{
			TranslatableType: "authors",
			TranslatableID:   author.ID,
			Language:         "es",
			Title:            "Autor Traducido",
			Content:          "Una biografía.",
		}
		s.Require().NoError(s.DB.Create(translation).Error)

		// Act
		foundAuthor, err := s.AuthorRepo.GetWithTranslations(context.Background(), author.ID)

		// Assert
		s.Require().NoError(err)
		s.Require().NotNil(foundAuthor)
		s.Require().Len(foundAuthor.Translations, 1)
		s.Equal("es", foundAuthor.Translations[0].Language)
		s.Equal("Una biografía.", foundAuthor.Translations[0].Content)
	})
}

func TestAuthorRepository(t *testing.T) {
	suite.Run(t, new(AuthorRepositoryTestSuite))
}