package service

import (
	"campaign-pool-be/app/database/entity"
	"campaign-pool-be/app/module/ebooks/mapper"
	"campaign-pool-be/app/module/ebooks/repository"
	"campaign-pool-be/app/module/ebooks/response"
	usersRepository "campaign-pool-be/app/module/users/repository"
	"campaign-pool-be/utils/paginator"
	utilSvc "campaign-pool-be/utils/service"
	"errors"
	"time"

	"github.com/rs/zerolog"
)

// EbookPurchasesService
type ebookPurchasesService struct {
	Repo       repository.EbookPurchasesRepository
	EbooksRepo repository.EbooksRepository
	Log        zerolog.Logger
	UsersRepo  usersRepository.UsersRepository
}

// EbookPurchasesService define interface of IEbookPurchasesService
type EbookPurchasesService interface {
	GetByBuyerId(authToken string, pagination *paginator.Pagination) (purchases []*response.EbookPurchaseResponse, paging paginator.Pagination, err error)
	PurchaseEbook(authToken string, ebookId uint, paymentMethod string) (purchase *response.EbookPurchaseResponse, err error)
	UpdatePaymentStatus(purchaseId uint, paymentStatus string, transactionId string, paymentProof string) (err error)
	GetPurchaseById(purchaseId uint) (purchase *response.EbookPurchaseResponse, err error)
	ConfirmPayment(purchaseId uint) (err error)
}

// NewEbookPurchasesService init EbookPurchasesService
func NewEbookPurchasesService(
	repo repository.EbookPurchasesRepository,
	ebooksRepo repository.EbooksRepository,
	log zerolog.Logger,
	usersRepo usersRepository.UsersRepository) EbookPurchasesService {

	return &ebookPurchasesService{
		Repo:       repo,
		EbooksRepo: ebooksRepo,
		Log:        log,
		UsersRepo:  usersRepo,
	}
}

// GetByBuyerId implement interface of EbookPurchasesService
func (_i *ebookPurchasesService) GetByBuyerId(authToken string, pagination *paginator.Pagination) (purchases []*response.EbookPurchaseResponse, paging paginator.Pagination, err error) {
	user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
	if user == nil {
		return nil, paginator.Pagination{}, errors.New("user not found")
	}

	purchasesData, paging, err := _i.Repo.GetByBuyerId(user.ID, pagination)
	if err != nil {
		return nil, paging, err
	}

	purchases = mapper.ToEbookPurchaseResponseList(purchasesData)

	return purchases, paging, nil
}

// PurchaseEbook implement interface of EbookPurchasesService
func (_i *ebookPurchasesService) PurchaseEbook(authToken string, ebookId uint, paymentMethod string) (purchase *response.EbookPurchaseResponse, err error) {
	user := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
	if user == nil {
		return nil, errors.New("user not found")
	}

	// Check if ebook exists
	ebook, err := _i.EbooksRepo.FindOne(ebookId)
	if err != nil {
		return nil, errors.New("ebook not found")
	}

	// Check if already purchased
	existingPurchase, err := _i.Repo.FindByBuyerAndEbook(user.ID, ebookId)
	if err == nil && existingPurchase != nil {
		return nil, errors.New("ebook already purchased")
	}

	// Create purchase record
	purchaseEntity := &entity.EbookPurchases{
		BuyerId:       user.ID,
		EbookId:       ebookId,
		PurchasePrice: ebook.Price,
		PaymentMethod: &paymentMethod,
		PaymentStatus: stringPtr("pending"),
		StatusId:      intPtr(1),
		IsActive:      boolPtr(true),
	}

	purchaseData, err := _i.Repo.Create(purchaseEntity)
	if err != nil {
		return nil, err
	}

	// Update purchase count
	err = _i.EbooksRepo.UpdatePurchaseCount(ebookId)
	if err != nil {
		_i.Log.Error().Err(err).Msg("Failed to update purchase count")
	}

	purchase = mapper.ToEbookPurchaseResponse(purchaseData)

	return purchase, nil
}

// UpdatePaymentStatus implement interface of EbookPurchasesService
func (_i *ebookPurchasesService) UpdatePaymentStatus(purchaseId uint, paymentStatus string, transactionId string, paymentProof string) (err error) {
	_, err = _i.Repo.FindOne(purchaseId)
	if err != nil {
		return errors.New("purchase not found")
	}

	updateData := &entity.EbookPurchases{
		PaymentStatus: &paymentStatus,
		TransactionId: &transactionId,
		PaymentProof:  &paymentProof,
	}

	if paymentStatus == "paid" {
		now := time.Now()
		updateData.PaymentDate = &now
	}

	err = _i.Repo.Update(purchaseId, updateData)
	if err != nil {
		return err
	}

	return nil
}

// GetPurchaseById implement interface of EbookPurchasesService
func (_i *ebookPurchasesService) GetPurchaseById(purchaseId uint) (purchase *response.EbookPurchaseResponse, err error) {
	purchaseData, err := _i.Repo.FindOne(purchaseId)
	if err != nil {
		return nil, err
	}

	purchase = mapper.ToEbookPurchaseResponse(purchaseData)

	return purchase, nil
}

// ConfirmPayment implement interface of EbookPurchasesService
func (_i *ebookPurchasesService) ConfirmPayment(purchaseId uint) (err error) {
	purchase, err := _i.Repo.FindOne(purchaseId)
	if err != nil {
		return errors.New("purchase not found")
	}

	if purchase.PaymentStatus == nil || *purchase.PaymentStatus != "paid" {
		return errors.New("payment not completed")
	}

	// Update status to confirmed
	updateData := &entity.EbookPurchases{
		StatusId: intPtr(2), // Assuming 2 is confirmed status
	}

	err = _i.Repo.Update(purchaseId, updateData)
	if err != nil {
		return err
	}

	return nil
}

// Helper functions
func stringPtr(s string) *string {
	return &s
}

func intPtr(i int) *int {
	return &i
}

func boolPtr(b bool) *bool {
	return &b
}
