package book

import (
	"context"
	"tercul/internal/app/authz"
	"tercul/internal/domain"
)

// BookCommands contains the command handlers for the book aggregate.
type BookCommands struct {
	repo     domain.BookRepository
	authzSvc *authz.Service
}

// NewBookCommands creates a new BookCommands handler.
func NewBookCommands(repo domain.BookRepository, authzSvc *authz.Service) *BookCommands {
	return &BookCommands{
		repo:     repo,
		authzSvc: authzSvc,
	}
}

// CreateBookInput represents the input for creating a new book.
type CreateBookInput struct {
	Title       string
	Description string
	Language    string
	ISBN        *string
	AuthorIDs   []uint
}

// CreateBook creates a new book.
func (c *BookCommands) CreateBook(ctx context.Context, input CreateBookInput) (*domain.Book, error) {
	can, err := c.authzSvc.CanCreateBook(ctx)
	if err != nil {
		return nil, err
	}
	if !can {
		return nil, domain.ErrForbidden
	}

	book := &domain.Book{
		Title:       input.Title,
		Description: input.Description,
		TranslatableModel: domain.TranslatableModel{
			Language: input.Language,
		},
	}
	if input.ISBN != nil {
		book.ISBN = *input.ISBN
	}

	// In a real implementation, we would associate the authors here.
	// for _, authorID := range input.AuthorIDs { ... }

	err = c.repo.Create(ctx, book)
	if err != nil {
		return nil, err
	}
	return book, nil
}

// UpdateBookInput represents the input for updating an existing book.
type UpdateBookInput struct {
	ID          uint
	Title       *string
	Description *string
	Language    *string
	ISBN        *string
	AuthorIDs   []uint
}

// UpdateBook updates an existing book.
func (c *BookCommands) UpdateBook(ctx context.Context, input UpdateBookInput) (*domain.Book, error) {
	can, err := c.authzSvc.CanUpdateBook(ctx)
	if err != nil {
		return nil, err
	}
	if !can {
		return nil, domain.ErrForbidden
	}

	book, err := c.repo.GetByID(ctx, input.ID)
	if err != nil {
		return nil, err
	}

	if input.Title != nil {
		book.Title = *input.Title
	}
	if input.Description != nil {
		book.Description = *input.Description
	}
	if input.Language != nil {
		book.Language = *input.Language
	}
	if input.ISBN != nil {
		book.ISBN = *input.ISBN
	}

	err = c.repo.Update(ctx, book)
	if err != nil {
		return nil, err
	}
	return book, nil
}

// DeleteBook deletes a book by ID.
func (c *BookCommands) DeleteBook(ctx context.Context, id uint) error {
	can, err := c.authzSvc.CanDeleteBook(ctx)
	if err != nil {
		return err
	}
	if !can {
		return domain.ErrForbidden
	}
	return c.repo.Delete(ctx, id)
}