package repository

import (
	"context"
	"time"

	"apskel-pos-be/internal/entities"

	"github.com/google/uuid"
	"gorm.io/gorm"
)

type PaymentRepository interface {
	Create(ctx context.Context, payment *entities.Payment) error
	GetByID(ctx context.Context, id uuid.UUID) (*entities.Payment, error)
	GetByOrderID(ctx context.Context, orderID uuid.UUID) ([]*entities.Payment, error)
	Update(ctx context.Context, payment *entities.Payment) error
	Delete(ctx context.Context, id uuid.UUID) error
	RefundPayment(ctx context.Context, id uuid.UUID, refundAmount float64, reason string, refundedBy uuid.UUID) error
	UpdateStatus(ctx context.Context, id uuid.UUID, status entities.PaymentTransactionStatus) error
	GetTotalPaidByOrderID(ctx context.Context, orderID uuid.UUID) (float64, error)
}

type PaymentRepositoryImpl struct {
	db *gorm.DB
}

func NewPaymentRepositoryImpl(db *gorm.DB) *PaymentRepositoryImpl {
	return &PaymentRepositoryImpl{
		db: db,
	}
}

func (r *PaymentRepositoryImpl) Create(ctx context.Context, payment *entities.Payment) error {
	return r.db.WithContext(ctx).Create(payment).Error
}

func (r *PaymentRepositoryImpl) GetByID(ctx context.Context, id uuid.UUID) (*entities.Payment, error) {
	var payment entities.Payment
	err := r.db.WithContext(ctx).
		Preload("PaymentMethod").
		Preload("PaymentOrderItems").
		First(&payment, "id = ?", id).Error
	if err != nil {
		return nil, err
	}
	return &payment, nil
}

func (r *PaymentRepositoryImpl) GetByOrderID(ctx context.Context, orderID uuid.UUID) ([]*entities.Payment, error) {
	var payments []*entities.Payment
	err := r.db.WithContext(ctx).
		Preload("PaymentMethod").
		Preload("PaymentOrderItems").
		Where("order_id = ?", orderID).
		Find(&payments).Error
	return payments, err
}

func (r *PaymentRepositoryImpl) Update(ctx context.Context, payment *entities.Payment) error {
	return r.db.WithContext(ctx).Save(payment).Error
}

func (r *PaymentRepositoryImpl) Delete(ctx context.Context, id uuid.UUID) error {
	return r.db.WithContext(ctx).Delete(&entities.Payment{}, "id = ?", id).Error
}

func (r *PaymentRepositoryImpl) RefundPayment(ctx context.Context, id uuid.UUID, refundAmount float64, reason string, refundedBy uuid.UUID) error {
	now := time.Now()
	return r.db.WithContext(ctx).Model(&entities.Payment{}).
		Where("id = ?", id).
		Updates(map[string]interface{}{
			"refund_amount": refundAmount,
			"refund_reason": reason,
			"refunded_at":   now,
			"refunded_by":   refundedBy,
			"status":        entities.PaymentTransactionStatusRefunded,
		}).Error
}

func (r *PaymentRepositoryImpl) UpdateStatus(ctx context.Context, id uuid.UUID, status entities.PaymentTransactionStatus) error {
	return r.db.WithContext(ctx).Model(&entities.Payment{}).
		Where("id = ?", id).
		Update("status", status).Error
}

func (r *PaymentRepositoryImpl) GetTotalPaidByOrderID(ctx context.Context, orderID uuid.UUID) (float64, error) {
	var total float64
	err := r.db.WithContext(ctx).Model(&entities.Payment{}).
		Where("order_id = ? AND status = ?", orderID, entities.PaymentTransactionStatusCompleted).
		Select("COALESCE(SUM(amount), 0)").
		Scan(&total).Error
	return total, err
}
