package services

import (
	"context"
	"errors"
	"time"

	"github.com/rs/zerolog/log"
	"gorm.io/gorm"

	"github.com/treytartt/honeydue-api/internal/apperrors"
	"github.com/treytartt/honeydue-api/internal/config"
	"github.com/treytartt/honeydue-api/internal/models"
	"github.com/treytartt/honeydue-api/internal/repositories"
)

// Subscription-related errors
var (
	// Deprecated: Use apperrors.NotFound("error.subscription_not_found") instead
	ErrSubscriptionNotFound     = errors.New("subscription not found")
	// Deprecated: Use apperrors.Forbidden("error.properties_limit_exceeded") instead
	ErrPropertiesLimitExceeded  = errors.New("properties limit exceeded for your subscription tier")
	// Deprecated: Use apperrors.Forbidden("error.tasks_limit_exceeded") instead
	ErrTasksLimitExceeded       = errors.New("tasks limit exceeded for your subscription tier")
	// Deprecated: Use apperrors.Forbidden("error.contractors_limit_exceeded") instead
	ErrContractorsLimitExceeded = errors.New("contractors limit exceeded for your subscription tier")
	// Deprecated: Use apperrors.Forbidden("error.documents_limit_exceeded") instead
	ErrDocumentsLimitExceeded   = errors.New("documents limit exceeded for your subscription tier")
	// Deprecated: Use apperrors.NotFound("error.upgrade_trigger_not_found") instead
	ErrUpgradeTriggerNotFound   = errors.New("upgrade trigger not found")
	// Deprecated: Use apperrors.NotFound("error.promotion_not_found") instead
	ErrPromotionNotFound        = errors.New("promotion not found")
)

// KnownSubscriptionIDs are the product IDs for Pro subscriptions
// Update these to match your actual App Store Connect / Google Play Console product IDs
var KnownSubscriptionIDs = []string{
	"com.tt.honeyDue.pro.monthly",
	"com.tt.honeyDue.pro.yearly",
	"honeydue_pro_monthly",
	"honeydue_pro_yearly",
}

// SubscriptionService handles subscription business logic
type SubscriptionService struct {
	subscriptionRepo *repositories.SubscriptionRepository
	residenceRepo    *repositories.ResidenceRepository
	taskRepo         *repositories.TaskRepository
	contractorRepo   *repositories.ContractorRepository
	documentRepo     *repositories.DocumentRepository
	appleClient      *AppleIAPClient
	googleClient     *GoogleIAPClient
}

// NewSubscriptionService creates a new subscription service
func NewSubscriptionService(
	subscriptionRepo *repositories.SubscriptionRepository,
	residenceRepo *repositories.ResidenceRepository,
	taskRepo *repositories.TaskRepository,
	contractorRepo *repositories.ContractorRepository,
	documentRepo *repositories.DocumentRepository,
) *SubscriptionService {
	svc := &SubscriptionService{
		subscriptionRepo: subscriptionRepo,
		residenceRepo:    residenceRepo,
		taskRepo:         taskRepo,
		contractorRepo:   contractorRepo,
		documentRepo:     documentRepo,
	}

	// Initialize Apple IAP client
	cfg := config.Get()
	if cfg != nil {
		appleClient, err := NewAppleIAPClient(cfg.AppleIAP)
		if err != nil {
			if !errors.Is(err, ErrIAPNotConfigured) {
				log.Warn().Err(err).Msg("Failed to initialize Apple IAP client")
			}
		} else {
			svc.appleClient = appleClient
			log.Info().Msg("Apple IAP validation client initialized")
		}

		// Initialize Google IAP client
		ctx := context.Background()
		googleClient, err := NewGoogleIAPClient(ctx, cfg.GoogleIAP)
		if err != nil {
			if !errors.Is(err, ErrIAPNotConfigured) {
				log.Warn().Err(err).Msg("Failed to initialize Google IAP client")
			}
		} else {
			svc.googleClient = googleClient
			log.Info().Msg("Google IAP validation client initialized")
		}
	}

	return svc
}

// GetSubscription gets the subscription for a user
func (s *SubscriptionService) GetSubscription(userID uint) (*SubscriptionResponse, error) {
	sub, err := s.subscriptionRepo.GetOrCreate(userID)
	if err != nil {
		return nil, apperrors.Internal(err)
	}
	return NewSubscriptionResponse(sub), nil
}

