package handlers

import (
	"net/http"
	"strings"

	"github.com/labstack/echo/v4"
	"github.com/redis/go-redis/v9"
	"github.com/rs/zerolog/log"

	"github.com/treytartt/honeydue-api/internal/dto/responses"
	"github.com/treytartt/honeydue-api/internal/i18n"
	"github.com/treytartt/honeydue-api/internal/services"
)

// SeededDataResponse represents the unified seeded data response
type SeededDataResponse struct {
	ResidenceTypes        interface{}                            `json:"residence_types"`
	TaskCategories        interface{}                            `json:"task_categories"`
	TaskPriorities        interface{}                            `json:"task_priorities"`
	TaskFrequencies       interface{}                            `json:"task_frequencies"`
	ContractorSpecialties interface{}                            `json:"contractor_specialties"`
	TaskTemplates         responses.TaskTemplatesGroupedResponse `json:"task_templates"`
}

// StaticDataHandler handles static/lookup data endpoints
type StaticDataHandler struct {
	residenceService    *services.ResidenceService
	taskService         *services.TaskService
	contractorService   *services.ContractorService
	taskTemplateService *services.TaskTemplateService
	cache               *services.CacheService
}

// NewStaticDataHandler creates a new static data handler
func NewStaticDataHandler(
	residenceService *services.ResidenceService,
	taskService *services.TaskService,
	contractorService *services.ContractorService,
	taskTemplateService *services.TaskTemplateService,
	cache *services.CacheService,
) *StaticDataHandler {
	return &StaticDataHandler{
		residenceService:    residenceService,
		taskService:         taskService,
		contractorService:   contractorService,
		taskTemplateService: taskTemplateService,
		cache:               cache,
	}
}

// GetStaticData handles GET /api/static_data/
// Returns all lookup/reference data in a single response with ETag support
func (h *StaticDataHandler) GetStaticData(c echo.Context) error {
	ctx := c.Request().Context()

	// Check If-None-Match header for conditional request
	// Strip W/ prefix if present (added by reverse proxy, but we store without it)
	clientETag := strings.TrimPrefix(c.Request().Header.Get("If-None-Match"), "W/")

	// Try to get cached ETag first (fast path for 304 responses)
	if h.cache != nil && clientETag != "" {
		cachedETag, err := h.cache.GetSeededDataETag(ctx)
		if err == nil && cachedETag == clientETag {
			// Client has the latest data, return 304 Not Modified
			return c.NoContent(http.StatusNotModified)
		}
	}

	// Try to get cached seeded data
	if h.cache != nil {
		var cachedData SeededDataResponse
		err := h.cache.GetCachedSeededData(ctx, &cachedData)
		if err == nil {
			// Cache hit - get the ETag and return data
			etag, etagErr := h.cache.GetSeededDataETag(ctx)
			if etagErr == nil {
				c.Response().Header().Set("ETag", etag)
				c.Response().Header().Set("Cache-Control", "private, max-age=3600")
			}
			return c.JSON(http.StatusOK, cachedData)
		} else if err != redis.Nil {
			// Log cache error but continue to fetch from DB
			log.Warn().Err(err).Msg("Failed to get cached seeded data")
		}
	}

	// Cache miss - fetch all data from services
	residenceTypes, err := h.residenceService.GetResidenceTypes()
	if err != nil {
		return err
	}

	taskCategories, err := h.taskService.GetCategories()
	if err != nil {
		return err
	}

	taskPriorities, err := h.taskService.GetPriorities()
	if err != nil {
		return err
	}

	taskFrequencies, err := h.taskService.GetFrequencies()
	if err != nil {
		return err
	}

	contractorSpecialties, err := h.contractorService.GetSpecialties()
	if err != nil {
		return err
	}

	taskTemplates, err := h.taskTemplateService.GetGrouped()
	if err != nil {
		return err
	}

	// Build response
	seededData := SeededDataResponse{
		ResidenceTypes:        residenceTypes,
		TaskCategories:        taskCategories,
		TaskPriorities:        taskPriorities,
		TaskFrequencies:       taskFrequencies,
		ContractorSpecialties: contractorSpecialties,
		TaskTemplates:         taskTemplates,
	}

	// Cache the data and get ETag
	if h.cache != nil {
		etag, cacheErr := h.cache.CacheSeededData(ctx, seededData)
		if cacheErr != nil {
			log.Warn().Err(cacheErr).Msg("Failed to cache seeded data")
		} else {
			c.Response().Header().Set("ETag", etag)
			c.Response().Header().Set("Cache-Control", "private, max-age=3600")
		}
	}

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

// RefreshStaticData handles POST /api/static_data/refresh/
// This is a no-op since data is fetched fresh each time
// Kept for API compatibility with mobile clients
func (h *StaticDataHandler) RefreshStaticData(c echo.Context) error {
	return c.JSON(http.StatusOK, map[string]interface{}{
		"message": i18n.LocalizedMessage(c, "message.static_data_refreshed"),
		"status":  "success",
	})
}
