package handlers import ( "errors" "net/http" "github.com/gin-gonic/gin" "github.com/treytartt/casera-api/internal/middleware" "github.com/treytartt/casera-api/internal/models" "github.com/treytartt/casera-api/internal/services" ) // SubscriptionHandler handles subscription-related HTTP requests type SubscriptionHandler struct { subscriptionService *services.SubscriptionService } // NewSubscriptionHandler creates a new subscription handler func NewSubscriptionHandler(subscriptionService *services.SubscriptionService) *SubscriptionHandler { return &SubscriptionHandler{subscriptionService: subscriptionService} } // GetSubscription handles GET /api/subscription/ func (h *SubscriptionHandler) GetSubscription(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) subscription, err := h.subscriptionService.GetSubscription(user.ID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, subscription) } // GetSubscriptionStatus handles GET /api/subscription/status/ func (h *SubscriptionHandler) GetSubscriptionStatus(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) status, err := h.subscriptionService.GetSubscriptionStatus(user.ID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, status) } // GetUpgradeTrigger handles GET /api/subscription/upgrade-trigger/:key/ func (h *SubscriptionHandler) GetUpgradeTrigger(c *gin.Context) { key := c.Param("key") trigger, err := h.subscriptionService.GetUpgradeTrigger(key) if err != nil { if errors.Is(err, services.ErrUpgradeTriggerNotFound) { c.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, trigger) } // GetAllUpgradeTriggers handles GET /api/subscription/upgrade-triggers/ func (h *SubscriptionHandler) GetAllUpgradeTriggers(c *gin.Context) { triggers, err := h.subscriptionService.GetAllUpgradeTriggers() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, triggers) } // GetFeatureBenefits handles GET /api/subscription/features/ func (h *SubscriptionHandler) GetFeatureBenefits(c *gin.Context) { benefits, err := h.subscriptionService.GetFeatureBenefits() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, benefits) } // GetPromotions handles GET /api/subscription/promotions/ func (h *SubscriptionHandler) GetPromotions(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) promotions, err := h.subscriptionService.GetActivePromotions(user.ID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, promotions) } // ProcessPurchase handles POST /api/subscription/purchase/ func (h *SubscriptionHandler) ProcessPurchase(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) var req services.ProcessPurchaseRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } var subscription *services.SubscriptionResponse var err error switch req.Platform { case "ios": if req.ReceiptData == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "receipt_data is required for iOS"}) return } subscription, err = h.subscriptionService.ProcessApplePurchase(user.ID, req.ReceiptData) case "android": if req.PurchaseToken == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "purchase_token is required for Android"}) return } subscription, err = h.subscriptionService.ProcessGooglePurchase(user.ID, req.PurchaseToken) } if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "message": "Subscription upgraded successfully", "subscription": subscription, }) } // CancelSubscription handles POST /api/subscription/cancel/ func (h *SubscriptionHandler) CancelSubscription(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) subscription, err := h.subscriptionService.CancelSubscription(user.ID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "message": "Subscription cancelled. You will retain Pro benefits until the end of your billing period.", "subscription": subscription, }) } // RestoreSubscription handles POST /api/subscription/restore/ func (h *SubscriptionHandler) RestoreSubscription(c *gin.Context) { user := c.MustGet(middleware.AuthUserKey).(*models.User) var req services.ProcessPurchaseRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // Same logic as ProcessPurchase - validates receipt/token and restores var subscription *services.SubscriptionResponse var err error switch req.Platform { case "ios": subscription, err = h.subscriptionService.ProcessApplePurchase(user.ID, req.ReceiptData) case "android": subscription, err = h.subscriptionService.ProcessGooglePurchase(user.ID, req.PurchaseToken) } if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "message": "Subscription restored successfully", "subscription": subscription, }) }