package service

import (
	"context"
	"fmt"

	v1 "template-plus/api/v1"
	"template-plus/api/v1/apperrors"
	"template-plus/internal/repository"
)

type ButtonService interface {
	Page(ctx context.Context, pageInfo *v1.ButtonPageInfo) ([]v1.ButtonPageResponse, int64, error)
	ID(ctx context.Context, id int64) (*v1.SimpleButtonResponse, error)
	Create(ctx context.Context, request *v1.CreateButtonRequest) error
	Update(ctx context.Context, request *v1.UpdateButtonRequest) error
	Delete(ctx context.Context, id int64) error
}

func NewButtonService(
	service *Service,
	buttonRepo repository.ButtonRepository,
	roleButtonRepo repository.RoleButtonRepository,
) ButtonService {
	return &buttonService{
		buttonRepo:     buttonRepo,
		roleButtonRepo: roleButtonRepo,
		Service:        service,
	}
}

type buttonService struct {
	buttonRepo     repository.ButtonRepository
	roleButtonRepo repository.RoleButtonRepository
	*Service
}

func (b *buttonService) Page(ctx context.Context, pageInfo *v1.ButtonPageInfo) ([]v1.ButtonPageResponse, int64, error) {
	buttons, total, err := b.buttonRepo.SelectButtonsPage(ctx, pageInfo)
	if err != nil {
		return nil, 0, apperrors.NewInternalServerError(fmt.Sprintf("failed to list bbuttons (size: %d, offset: %d)", pageInfo.Size, pageInfo.Offset), err)
	}

	responses := make([]v1.ButtonPageResponse, len(buttons))
	for i, button := range buttons {
		responses[i] = v1.ButtonToFull(button)
	}
	return responses, total, nil
}

func (b *buttonService) ID(ctx context.Context, id int64) (*v1.SimpleButtonResponse, error) {
	button, err := b.buttonRepo.GetButtonByID(ctx, id)
	if err != nil {
		return nil, apperrors.NewInternalServerError(fmt.Sprintf("failed to retrieve button ID %d", id), err)
	}

	response := v1.ButtonToSimple(button)
	return &response, nil
}

func (b *buttonService) Create(ctx context.Context, request *v1.CreateButtonRequest) error {
	button := v1.CreateRequestToButton(request)

	if _, err := b.buttonRepo.InsertButton(ctx, button); err != nil {
		return apperrors.NewInternalServerError("failed to create button", err)
	}
	return nil
}

func (b *buttonService) Update(ctx context.Context, request *v1.UpdateButtonRequest) error {
	button := v1.UpdateRequestToButton(request)

	 rowsAffected, err := b.buttonRepo.UpdateButton(ctx, button)
	 if err != nil {
		return apperrors.NewInternalServerError(fmt.Sprintf("failed to update button with ID %d", button.ID), err)
	}
	affectedRows, err := rowsAffected.RowsAffected()
		if err != nil {
			return apperrors.NewInternalServerError(
				"failed to check rows affected after delete", err,
			)
		}
	if affectedRows <= 0 {
		return apperrors.NewNotFoundError(fmt.Sprintf("button ID %d not found", button.ID), nil)
	}
	return nil
}

func (b *buttonService) Delete(ctx context.Context, id int64) error {
	return b.tm.Transaction(ctx, func(ctx context.Context) error {
		if _, err := b.roleButtonRepo.DeleteRoleButtonByButtonID(ctx, id); err != nil {
			return apperrors.NewInternalServerError(fmt.Sprintf("failed to delete role button by button ID %d", id), err)
		}
		rowsResult, err := b.buttonRepo.DeleteButton(ctx, id)
		 if err != nil {
			return apperrors.NewInternalServerError(fmt.Sprintf("failed to delete button with ID %d", id), err)
		}
		affectedRows, err := rowsResult.RowsAffected()
		if err != nil {
			return apperrors.NewInternalServerError(
				"failed to check rows affected after delete", err,
			)
		}
		if affectedRows <= 0 {
			return apperrors.NewNotFoundError(fmt.Sprintf("resource ID %d not found", id), nil)
		}

		return nil
	})
}
please optimize the code and add comments