package booking

import (
	"context"
	"errors"
	"fmt"
	"math"
	"strings"

	stripeclient "github.com/rjNemo/rentease/internal/driver/stripe"
)

// ErrBookingNotFound indicates that a booking could not be retrieved from the datastore.
var ErrBookingNotFound = errors.New("booking not found")

// ErrNoOutstandingBalance indicates that the booking has already been fully paid.
var ErrNoOutstandingBalance = errors.New("booking has no outstanding balance")

// CreateStripePaymentLink generates a Stripe payment link for the outstanding balance of a booking.
func (bs Service) CreateStripePaymentLink(ctx context.Context, bookingID int) (string, error) {
	if bs.stripe == nil {
		return "", ErrStripeClientNotConfigured
	}

	b := bs.store.Get(bookingID)
	if b == nil || b.ID == 0 {
		return "", ErrBookingNotFound
	}

	outstanding := calculateOutstandingBalance(b)
	if outstanding <= 0 {
		return "", ErrNoOutstandingBalance
	}

	description := fmt.Sprintf("Payment for booking %d", b.ID)
	if name := strings.TrimSpace(b.Name); name != "" {
		description = fmt.Sprintf("Payment for %s", name)
	}

	url, err := bs.stripe.CreatePaymentLink(ctx, stripeclient.CreatePaymentLinkParams{
		Amount:             outstanding,
		Currency:           "eur",
		BookingID:          uint(b.ID),
		Description:        description,
		PaymentMethodTypes: []string{"card", "sepa_debit"},
	})
	if err != nil {
		return "", err
	}

	return url, nil
}

func calculateOutstandingBalance(b *Booking) float64 {
	if b == nil {
		return 0
	}

	var total float64
	for _, item := range b.Items {
		total += item.Price * float64(item.Quantity)
	}

	var paid float64
	for _, payment := range b.Payments {
		paid += payment.Amount
	}

	outstanding := total - paid
	outstanding = math.Round(outstanding*100) / 100
	if outstanding < 0 {
		return 0
	}
	return outstanding
}