// GetSubscriptionStatus gets detailed subscription status including limits
func (s *SubscriptionService) GetSubscriptionStatus(userID uint) (*SubscriptionStatusResponse, error) {
	sub, err := s.subscriptionRepo.GetOrCreate(userID)
	if err != nil {
		return nil, apperrors.Internal(err)
	}

	settings, err := s.subscriptionRepo.GetSettings()
	if err != nil {
		return nil, apperrors.Internal(err)
	}

	// Auto-start trial for new users who have never had a trial
	if !sub.TrialUsed && sub.TrialEnd == nil && settings.TrialEnabled {
		now := time.Now().UTC()
		trialEnd := now.Add(time.Duration(settings.TrialDurationDays) * 24 * time.Hour)
		if err := s.subscriptionRepo.SetTrialDates(userID, now, trialEnd); err != nil {
			return nil, apperrors.Internal(err)
		}
		// Re-fetch after starting trial so response reflects the new state
		sub, err = s.subscriptionRepo.FindByUserID(userID)
		if err != nil {
			return nil, apperrors.Internal(err)
		}
	}

	// Get all tier limits and build a map
	allLimits, err := s.subscriptionRepo.GetAllTierLimits()
	if err != nil {
		return nil, apperrors.Internal(err)
	}

	limitsMap := make(map[string]*TierLimitsClientResponse)
	for _, l := range allLimits {
		limitsMap[string(l.Tier)] = NewTierLimitsClientResponse(&l)
	}

	// Ensure both free and pro exist with defaults if missing
	if _, ok := limitsMap["free"]; !ok {
		defaults := models.GetDefaultFreeLimits()
		limitsMap["free"] = NewTierLimitsClientResponse(&defaults)
	}
	if _, ok := limitsMap["pro"]; !ok {
		defaults := models.GetDefaultProLimits()
		limitsMap["pro"] = NewTierLimitsClientResponse(&defaults)
	}

	// Get current usage
	usage, err := s.getUserUsage(userID)
	if err != nil {
		return nil, err
	}

	// Determine if limitations are enabled for this user
	// If user has IsFree flag, always return false (no limitations)
	limitationsEnabled := settings.EnableLimitations
	if sub.IsFree {
		limitationsEnabled = false
	}

	// Build flattened response (KMM expects subscription fields at top level)
	resp := &SubscriptionStatusResponse{
		Tier:               string(sub.Tier),
		IsActive:           sub.IsActive(),
		AutoRenew:          sub.AutoRenew,
		Limits:             limitsMap,
		Usage:              usage,
		LimitationsEnabled: limitationsEnabled,
	}

	// Format dates if present
	if sub.SubscribedAt != nil {
		t := sub.SubscribedAt.Format("2006-01-02T15:04:05Z")
		resp.SubscribedAt = &t
	}
	if sub.ExpiresAt != nil {
		t := sub.ExpiresAt.Format("2006-01-02T15:04:05Z")
		resp.ExpiresAt = &t
	}

	// Populate trial fields
	if sub.TrialStart != nil {
		t := sub.TrialStart.Format("2006-01-02T15:04:05Z")
		resp.TrialStart = &t
	}
	if sub.TrialEnd != nil {
		t := sub.TrialEnd.Format("2006-01-02T15:04:05Z")
		resp.TrialEnd = &t
	}
	resp.TrialActive = sub.IsTrialActive()
	resp.SubscriptionSource = sub.SubscriptionSource()

	return resp, nil
}

// getUserUsage calculates current usage for a user.
// P-10: Uses CountByOwner for properties count instead of loading all owned residences.
// Uses batch COUNT queries (O(1) queries) instead of per-residence queries (O(N)).
func (s *SubscriptionService) getUserUsage(userID uint) (*UsageResponse, error) {
	// P-10: Use CountByOwner for an efficient COUNT query instead of loading all records
	propertiesCount, err := s.residenceRepo.CountByOwner(userID)
	if err != nil {
		return nil, apperrors.Internal(err)
	}

	// Still need residence IDs for batch counting tasks/contractors/documents
	residenceIDs, err := s.residenceRepo.FindResidenceIDsByOwner(userID)
	if err != nil {
		return nil, apperrors.Internal(err)
	}

	// Count tasks, contractors, and documents across all residences with single queries each
	tasksCount, err := s.taskRepo.CountByResidenceIDs(residenceIDs)
	if err != nil {
		return nil, apperrors.Internal(err)
	}

	contractorsCount, err := s.contractorRepo.CountByResidenceIDs(residenceIDs)
	if err != nil {
		return nil, apperrors.Internal(err)
	}

	documentsCount, err := s.documentRepo.CountByResidenceIDs(residenceIDs)
	if err != nil {
		return nil, apperrors.Internal(err)
	}

	return &UsageResponse{
		PropertiesCount:  propertiesCount,
		TasksCount:       tasksCount,
		ContractorsCount: contractorsCount,
		DocumentsCount:   documentsCount,
	}, nil
}

