package handlers

import (
	"net/http"
	"strconv"
	"time"

	"github.com/labstack/echo/v4"
	"gorm.io/gorm"

	"github.com/treytartt/honeydue-api/internal/admin/dto"
	"github.com/treytartt/honeydue-api/internal/models"
)

// AdminSubscriptionHandler handles admin subscription management endpoints
type AdminSubscriptionHandler struct {
	db *gorm.DB
}

// NewAdminSubscriptionHandler creates a new admin subscription handler
func NewAdminSubscriptionHandler(db *gorm.DB) *AdminSubscriptionHandler {
	return &AdminSubscriptionHandler{db: db}
}

// List handles GET /api/admin/subscriptions
func (h *AdminSubscriptionHandler) List(c echo.Context) error {
	var filters dto.SubscriptionFilters
	if err := c.Bind(&filters); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}

	var subscriptions []models.UserSubscription
	var total int64

	query := h.db.Model(&models.UserSubscription{}).
		Preload("User")

	// Apply search (search by user email)
	if filters.Search != "" {
		search := "%" + filters.Search + "%"
		query = query.Joins("JOIN auth_user ON auth_user.id = subscription_usersubscription.user_id").
			Where("auth_user.email ILIKE ? OR auth_user.username ILIKE ?", search, search)
	}

	// Apply filters
	if filters.UserID != nil {
		query = query.Where("user_id = ?", *filters.UserID)
	}
	if filters.Tier != nil {
		query = query.Where("tier = ?", *filters.Tier)
	}
	if filters.Platform != nil {
		query = query.Where("platform = ?", *filters.Platform)
	}
	if filters.AutoRenew != nil {
		query = query.Where("auto_renew = ?", *filters.AutoRenew)
	}
	if filters.Active != nil {
		if *filters.Active {
			query = query.Where("expires_at IS NULL OR expires_at > NOW()")
		} else {
			query = query.Where("expires_at IS NOT NULL AND expires_at <= NOW()")
		}
	}
	if filters.HasStripe != nil {
		if *filters.HasStripe {
			query = query.Where("stripe_subscription_id IS NOT NULL")
		} else {
			query = query.Where("stripe_subscription_id IS NULL")
		}
	}
	if filters.TrialActive != nil {
		if *filters.TrialActive {
			query = query.Where("trial_end IS NOT NULL AND trial_end > NOW()")
		} else {
			query = query.Where("trial_end IS NULL OR trial_end <= NOW()")
		}
	}

	// Get total count
	query.Count(&total)

	// Apply sorting (allowlist prevents SQL injection via sort_by parameter)
	sortBy := filters.GetSafeSortBy([]string{
		"id", "created_at", "updated_at", "user_id",
		"tier", "platform", "auto_renew", "expires_at", "subscribed_at",
	}, "created_at")
	query = query.Order(sortBy + " " + filters.GetSortDir())

	// Apply pagination
	query = query.Offset(filters.GetOffset()).Limit(filters.GetPerPage())

	if err := query.Find(&subscriptions).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch subscriptions"})
	}

	// Build response
	responses := make([]dto.SubscriptionResponse, len(subscriptions))
	for i, sub := range subscriptions {
		responses[i] = h.toSubscriptionResponse(&sub)
	}

	return c.JSON(http.StatusOK, dto.NewPaginatedResponse(responses, total, filters.GetPage(), filters.GetPerPage()))
}

// Get handles GET /api/admin/subscriptions/:id
func (h *AdminSubscriptionHandler) Get(c echo.Context) error {
	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid subscription ID"})
	}

	var subscription models.UserSubscription
	if err := h.db.
		Preload("User").
		First(&subscription, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Subscription not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch subscription"})
	}

	return c.JSON(http.StatusOK, h.toSubscriptionDetailResponse(&subscription))
}

// Update handles PUT /api/admin/subscriptions/:id
func (h *AdminSubscriptionHandler) Update(c echo.Context) error {
	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid subscription ID"})
	}

	var subscription models.UserSubscription
	if err := h.db.First(&subscription, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Subscription not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch subscription"})
	}

	var req dto.UpdateSubscriptionRequest
	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}

	if req.Tier != nil {
		subscription.Tier = models.SubscriptionTier(*req.Tier)
	}
	if req.AutoRenew != nil {
		subscription.AutoRenew = *req.AutoRenew
	}
	if req.IsFree != nil {
		subscription.IsFree = *req.IsFree
	}
	if req.StripeCustomerID != nil {
		subscription.StripeCustomerID = req.StripeCustomerID
	}
	if req.StripeSubscriptionID != nil {
		subscription.StripeSubscriptionID = req.StripeSubscriptionID
	}
	if req.StripePriceID != nil {
		subscription.StripePriceID = req.StripePriceID
	}
	if req.TrialStart != nil {
		parsed, err := time.Parse(time.RFC3339, *req.TrialStart)
		if err != nil {
			return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid trial_start format, expected RFC3339"})
		}
		subscription.TrialStart = &parsed
	}
	if req.TrialEnd != nil {
		parsed, err := time.Parse(time.RFC3339, *req.TrialEnd)
		if err != nil {
			return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid trial_end format, expected RFC3339"})
		}
		subscription.TrialEnd = &parsed
	}
	if req.TrialUsed != nil {
		subscription.TrialUsed = *req.TrialUsed
	}

	if err := h.db.Save(&subscription).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to update subscription"})
	}

	h.db.Preload("User").First(&subscription, id)
	return c.JSON(http.StatusOK, h.toSubscriptionResponse(&subscription))
}

