package handlers

import (
	"net/http"
	"strconv"

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

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

// AdminLimitationsHandler handles subscription limitations management
type AdminLimitationsHandler struct {
	db *gorm.DB
}

// NewAdminLimitationsHandler creates a new handler
func NewAdminLimitationsHandler(db *gorm.DB) *AdminLimitationsHandler {
	return &AdminLimitationsHandler{db: db}
}

// === Settings (enable_limitations) ===

// LimitationsSettingsResponse represents the limitations settings
type LimitationsSettingsResponse struct {
	EnableLimitations bool `json:"enable_limitations"`
}

// GetSettings handles GET /api/admin/limitations/settings
func (h *AdminLimitationsHandler) GetSettings(c echo.Context) error {
	var settings models.SubscriptionSettings
	if err := h.db.First(&settings, 1).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			// Create default settings
			settings = models.SubscriptionSettings{ID: 1, EnableLimitations: false}
			if err := h.db.Create(&settings).Error; err != nil {
				return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to create default settings"})
			}
		} else {
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch settings"})
		}
	}

	return c.JSON(http.StatusOK, LimitationsSettingsResponse{
		EnableLimitations: settings.EnableLimitations,
	})
}

// UpdateSettingsRequest represents the update request
type UpdateLimitationsSettingsRequest struct {
	EnableLimitations *bool `json:"enable_limitations"`
}

// UpdateSettings handles PUT /api/admin/limitations/settings
func (h *AdminLimitationsHandler) UpdateSettings(c echo.Context) error {
	var req UpdateLimitationsSettingsRequest
	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}

	var settings models.SubscriptionSettings
	if err := h.db.First(&settings, 1).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			settings = models.SubscriptionSettings{ID: 1}
		} else {
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch settings"})
		}
	}

	if req.EnableLimitations != nil {
		settings.EnableLimitations = *req.EnableLimitations
	}

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

	return c.JSON(http.StatusOK, LimitationsSettingsResponse{
		EnableLimitations: settings.EnableLimitations,
	})
}

// === Tier Limits ===

// TierLimitsResponse represents tier limits in API response
type TierLimitsResponse struct {
	ID               uint   `json:"id"`
	Tier             string `json:"tier"`
	PropertiesLimit  *int   `json:"properties_limit"`
	TasksLimit       *int   `json:"tasks_limit"`
	ContractorsLimit *int   `json:"contractors_limit"`
	DocumentsLimit   *int   `json:"documents_limit"`
	CreatedAt        string `json:"created_at"`
	UpdatedAt        string `json:"updated_at"`
}

func toTierLimitsResponse(t *models.TierLimits) TierLimitsResponse {
	return TierLimitsResponse{
		ID:               t.ID,
		Tier:             string(t.Tier),
		PropertiesLimit:  t.PropertiesLimit,
		TasksLimit:       t.TasksLimit,
		ContractorsLimit: t.ContractorsLimit,
		DocumentsLimit:   t.DocumentsLimit,
		CreatedAt:        t.CreatedAt.Format("2006-01-02T15:04:05Z"),
		UpdatedAt:        t.UpdatedAt.Format("2006-01-02T15:04:05Z"),
	}
}

// ListTierLimits handles GET /api/admin/limitations/tier-limits
func (h *AdminLimitationsHandler) ListTierLimits(c echo.Context) error {
	var limits []models.TierLimits
	if err := h.db.Order("tier").Find(&limits).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch tier limits"})
	}

	// If no limits exist, create defaults
	if len(limits) == 0 {
		freeLimits := models.GetDefaultFreeLimits()
		proLimits := models.GetDefaultProLimits()
		if err := h.db.Create(&freeLimits).Error; err != nil {
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to create default free tier limits"})
		}
		if err := h.db.Create(&proLimits).Error; err != nil {
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to create default pro tier limits"})
		}
		limits = []models.TierLimits{freeLimits, proLimits}
	}

	responses := make([]TierLimitsResponse, len(limits))
	for i, l := range limits {
		responses[i] = toTierLimitsResponse(&l)
	}

	return c.JSON(http.StatusOK, map[string]interface{}{
		"data":  responses,
		"total": len(responses),
	})
}