// CheckLimit checks if a user has exceeded a specific limit
func (s *SubscriptionService) CheckLimit(userID uint, limitType string) error {
	settings, err := s.subscriptionRepo.GetSettings()
	if err != nil {
		return apperrors.Internal(err)
	}

	// If limitations are disabled globally, allow everything
	if !settings.EnableLimitations {
		return nil
	}

	sub, err := s.subscriptionRepo.GetOrCreate(userID)
	if err != nil {
		return apperrors.Internal(err)
	}

	// IsFree users bypass all limitations
	if sub.IsFree {
		return nil
	}

	// Pro users have unlimited access
	if sub.IsPro() {
		return nil
	}

	limits, err := s.subscriptionRepo.GetTierLimits(sub.Tier)
	if err != nil {
		return apperrors.Internal(err)
	}

	usage, err := s.getUserUsage(userID)
	if err != nil {
		return err
	}

	switch limitType {
	case "properties":
		if limits.PropertiesLimit != nil && usage.PropertiesCount >= int64(*limits.PropertiesLimit) {
			return apperrors.Forbidden("error.properties_limit_exceeded")
		}
	case "tasks":
		if limits.TasksLimit != nil && usage.TasksCount >= int64(*limits.TasksLimit) {
			return apperrors.Forbidden("error.tasks_limit_exceeded")
		}
	case "contractors":
		if limits.ContractorsLimit != nil && usage.ContractorsCount >= int64(*limits.ContractorsLimit) {
			return apperrors.Forbidden("error.contractors_limit_exceeded")
		}
	case "documents":
		if limits.DocumentsLimit != nil && usage.DocumentsCount >= int64(*limits.DocumentsLimit) {
			return apperrors.Forbidden("error.documents_limit_exceeded")
		}
	}

	return nil
}

// GetUpgradeTrigger gets an upgrade trigger by key
func (s *SubscriptionService) GetUpgradeTrigger(key string) (*UpgradeTriggerResponse, error) {
	trigger, err := s.subscriptionRepo.GetUpgradeTrigger(key)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, apperrors.NotFound("error.upgrade_trigger_not_found")
		}
		return nil, apperrors.Internal(err)
	}
	return NewUpgradeTriggerResponse(trigger), nil
}

// GetAllUpgradeTriggers gets all active upgrade triggers as a map keyed by trigger_key
// KMM client expects Map<String, UpgradeTriggerData>
func (s *SubscriptionService) GetAllUpgradeTriggers() (map[string]*UpgradeTriggerDataResponse, error) {
	triggers, err := s.subscriptionRepo.GetAllUpgradeTriggers()
	if err != nil {
		return nil, apperrors.Internal(err)
	}

	result := make(map[string]*UpgradeTriggerDataResponse)
	for _, t := range triggers {
		result[t.TriggerKey] = NewUpgradeTriggerDataResponse(&t)
	}
	return result, nil
}

// GetFeatureBenefits gets all feature benefits
func (s *SubscriptionService) GetFeatureBenefits() ([]FeatureBenefitResponse, error) {
	benefits, err := s.subscriptionRepo.GetFeatureBenefits()
	if err != nil {
		return nil, apperrors.Internal(err)
	}

	result := make([]FeatureBenefitResponse, len(benefits))
	for i, b := range benefits {
		result[i] = *NewFeatureBenefitResponse(&b)
	}
	return result, nil
}

// GetActivePromotions gets active promotions for a user
func (s *SubscriptionService) GetActivePromotions(userID uint) ([]PromotionResponse, error) {
	sub, err := s.subscriptionRepo.GetOrCreate(userID)
	if err != nil {
		return nil, apperrors.Internal(err)
	}

	promotions, err := s.subscriptionRepo.GetActivePromotions(sub.Tier)
	if err != nil {
		return nil, apperrors.Internal(err)
	}

	result := make([]PromotionResponse, len(promotions))
	for i, p := range promotions {
		result[i] = *NewPromotionResponse(&p)
	}
	return result, nil
}

