package booking

import (
	"context"
	"errors"
	"log/slog"
	"strings"
	"time"

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

// ErrStripeClientNotConfigured indicates the service was asked to run a Stripe operation without a configured client.
var ErrStripeClientNotConfigured = errors.New("stripe client not configured")

// SyncStripePayments pulls Stripe payments within the provided time window and
// upserts them into the local datastore. Payments lacking booking metadata are
// skipped to avoid incorrect associations.
func (bs Service) SyncStripePayments(ctx context.Context, from, to time.Time) error {
	if bs.stripe == nil {
		return ErrStripeClientNotConfigured
	}

	payments, err := bs.stripe.ListPayments(ctx, stripeclient.ListPaymentsParams{From: from, To: to})
	if err != nil {
		return err
	}

	var multi error
	for _, payment := range payments {
		if payment.BookingID == nil {
			bs.logger.Warn("stripe payment missing booking metadata", slog.String("payment_id", payment.ID))
			continue
		}

		bookingID := uint(*payment.BookingID)
		stripeID := payment.ID
		status := strings.ToLower(payment.Status)

		_, err = bs.store.UpsertStripePayment(&Payment{
			BookingID:       bookingID,
			Amount:          payment.Amount,
			PaymentMethod:   mapStripeMethod(payment.PaymentMethod),
			StripePaymentID: &stripeID,
			StripeStatus:    &status,
		})
		if err != nil {
			multi = errors.Join(multi, err)
			bs.logger.Error("failed to upsert stripe payment", slog.String("payment_id", payment.ID), slog.Any("error", err))
		}
	}

	return multi
}

func mapStripeMethod(method string) config.PaymentMethod {
	switch strings.ToLower(method) {
	case "card", "link", "apple_pay", "google_pay", "cashapp":
		return config.PaymentMethod("Card")
	case "ach_credit_transfer", "ach_debit", "us_bank_account", "sepa_debit", "bank_transfer", "blik", "bancontact":
		return config.PaymentMethod("Transfer")
	case "cash":
		return config.PaymentMethod("Cash")
	case "check":
		return config.PaymentMethod("Cheque")
	default:
		return config.PaymentMethod("Card")
	}
}