// GetTierLimits handles GET /api/admin/limitations/tier-limits/:tier
func (h *AdminLimitationsHandler) GetTierLimits(c echo.Context) error {
	tier := c.Param("tier")
	if tier != "free" && tier != "pro" {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid tier. Must be 'free' or 'pro'"})
	}

	var limits models.TierLimits
	if err := h.db.Where("tier = ?", tier).First(&limits).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			// Create default
			if tier == "free" {
				limits = models.GetDefaultFreeLimits()
			} else {
				limits = models.GetDefaultProLimits()
			}
			if err := h.db.Create(&limits).Error; err != nil {
				return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to create default tier limits"})
			}
		} else {
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch tier limits"})
		}
	}

	return c.JSON(http.StatusOK, toTierLimitsResponse(&limits))
}

// UpdateTierLimitsRequest represents the update request for tier limits
type UpdateTierLimitsRequest struct {
	PropertiesLimit  *int `json:"properties_limit"`
	TasksLimit       *int `json:"tasks_limit"`
	ContractorsLimit *int `json:"contractors_limit"`
	DocumentsLimit   *int `json:"documents_limit"`
}

// UpdateTierLimits handles PUT /api/admin/limitations/tier-limits/:tier
func (h *AdminLimitationsHandler) UpdateTierLimits(c echo.Context) error {
	tier := c.Param("tier")
	if tier != "free" && tier != "pro" {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid tier. Must be 'free' or 'pro'"})
	}

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

	var limits models.TierLimits
	if err := h.db.Where("tier = ?", tier).First(&limits).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			// Create new entry
			limits = models.TierLimits{Tier: models.SubscriptionTier(tier)}
		} else {
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch tier limits"})
		}
	}

	// Update fields only when explicitly provided in the request body.
	// JSON unmarshaling sets *int to nil when the key is absent, and to
	// a non-nil *int (possibly pointing to 0) when the key is present.
	// We rely on Bind populating these before calling this handler, so
	// a nil pointer here means "don't change".
	if req.PropertiesLimit != nil {
		limits.PropertiesLimit = req.PropertiesLimit
	}
	if req.TasksLimit != nil {
		limits.TasksLimit = req.TasksLimit
	}
	if req.ContractorsLimit != nil {
		limits.ContractorsLimit = req.ContractorsLimit
	}
	if req.DocumentsLimit != nil {
		limits.DocumentsLimit = req.DocumentsLimit
	}

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

	return c.JSON(http.StatusOK, toTierLimitsResponse(&limits))
}

// === Upgrade Triggers ===

// UpgradeTriggerResponse represents an upgrade trigger in API response
type UpgradeTriggerResponse struct {
	ID         uint   `json:"id"`
	TriggerKey string `json:"trigger_key"`
	Title      string `json:"title"`
	Message    string `json:"message"`
	PromoHTML  string `json:"promo_html"`
	ButtonText string `json:"button_text"`
	IsActive   bool   `json:"is_active"`
	CreatedAt  string `json:"created_at"`
	UpdatedAt  string `json:"updated_at"`
}

func toUpgradeTriggerResponse(t *models.UpgradeTrigger) UpgradeTriggerResponse {
	return UpgradeTriggerResponse{
		ID:         t.ID,
		TriggerKey: t.TriggerKey,
		Title:      t.Title,
		Message:    t.Message,
		PromoHTML:  t.PromoHTML,
		ButtonText: t.ButtonText,
		IsActive:   t.IsActive,
		CreatedAt:  t.CreatedAt.Format("2006-01-02T15:04:05Z"),
		UpdatedAt:  t.UpdatedAt.Format("2006-01-02T15:04:05Z"),
	}
}

// Available trigger keys
var availableTriggerKeys = []string{
	"user_profile",
	"add_second_property",
	"add_11th_task",
	"view_contractors",
	"view_documents",
}

// GetAvailableTriggerKeys handles GET /api/admin/limitations/upgrade-triggers/keys
func (h *AdminLimitationsHandler) GetAvailableTriggerKeys(c echo.Context) error {
	type KeyOption struct {
		Key   string `json:"key"`
		Label string `json:"label"`
	}

	keys := []KeyOption{
		{Key: "user_profile", Label: "User Profile"},
		{Key: "add_second_property", Label: "Add Second Property"},
		{Key: "add_11th_task", Label: "Add 11th Task"},
		{Key: "view_contractors", Label: "View Contractors"},
		{Key: "view_documents", Label: "View Documents & Warranties"},
	}

	return c.JSON(http.StatusOK, keys)
}