// GetByUser handles GET /api/admin/subscriptions/user/:user_id
func (h *AdminSubscriptionHandler) GetByUser(c echo.Context) error {
	userID, err := strconv.ParseUint(c.Param("user_id"), 10, 32)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid user ID"})
	}

	var subscription models.UserSubscription
	err = h.db.
		Preload("User").
		Where("user_id = ?", userID).
		First(&subscription).Error

	if err != nil {
		if err == gorm.ErrRecordNotFound {
			// Create a default subscription for the user
			subscription = models.UserSubscription{
				UserID:    uint(userID),
				Tier:      models.TierFree,
				AutoRenew: true,
				IsFree:    false,
			}
			if err := h.db.Create(&subscription).Error; err != nil {
				return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to create subscription"})
			}
			// Reload with user
			h.db.Preload("User").First(&subscription, subscription.ID)
		} else {
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch subscription"})
		}
	}

	return c.JSON(http.StatusOK, h.toSubscriptionResponse(&subscription))
}

// GetStats handles GET /api/admin/subscriptions/stats
func (h *AdminSubscriptionHandler) GetStats(c echo.Context) error {
	var total, free, premium, pro int64
	var stripeSubscribers, activeTrials int64

	h.db.Model(&models.UserSubscription{}).Count(&total)
	h.db.Model(&models.UserSubscription{}).Where("tier = ?", "free").Count(&free)
	h.db.Model(&models.UserSubscription{}).Where("tier = ?", "premium").Count(&premium)
	h.db.Model(&models.UserSubscription{}).Where("tier = ?", "pro").Count(&pro)
	h.db.Model(&models.UserSubscription{}).Where("stripe_subscription_id IS NOT NULL AND tier = ?", "pro").Count(&stripeSubscribers)
	h.db.Model(&models.UserSubscription{}).Where("trial_end IS NOT NULL AND trial_end > NOW()").Count(&activeTrials)

	return c.JSON(http.StatusOK, map[string]interface{}{
		"total":              total,
		"free":               free,
		"premium":            premium,
		"pro":                pro,
		"stripe_subscribers": stripeSubscribers,
		"active_trials":      activeTrials,
	})
}

func (h *AdminSubscriptionHandler) toSubscriptionResponse(sub *models.UserSubscription) dto.SubscriptionResponse {
	response := dto.SubscriptionResponse{
		ID:                   sub.ID,
		UserID:               sub.UserID,
		Tier:                 string(sub.Tier),
		Platform:             sub.Platform,
		AutoRenew:            sub.AutoRenew,
		IsFree:               sub.IsFree,
		StripeCustomerID:     sub.StripeCustomerID,
		StripeSubscriptionID: sub.StripeSubscriptionID,
		StripePriceID:        sub.StripePriceID,
		TrialUsed:            sub.TrialUsed,
		TrialActive:          sub.IsTrialActive(),
		CreatedAt:            sub.CreatedAt.Format("2006-01-02T15:04:05Z"),
	}

	if sub.User.ID != 0 {
		response.UserEmail = sub.User.Email
		response.Username = sub.User.Username
	}
	if sub.SubscribedAt != nil {
		subscribedAt := sub.SubscribedAt.Format("2006-01-02T15:04:05Z")
		response.SubscribedAt = &subscribedAt
	}
	if sub.ExpiresAt != nil {
		expiresAt := sub.ExpiresAt.Format("2006-01-02T15:04:05Z")
		response.ExpiresAt = &expiresAt
	}
	if sub.CancelledAt != nil {
		cancelledAt := sub.CancelledAt.Format("2006-01-02T15:04:05Z")
		response.CancelledAt = &cancelledAt
	}
	if sub.TrialStart != nil {
		trialStart := sub.TrialStart.Format(time.RFC3339)
		response.TrialStart = &trialStart
	}
	if sub.TrialEnd != nil {
		trialEnd := sub.TrialEnd.Format(time.RFC3339)
		response.TrialEnd = &trialEnd
	}

	return response
}

func (h *AdminSubscriptionHandler) toSubscriptionDetailResponse(sub *models.UserSubscription) dto.SubscriptionDetailResponse {
	return dto.SubscriptionDetailResponse{
		SubscriptionResponse: h.toSubscriptionResponse(sub),
	}
}
