package server

import (
	"context"
	"encoding/json"
	"io"
	"net/http"

	"github.com/stripe/stripe-go/v83"
	"github.com/stripe/stripe-go/v83/webhook"
)

type stripeEventService interface {
	HandlePaymentIntentSucceeded(ctx context.Context, pi *stripe.PaymentIntent) error
	HandleChargeRefunded(ctx context.Context, ch *stripe.Charge) error
}

var constructEvent = webhook.ConstructEvent

func handleStripeWebhook(bs stripeEventService, secret string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if secret == "" {
			http.Error(w, "stripe webhook secret not configured", http.StatusServiceUnavailable)
			return
		}

		payload, err := io.ReadAll(r.Body)
		if err != nil {
			http.Error(w, "unable to read request body", http.StatusBadRequest)
			return
		}

		sig := r.Header.Get("Stripe-Signature")
		if sig == "" {
			http.Error(w, "missing Stripe-Signature header", http.StatusBadRequest)
			return
		}

		event, err := constructEvent(payload, sig, secret)
		if err != nil {
			http.Error(w, "invalid webhook signature", http.StatusBadRequest)
			return
		}

		switch event.Type {
		case stripe.EventTypePaymentIntentSucceeded:
			var pi stripe.PaymentIntent
			if err := json.Unmarshal(event.Data.Raw, &pi); err != nil {
				http.Error(w, "invalid payment intent payload", http.StatusBadRequest)
				return
			}

			if err := bs.HandlePaymentIntentSucceeded(r.Context(), &pi); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case stripe.EventTypeChargeRefunded:
			var ch stripe.Charge
			if err := json.Unmarshal(event.Data.Raw, &ch); err != nil {
				http.Error(w, "invalid charge payload", http.StatusBadRequest)
				return
			}

			if err := bs.HandleChargeRefunded(r.Context(), &ch); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		default:
			// Acknowledge events we don't actively process.
		}

		w.WriteHeader(http.StatusOK)
	}
}