// ListUpgradeTriggers handles GET /api/admin/limitations/upgrade-triggers
func (h *AdminLimitationsHandler) ListUpgradeTriggers(c echo.Context) error {
	var triggers []models.UpgradeTrigger
	if err := h.db.Order("trigger_key").Find(&triggers).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch upgrade triggers"})
	}

	responses := make([]UpgradeTriggerResponse, len(triggers))
	for i, t := range triggers {
		responses[i] = toUpgradeTriggerResponse(&t)
	}

	return c.JSON(http.StatusOK, map[string]interface{}{
		"data":  responses,
		"total": len(responses),
	})
}

// GetUpgradeTrigger handles GET /api/admin/limitations/upgrade-triggers/:id
func (h *AdminLimitationsHandler) GetUpgradeTrigger(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 ID"})
	}

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

	return c.JSON(http.StatusOK, toUpgradeTriggerResponse(&trigger))
}

// CreateUpgradeTriggerRequest represents the create request
type CreateUpgradeTriggerRequest struct {
	TriggerKey string `json:"trigger_key" validate:"required"`
	Title      string `json:"title" validate:"required"`
	Message    string `json:"message" validate:"required"`
	PromoHTML  string `json:"promo_html"`
	ButtonText string `json:"button_text"`
	IsActive   *bool  `json:"is_active"`
}

// CreateUpgradeTrigger handles POST /api/admin/limitations/upgrade-triggers
func (h *AdminLimitationsHandler) CreateUpgradeTrigger(c echo.Context) error {
	var req CreateUpgradeTriggerRequest
	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}
	if err := c.Validate(&req); err != nil {
		return err
	}

	// Validate trigger key
	validKey := false
	for _, k := range availableTriggerKeys {
		if k == req.TriggerKey {
			validKey = true
			break
		}
	}
	if !validKey {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid trigger_key"})
	}

	// Check if trigger key already exists
	var existing models.UpgradeTrigger
	if err := h.db.Where("trigger_key = ?", req.TriggerKey).First(&existing).Error; err == nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Trigger key already exists"})
	}

	trigger := models.UpgradeTrigger{
		TriggerKey: req.TriggerKey,
		Title:      req.Title,
		Message:    req.Message,
		PromoHTML:  req.PromoHTML,
		ButtonText: req.ButtonText,
		IsActive:   true,
	}

	if req.ButtonText == "" {
		trigger.ButtonText = "Upgrade to Pro"
	}
	if req.IsActive != nil {
		trigger.IsActive = *req.IsActive
	}

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

	return c.JSON(http.StatusCreated, toUpgradeTriggerResponse(&trigger))
}

// UpdateUpgradeTriggerRequest represents the update request
type UpdateUpgradeTriggerRequest struct {
	TriggerKey *string `json:"trigger_key"`
	Title      *string `json:"title"`
	Message    *string `json:"message"`
	PromoHTML  *string `json:"promo_html"`
	ButtonText *string `json:"button_text"`
	IsActive   *bool   `json:"is_active"`
}

// UpdateUpgradeTrigger handles PUT /api/admin/limitations/upgrade-triggers/:id
func (h *AdminLimitationsHandler) UpdateUpgradeTrigger(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 ID"})
	}

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

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

	if req.TriggerKey != nil {
		// Validate new trigger key
		validKey := false
		for _, k := range availableTriggerKeys {
			if k == *req.TriggerKey {
				validKey = true
				break
			}
		}
		if !validKey {
			return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid trigger_key"})
		}
		// Check if key is already used by another trigger
		if *req.TriggerKey != trigger.TriggerKey {
			var existing models.UpgradeTrigger
			if err := h.db.Where("trigger_key = ?", *req.TriggerKey).First(&existing).Error; err == nil {
				return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Trigger key already exists"})
			}
		}
		trigger.TriggerKey = *req.TriggerKey
	}
	if req.Title != nil {
		trigger.Title = *req.Title
	}
	if req.Message != nil {
		trigger.Message = *req.Message
	}
	if req.PromoHTML != nil {
		trigger.PromoHTML = *req.PromoHTML
	}
	if req.ButtonText != nil {
		trigger.ButtonText = *req.ButtonText
	}
	if req.IsActive != nil {
		trigger.IsActive = *req.IsActive
	}

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

	return c.JSON(http.StatusOK, toUpgradeTriggerResponse(&trigger))
}

// DeleteUpgradeTrigger handles DELETE /api/admin/limitations/upgrade-triggers/:id
func (h *AdminLimitationsHandler) DeleteUpgradeTrigger(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 ID"})
	}

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

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

	return c.JSON(http.StatusOK, map[string]interface{}{"message": "Upgrade trigger deleted"})
}