// ProcessApplePurchase processes an Apple IAP purchase
// Supports both StoreKit 1 (receiptData) and StoreKit 2 (transactionID)
func (s *SubscriptionService) ProcessApplePurchase(userID uint, receiptData string, transactionID string) (*SubscriptionResponse, error) {
	// Store receipt/transaction data
	dataToStore := receiptData
	if dataToStore == "" {
		dataToStore = transactionID
	}
	if err := s.subscriptionRepo.UpdateReceiptData(userID, dataToStore); err != nil {
		return nil, apperrors.Internal(err)
	}

	// Apple IAP client must be configured to validate purchases.
	// Without server-side validation, we cannot trust client-provided receipts.
	if s.appleClient == nil {
		log.Error().Uint("user_id", userID).Msg("Apple IAP validation not configured, rejecting purchase")
		return nil, apperrors.BadRequest("error.iap_validation_not_configured")
	}

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	var result *AppleValidationResult
	var err error

	// Prefer transaction ID (StoreKit 2), fall back to receipt data (StoreKit 1)
	if transactionID != "" {
		result, err = s.appleClient.ValidateTransaction(ctx, transactionID)
	} else if receiptData != "" {
		result, err = s.appleClient.ValidateReceipt(ctx, receiptData)
	}

	if err != nil {
		// Validation failed -- do NOT fall through to grant Pro.
		log.Error().Err(err).Uint("user_id", userID).Msg("Apple validation failed")
		return nil, err
	}

	if result == nil {
		return nil, apperrors.BadRequest("error.no_receipt_or_transaction")
	}

	expiresAt := result.ExpiresAt
	log.Info().Uint("user_id", userID).Str("product", result.ProductID).Time("expires", result.ExpiresAt).Str("env", result.Environment).Msg("Apple purchase validated")

	// Upgrade to Pro with the validated expiration
	if err := s.subscriptionRepo.UpgradeToPro(userID, expiresAt, "ios"); err != nil {
		return nil, apperrors.Internal(err)
	}

	return s.GetSubscription(userID)
}

// ProcessGooglePurchase processes a Google Play purchase
// productID is optional but helps validate the specific subscription
func (s *SubscriptionService) ProcessGooglePurchase(userID uint, purchaseToken string, productID string) (*SubscriptionResponse, error) {
	// Store purchase token first
	if err := s.subscriptionRepo.UpdatePurchaseToken(userID, purchaseToken); err != nil {
		return nil, apperrors.Internal(err)
	}

	// Google IAP client must be configured to validate purchases.
	// Without server-side validation, we cannot trust client-provided tokens.
	if s.googleClient == nil {
		log.Error().Uint("user_id", userID).Msg("Google IAP validation not configured, rejecting purchase")
		return nil, apperrors.BadRequest("error.iap_validation_not_configured")
	}

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	var result *GoogleValidationResult
	var err error

	// If productID is provided, use it directly; otherwise try known IDs
	if productID != "" {
		result, err = s.googleClient.ValidateSubscription(ctx, productID, purchaseToken)
	} else {
		result, err = s.googleClient.ValidatePurchaseToken(ctx, purchaseToken, KnownSubscriptionIDs)
	}

	if err != nil {
		// Validation failed -- do NOT fall through to grant Pro.
		log.Error().Err(err).Uint("user_id", userID).Msg("Google purchase validation failed")
		return nil, err
	}

	if result == nil {
		return nil, apperrors.BadRequest("error.no_purchase_token")
	}

	expiresAt := result.ExpiresAt
	log.Info().Uint("user_id", userID).Str("product", result.ProductID).Time("expires", result.ExpiresAt).Bool("auto_renew", result.AutoRenewing).Msg("Google purchase validated")

	// Acknowledge the subscription if not already acknowledged
	if !result.AcknowledgedState {
		if err := s.googleClient.AcknowledgeSubscription(ctx, result.ProductID, purchaseToken); err != nil {
			log.Warn().Err(err).Uint("user_id", userID).Msg("Failed to acknowledge Google subscription")
			// Don't fail the purchase, just log the warning
		}
	}

	// Upgrade to Pro with the validated expiration
	if err := s.subscriptionRepo.UpgradeToPro(userID, expiresAt, "android"); err != nil {
		return nil, apperrors.Internal(err)
	}

	return s.GetSubscription(userID)
}

// CancelSubscription cancels a subscription (downgrades to free at end of period)
func (s *SubscriptionService) CancelSubscription(userID uint) (*SubscriptionResponse, error) {
	if err := s.subscriptionRepo.SetAutoRenew(userID, false); err != nil {
		return nil, apperrors.Internal(err)
	}
	return s.GetSubscription(userID)
}

