package contribution

import (
	"context"
	"tercul/internal/app/authz"
	"tercul/internal/domain"
	platform_auth "tercul/internal/platform/auth"
)

// Commands contains the command handlers for the contribution aggregate.
type Commands struct {
	repo     domain.ContributionRepository
	authzSvc *authz.Service
}

// NewCommands creates a new Commands handler.
func NewCommands(repo domain.ContributionRepository, authzSvc *authz.Service) *Commands {
	return &Commands{
		repo:     repo,
		authzSvc: authzSvc,
	}
}

// CreateContributionInput represents the input for creating a new contribution.
type CreateContributionInput struct {
	Name          string
	Status        string
	WorkID        *uint
	TranslationID *uint
}

// CreateContribution creates a new contribution.
func (c *Commands) CreateContribution(ctx context.Context, input CreateContributionInput) (*domain.Contribution, error) {
	actorID, ok := platform_auth.GetUserIDFromContext(ctx)
	if !ok {
		return nil, domain.ErrUnauthorized
	}

	// TODO: Add authorization check using authzSvc if necessary

	contribution := &domain.Contribution{
		Name:          input.Name,
		Status:        input.Status,
		UserID:        actorID,
		WorkID:        input.WorkID,
		TranslationID: input.TranslationID,
	}

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

	return contribution, nil
}

// UpdateContributionInput represents the input for updating a contribution.
type UpdateContributionInput struct {
	ID     uint
	UserID uint
	Name   *string
	Status *string
}

// UpdateContribution updates an existing contribution.
func (c *Commands) UpdateContribution(ctx context.Context, input UpdateContributionInput) (*domain.Contribution, error) {
	contribution, err := c.repo.GetByID(ctx, input.ID)
	if err != nil {
		return nil, err
	}

	// Authorization check: only the user who created the contribution can update it.
	if contribution.UserID != input.UserID {
		return nil, domain.ErrForbidden
	}

	if input.Name != nil {
		contribution.Name = *input.Name
	}
	if input.Status != nil {
		contribution.Status = *input.Status
	}

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

	return contribution, nil
}

// DeleteContribution deletes a contribution.
func (c *Commands) DeleteContribution(ctx context.Context, contributionID uint, userID uint) error {
	contribution, err := c.repo.GetByID(ctx, contributionID)
	if err != nil {
		return err
	}

	// Authorization check: only the user who created the contribution can delete it.
	if contribution.UserID != userID {
		return domain.ErrForbidden
	}

	return c.repo.Delete(ctx, contributionID)
}

// ReviewContributionInput represents the input for reviewing a contribution.
type ReviewContributionInput struct {
	ID       uint
	Status   string
	Feedback *string
}

// ReviewContribution reviews a contribution, updating its status and adding feedback.
func (c *Commands) ReviewContribution(ctx context.Context, input ReviewContributionInput) (*domain.Contribution, error) {
	// Authorization check: for now, let's assume only admins/editors/reviewers can review.
	claims, ok := platform_auth.GetClaimsFromContext(ctx)
	if !ok {
		return nil, domain.ErrUnauthorized
	}
	if claims.Role != string(domain.UserRoleAdmin) && claims.Role != string(domain.UserRoleEditor) && claims.Role != string(domain.UserRoleReviewer) {
		return nil, domain.ErrForbidden
	}

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

	contribution.Status = input.Status
	// Note: The feedback handling is not fully implemented.
	// In a real application, this might create a new comment associated with the contribution.

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

	return contribution, nil
}