package graphql_test

import (
	"context"
	"os"
	"tercul/internal/adapters/graphql"
	"tercul/internal/adapters/graphql/model"
	"tercul/internal/app/auth"
	"tercul/internal/domain"
	platform_auth "tercul/internal/platform/auth"
	"tercul/internal/testutil"
	"testing"

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

type BookResolversTestSuite struct {
	testutil.IntegrationTestSuite
	queryResolver    graphql.QueryResolver
	mutationResolver graphql.MutationResolver
}

func TestBookResolvers(t *testing.T) {
	suite.Run(t, new(BookResolversTestSuite))
}

func (s *BookResolversTestSuite) SetupSuite() {
	s.IntegrationTestSuite.SetupSuite(&testutil.TestConfig{
		DBPath: "book_resolvers_test.db",
	})
}

func (s *BookResolversTestSuite) TearDownSuite() {
	s.IntegrationTestSuite.TearDownSuite()
	_ = os.Remove("book_resolvers_test.db")
}

func (s *BookResolversTestSuite) SetupTest() {
	s.IntegrationTestSuite.SetupTest()
	resolver := &graphql.Resolver{App: s.App}
	s.queryResolver = resolver.Query()
	s.mutationResolver = resolver.Mutation()
}

// Helper to create a user for tests
func (s *BookResolversTestSuite) createUser(username, email, password string, role domain.UserRole) *domain.User {
	resp, err := s.App.Auth.Commands.Register(context.Background(), auth.RegisterInput{
		Username: username,
		Email:    email,
		Password: password,
	})
	s.Require().NoError(err)

	user, err := s.App.User.Queries.User(context.Background(), resp.User.ID)
	s.Require().NoError(err)

	if role != user.Role {
		user.Role = role
		err = s.DB.Save(user).Error
		s.Require().NoError(err)
	}
	return user
}

// Helper to create a context with JWT claims
func (s *BookResolversTestSuite) contextWithClaims(user *domain.User) context.Context {
	return testutil.ContextWithClaims(context.Background(), &platform_auth.Claims{
		UserID: user.ID,
		Role:   string(user.Role),
	})
}

func (s *BookResolversTestSuite) TestCreateBook() {
	user := s.createUser("book-creator", "book-creator@test.com", "password", domain.UserRoleContributor)
	ctx := s.contextWithClaims(user)

	s.Run("Success", func() {
		// Arrange
		description := "A test book description."
		isbn := "978-0321765723"
		input := model.BookInput{
			Name:        "My First Book",
			Language:    "en",
			Description: &description,
			Isbn:        &isbn,
		}

		// Act
		book, err := s.mutationResolver.CreateBook(ctx, input)

		// Assert
		s.Require().NoError(err)
		s.Require().NotNil(book)
		s.Equal("My First Book", book.Name)
		s.Equal("en", book.Language)
		s.Equal(description, *book.Description)
		s.Equal(isbn, *book.Isbn)
	})
}

func (s *BookResolversTestSuite) TestUpdateBook() {
	user := s.createUser("book-updater", "book-updater@test.com", "password", domain.UserRoleContributor)
	ctx := s.contextWithClaims(user)

	// Create a book to update
	description := "Initial description"
	isbn := "978-1491904244"
	createInput := model.BookInput{
		Name:        "Updatable Book",
		Language:    "en",
		Description: &description,
		Isbn:        &isbn,
	}
	createdBook, err := s.mutationResolver.CreateBook(ctx, createInput)
	s.Require().NoError(err)

	s.Run("Success", func() {
		// Arrange
		updatedDescription := "Updated description"
		updateInput := model.BookInput{
			Name:        "Updated Book Title",
			Language:    "en",
			Description: &updatedDescription,
			Isbn:        &isbn,
		}

		// Act
		updatedBook, err := s.mutationResolver.UpdateBook(s.AdminCtx, createdBook.ID, updateInput)

		// Assert
		s.Require().NoError(err)
		s.Require().NotNil(updatedBook)
		s.Equal("Updated Book Title", updatedBook.Name)
		s.Equal(updatedDescription, *updatedBook.Description)
	})
}

func (s *BookResolversTestSuite) TestDeleteBook() {
	user := s.createUser("book-deletor", "book-deletor@test.com", "password", domain.UserRoleContributor)
	ctx := s.contextWithClaims(user)

	// Create a book to delete
	description := "Deletable description"
	isbn := "978-1491904245"
	createInput := model.BookInput{
		Name:        "Deletable Book",
		Language:    "en",
		Description: &description,
		Isbn:        &isbn,
	}
	createdBook, err := s.mutationResolver.CreateBook(ctx, createInput)
	s.Require().NoError(err)

	s.Run("Success", func() {
		// Act
		ok, err := s.mutationResolver.DeleteBook(s.AdminCtx, createdBook.ID)

		// Assert
		s.Require().NoError(err)
		s.True(ok)
	})
}

func (s *BookResolversTestSuite) TestBookQueries() {
	user := s.createUser("book-reader", "book-reader@test.com", "password", domain.UserRoleReader)
	ctx := s.contextWithClaims(user)

	// Create a book to query
	description := "Queryable description"
	isbn := "978-1491904246"
	createInput := model.BookInput{
		Name:        "Queryable Book",
		Language:    "en",
		Description: &description,
		Isbn:        &isbn,
	}
	createdBook, err := s.mutationResolver.CreateBook(ctx, createInput)
	s.Require().NoError(err)

	s.Run("Get Book by ID", func() {
		// Act
		book, err := s.queryResolver.Book(ctx, createdBook.ID)

		// Assert
		s.Require().NoError(err)
		s.Require().NotNil(book)
		s.Equal("Queryable Book", book.Name)
	})

	s.Run("List Books", func() {
		// Act
		books, err := s.queryResolver.Books(ctx, nil, nil)

		// Assert
		s.Require().NoError(err)
		s.Require().NotNil(books)
		s.True(len(books) >= 1)
	})
}
