package handlers

import (
	"context"
	"net/http"
	"strconv"
	"strings"

	"github.com/labstack/echo/v4"
	"github.com/rs/zerolog/log"
	"gorm.io/gorm"

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

// AdminTaskTemplateHandler handles admin task template management endpoints
type AdminTaskTemplateHandler struct {
	db *gorm.DB
}

// NewAdminTaskTemplateHandler creates a new admin task template handler
func NewAdminTaskTemplateHandler(db *gorm.DB) *AdminTaskTemplateHandler {
	return &AdminTaskTemplateHandler{db: db}
}

// refreshTaskTemplatesCache invalidates and refreshes the task templates cache
func (h *AdminTaskTemplateHandler) refreshTaskTemplatesCache(ctx context.Context) {
	cache := services.GetCache()
	if cache == nil {
		log.Warn().Msg("Cache service unavailable, skipping task templates cache refresh")
		return
	}

	var templates []models.TaskTemplate
	if err := h.db.Preload("Category").Preload("Frequency").
		Where("is_active = ?", true).
		Order("display_order ASC, title ASC").
		Find(&templates).Error; err != nil {
		log.Warn().Err(err).Msg("Failed to fetch task templates for cache refresh")
	}

	if err := cache.CacheTaskTemplates(ctx, templates); err != nil {
		log.Warn().Err(err).Msg("Failed to cache task templates")
	}
	log.Debug().Int("count", len(templates)).Msg("Refreshed task templates cache")

	// Invalidate unified seeded data cache
	if err := cache.InvalidateSeededData(ctx); err != nil {
		log.Warn().Err(err).Msg("Failed to invalidate seeded data cache")
	}
	log.Debug().Msg("Invalidated seeded data cache")
}

// TaskTemplateResponse represents a task template in admin responses
type TaskTemplateResponse struct {
	ID           uint                  `json:"id"`
	Title        string                `json:"title"`
	Description  string                `json:"description"`
	CategoryID   *uint                 `json:"category_id"`
	Category     *TaskCategoryResponse `json:"category,omitempty"`
	FrequencyID  *uint                 `json:"frequency_id"`
	Frequency    *TaskFrequencyResponse `json:"frequency,omitempty"`
	IconIOS      string                `json:"icon_ios"`
	IconAndroid  string                `json:"icon_android"`
	Tags         string                `json:"tags"`
	DisplayOrder int                   `json:"display_order"`
	IsActive     bool                  `json:"is_active"`
}

// CreateUpdateTaskTemplateRequest represents the request body for creating/updating templates
type CreateUpdateTaskTemplateRequest struct {
	Title        string `json:"title" validate:"required,max=200"`
	Description  string `json:"description"`
	CategoryID   *uint  `json:"category_id"`
	FrequencyID  *uint  `json:"frequency_id"`
	IconIOS      string `json:"icon_ios" validate:"max=100"`
	IconAndroid  string `json:"icon_android" validate:"max=100"`
	Tags         string `json:"tags"`
	DisplayOrder *int   `json:"display_order"`
	IsActive     *bool  `json:"is_active"`
}

// ListTemplates handles GET /admin/api/task-templates/
func (h *AdminTaskTemplateHandler) ListTemplates(c echo.Context) error {
	var templates []models.TaskTemplate
	query := h.db.Preload("Category").Preload("Frequency").Order("display_order ASC, title ASC")

	// Optional filter by active status
	if activeParam := c.QueryParam("is_active"); activeParam != "" {
		isActive := activeParam == "true"
		query = query.Where("is_active = ?", isActive)
	}

	// Optional filter by category
	if categoryID := c.QueryParam("category_id"); categoryID != "" {
		query = query.Where("category_id = ?", categoryID)
	}

	// Optional filter by frequency
	if frequencyID := c.QueryParam("frequency_id"); frequencyID != "" {
		query = query.Where("frequency_id = ?", frequencyID)
	}

	// Optional search
	if search := c.QueryParam("search"); search != "" {
		searchTerm := "%" + strings.ToLower(search) + "%"
		query = query.Where("LOWER(title) LIKE ? OR LOWER(tags) LIKE ?", searchTerm, searchTerm)
	}

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

	responses := make([]TaskTemplateResponse, len(templates))
	for i, t := range templates {
		responses[i] = h.toResponse(&t)
	}

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

// GetTemplate handles GET /admin/api/task-templates/:id/
func (h *AdminTaskTemplateHandler) GetTemplate(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 template ID"})
	}

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

	return c.JSON(http.StatusOK, h.toResponse(&template))
}

// CreateTemplate handles POST /admin/api/task-templates/
func (h *AdminTaskTemplateHandler) CreateTemplate(c echo.Context) error {
	var req CreateUpdateTaskTemplateRequest
	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
	}

	template := models.TaskTemplate{
		Title:       req.Title,
		Description: req.Description,
		CategoryID:  req.CategoryID,
		FrequencyID: req.FrequencyID,
		IconIOS:     req.IconIOS,
		IconAndroid: req.IconAndroid,
		Tags:        req.Tags,
		IsActive:    true, // Default to active
	}

	if req.DisplayOrder != nil {
		template.DisplayOrder = *req.DisplayOrder
	}
	if req.IsActive != nil {
		template.IsActive = *req.IsActive
	}

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

	// Reload with preloads
	h.db.Preload("Category").Preload("Frequency").First(&template, template.ID)

	// Refresh cache after creating
	h.refreshTaskTemplatesCache(c.Request().Context())

	return c.JSON(http.StatusCreated, h.toResponse(&template))
}