// IsAlreadyProFromOtherPlatform checks if a user already has an active Pro subscription
// from a different platform than the one being requested. Returns (conflict, existingPlatform, error).
func (s *SubscriptionService) IsAlreadyProFromOtherPlatform(userID uint, requestedPlatform string) (bool, string, error) {
	sub, err := s.subscriptionRepo.GetOrCreate(userID)
	if err != nil {
		return false, "", apperrors.Internal(err)
	}
	if !sub.IsPro() {
		return false, "", nil
	}
	if sub.Platform == requestedPlatform {
		return false, "", nil
	}
	return true, sub.Platform, nil
}

// === Response Types ===

// SubscriptionResponse represents a subscription in API response
type SubscriptionResponse struct {
	Tier               string  `json:"tier"`
	SubscribedAt       *string `json:"subscribed_at"`
	ExpiresAt          *string `json:"expires_at"`
	AutoRenew          bool    `json:"auto_renew"`
	CancelledAt        *string `json:"cancelled_at"`
	Platform           string  `json:"platform"`
	IsActive           bool    `json:"is_active"`
	IsPro              bool    `json:"is_pro"`
	TrialActive        bool    `json:"trial_active"`
	SubscriptionSource string  `json:"subscription_source"`
}

// NewSubscriptionResponse creates a SubscriptionResponse from a model
func NewSubscriptionResponse(s *models.UserSubscription) *SubscriptionResponse {
	resp := &SubscriptionResponse{
		Tier:               string(s.Tier),
		AutoRenew:          s.AutoRenew,
		Platform:           s.Platform,
		IsActive:           s.IsActive(),
		IsPro:              s.IsPro(),
		TrialActive:        s.IsTrialActive(),
		SubscriptionSource: s.SubscriptionSource(),
	}
	if s.SubscribedAt != nil {
		t := s.SubscribedAt.Format("2006-01-02T15:04:05Z")
		resp.SubscribedAt = &t
	}
	if s.ExpiresAt != nil {
		t := s.ExpiresAt.Format("2006-01-02T15:04:05Z")
		resp.ExpiresAt = &t
	}
	if s.CancelledAt != nil {
		t := s.CancelledAt.Format("2006-01-02T15:04:05Z")
		resp.CancelledAt = &t
	}
	return resp
}

// TierLimitsResponse represents tier limits
type TierLimitsResponse struct {
	Tier             string `json:"tier"`
	PropertiesLimit  *int   `json:"properties_limit"`
	TasksLimit       *int   `json:"tasks_limit"`
	ContractorsLimit *int   `json:"contractors_limit"`
	DocumentsLimit   *int   `json:"documents_limit"`
}

// NewTierLimitsResponse creates a TierLimitsResponse from a model
func NewTierLimitsResponse(l *models.TierLimits) *TierLimitsResponse {
	return &TierLimitsResponse{
		Tier:             string(l.Tier),
		PropertiesLimit:  l.PropertiesLimit,
		TasksLimit:       l.TasksLimit,
		ContractorsLimit: l.ContractorsLimit,
		DocumentsLimit:   l.DocumentsLimit,
	}
}

// UsageResponse represents current usage (KMM client expects _count suffix)
type UsageResponse struct {
	PropertiesCount  int64 `json:"properties_count"`
	TasksCount       int64 `json:"tasks_count"`
	ContractorsCount int64 `json:"contractors_count"`
	DocumentsCount   int64 `json:"documents_count"`
}

// TierLimitsClientResponse represents tier limits for mobile client (simple field names)
type TierLimitsClientResponse struct {
	Properties  *int `json:"properties"`
	Tasks       *int `json:"tasks"`
	Contractors *int `json:"contractors"`
	Documents   *int `json:"documents"`
}

// NewTierLimitsClientResponse creates a TierLimitsClientResponse from a model
func NewTierLimitsClientResponse(l *models.TierLimits) *TierLimitsClientResponse {
	return &TierLimitsClientResponse{
		Properties:  l.PropertiesLimit,
		Tasks:       l.TasksLimit,
		Contractors: l.ContractorsLimit,
		Documents:   l.DocumentsLimit,
	}
}