// UpdateTemplate handles PUT /admin/api/task-templates/:id/
func (h *AdminTaskTemplateHandler) UpdateTemplate(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 template ID"})
	}

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

	var req CreateUpdateTaskTemplateRequest
	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
	}

	template.Title = req.Title
	template.Description = req.Description
	template.CategoryID = req.CategoryID
	template.FrequencyID = req.FrequencyID
	template.IconIOS = req.IconIOS
	template.IconAndroid = req.IconAndroid
	template.Tags = req.Tags

	if req.DisplayOrder != nil {
		template.DisplayOrder = *req.DisplayOrder
	}
	if req.IsActive != nil {
		template.IsActive = *req.IsActive
	}

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

	// Reload with preloads
	h.db.Preload("Category").Preload("Frequency").First(&template, template.ID)

	// Refresh cache after updating
	h.refreshTaskTemplatesCache(c.Request().Context())

	return c.JSON(http.StatusOK, h.toResponse(&template))
}

// DeleteTemplate handles DELETE /admin/api/task-templates/:id/
func (h *AdminTaskTemplateHandler) DeleteTemplate(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 template ID"})
	}

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

	// Refresh cache after deleting
	h.refreshTaskTemplatesCache(c.Request().Context())

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

// ToggleActive handles POST /admin/api/task-templates/:id/toggle-active/
func (h *AdminTaskTemplateHandler) ToggleActive(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 template ID"})
	}

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

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

	// Reload with preloads
	h.db.Preload("Category").Preload("Frequency").First(&template, template.ID)

	// Refresh cache after toggling active status
	h.refreshTaskTemplatesCache(c.Request().Context())

	return c.JSON(http.StatusOK, h.toResponse(&template))
}

// BulkCreate handles POST /admin/api/task-templates/bulk/
func (h *AdminTaskTemplateHandler) BulkCreate(c echo.Context) error {
	var req struct {
		Templates []CreateUpdateTaskTemplateRequest `json:"templates" validate:"required,dive"`
	}
	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
	}

	templates := make([]models.TaskTemplate, len(req.Templates))
	for i, t := range req.Templates {
		templates[i] = models.TaskTemplate{
			Title:       t.Title,
			Description: t.Description,
			CategoryID:  t.CategoryID,
			FrequencyID: t.FrequencyID,
			IconIOS:     t.IconIOS,
			IconAndroid: t.IconAndroid,
			Tags:        t.Tags,
			IsActive:    true,
		}
		if t.DisplayOrder != nil {
			templates[i].DisplayOrder = *t.DisplayOrder
		}
		if t.IsActive != nil {
			templates[i].IsActive = *t.IsActive
		}
	}

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

	// Refresh cache after bulk creating
	h.refreshTaskTemplatesCache(c.Request().Context())

	return c.JSON(http.StatusCreated, map[string]interface{}{"message": "Templates created successfully", "count": len(templates)})
}

// Helper to convert model to response
func (h *AdminTaskTemplateHandler) toResponse(t *models.TaskTemplate) TaskTemplateResponse {
	resp := TaskTemplateResponse{
		ID:           t.ID,
		Title:        t.Title,
		Description:  t.Description,
		CategoryID:   t.CategoryID,
		FrequencyID:  t.FrequencyID,
		IconIOS:      t.IconIOS,
		IconAndroid:  t.IconAndroid,
		Tags:         t.Tags,
		DisplayOrder: t.DisplayOrder,
		IsActive:     t.IsActive,
	}

	if t.Category != nil {
		resp.Category = &TaskCategoryResponse{
			ID:           t.Category.ID,
			Name:         t.Category.Name,
			Description:  t.Category.Description,
			Icon:         t.Category.Icon,
			Color:        t.Category.Color,
			DisplayOrder: t.Category.DisplayOrder,
		}
	}

	if t.Frequency != nil {
		resp.Frequency = &TaskFrequencyResponse{
			ID:           t.Frequency.ID,
			Name:         t.Frequency.Name,
			Days:         t.Frequency.Days,
			DisplayOrder: t.Frequency.DisplayOrder,
		}
	}

	return resp
}