// SubscriptionStatusResponse represents full subscription status
// Fields are flattened to match KMM client expectations
type SubscriptionStatusResponse struct {
	// Tier and active status
	Tier     string `json:"tier"`
	IsActive bool   `json:"is_active"`

	// Flattened subscription fields (KMM expects these at top level)
	SubscribedAt *string `json:"subscribed_at"`
	ExpiresAt    *string `json:"expires_at"`
	AutoRenew    bool    `json:"auto_renew"`

	// Trial fields
	TrialStart *string `json:"trial_start,omitempty"`
	TrialEnd   *string `json:"trial_end,omitempty"`
	TrialActive bool   `json:"trial_active"`

	// Subscription source
	SubscriptionSource string `json:"subscription_source"`

	// Other fields
	Usage              *UsageResponse                       `json:"usage"`
	Limits             map[string]*TierLimitsClientResponse `json:"limits"`
	LimitationsEnabled bool                                 `json:"limitations_enabled"`
}

// UpgradeTriggerResponse represents an upgrade trigger (includes trigger_key)
type UpgradeTriggerResponse struct {
	TriggerKey string `json:"trigger_key"`
	Title      string `json:"title"`
	Message    string `json:"message"`
	PromoHTML  string `json:"promo_html"`
	ButtonText string `json:"button_text"`
}

// NewUpgradeTriggerResponse creates an UpgradeTriggerResponse from a model
func NewUpgradeTriggerResponse(t *models.UpgradeTrigger) *UpgradeTriggerResponse {
	return &UpgradeTriggerResponse{
		TriggerKey: t.TriggerKey,
		Title:      t.Title,
		Message:    t.Message,
		PromoHTML:  t.PromoHTML,
		ButtonText: t.ButtonText,
	}
}

// UpgradeTriggerDataResponse represents trigger data for map values (no trigger_key)
// Matches KMM UpgradeTriggerData model
type UpgradeTriggerDataResponse struct {
	Title      string  `json:"title"`
	Message    string  `json:"message"`
	PromoHTML  *string `json:"promo_html"`
	ButtonText string  `json:"button_text"`
}

// NewUpgradeTriggerDataResponse creates an UpgradeTriggerDataResponse from a model
func NewUpgradeTriggerDataResponse(t *models.UpgradeTrigger) *UpgradeTriggerDataResponse {
	var promoHTML *string
	if t.PromoHTML != "" {
		promoHTML = &t.PromoHTML
	}
	return &UpgradeTriggerDataResponse{
		Title:      t.Title,
		Message:    t.Message,
		PromoHTML:  promoHTML,
		ButtonText: t.ButtonText,
	}
}

// FeatureBenefitResponse represents a feature benefit
type FeatureBenefitResponse struct {
	FeatureName  string `json:"feature_name"`
	FreeTierText string `json:"free_tier_text"`
	ProTierText  string `json:"pro_tier_text"`
	DisplayOrder int    `json:"display_order"`
}

// NewFeatureBenefitResponse creates a FeatureBenefitResponse from a model
func NewFeatureBenefitResponse(f *models.FeatureBenefit) *FeatureBenefitResponse {
	return &FeatureBenefitResponse{
		FeatureName:  f.FeatureName,
		FreeTierText: f.FreeTierText,
		ProTierText:  f.ProTierText,
		DisplayOrder: f.DisplayOrder,
	}
}

// PromotionResponse represents a promotion
type PromotionResponse struct {
	PromotionID string  `json:"promotion_id"`
	Title       string  `json:"title"`
	Message     string  `json:"message"`
	Link        *string `json:"link"`
	StartDate   string  `json:"start_date"`
	EndDate     string  `json:"end_date"`
}

// NewPromotionResponse creates a PromotionResponse from a model
func NewPromotionResponse(p *models.Promotion) *PromotionResponse {
	return &PromotionResponse{
		PromotionID: p.PromotionID,
		Title:       p.Title,
		Message:     p.Message,
		Link:        p.Link,
		StartDate:   p.StartDate.Format("2006-01-02"),
		EndDate:     p.EndDate.Format("2006-01-02"),
	}
}

// === Request Types ===

// ProcessPurchaseRequest represents an IAP purchase request
type ProcessPurchaseRequest struct {
	ReceiptData   string `json:"receipt_data"`   // iOS (StoreKit 1 receipt or StoreKit 2 JWS)
	TransactionID string `json:"transaction_id"` // iOS StoreKit 2 transaction ID
	PurchaseToken string `json:"purchase_token"` // Android
	ProductID     string `json:"product_id"`     // Android (optional, helps identify subscription)
	Platform      string `json:"platform" validate:"required,oneof=ios android stripe"`
}
