package handlers

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

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

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

// AdminLookupHandler handles admin lookup table management endpoints
type AdminLookupHandler struct {
	db *gorm.DB
}

// NewAdminLookupHandler creates a new admin lookup handler
func NewAdminLookupHandler(db *gorm.DB) *AdminLookupHandler {
	return &AdminLookupHandler{db: db}
}

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

	var categories []models.TaskCategory
	if err := h.db.Order("display_order ASC, name ASC").Find(&categories).Error; err != nil {
		log.Warn().Err(err).Msg("Failed to fetch categories for cache refresh")
	}

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

	// Invalidate unified seeded data cache
	h.invalidateSeededDataCache(ctx)
}

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

	var priorities []models.TaskPriority
	if err := h.db.Order("display_order ASC, level ASC").Find(&priorities).Error; err != nil {
		log.Warn().Err(err).Msg("Failed to fetch priorities for cache refresh")
	}

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

	// Invalidate unified seeded data cache
	h.invalidateSeededDataCache(ctx)
}

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

	var frequencies []models.TaskFrequency
	if err := h.db.Order("display_order ASC, name ASC").Find(&frequencies).Error; err != nil {
		log.Warn().Err(err).Msg("Failed to fetch frequencies for cache refresh")
	}

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

	// Invalidate unified seeded data cache
	h.invalidateSeededDataCache(ctx)
}

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

	var types []models.ResidenceType
	if err := h.db.Order("name ASC").Find(&types).Error; err != nil {
		log.Warn().Err(err).Msg("Failed to fetch residence types for cache refresh")
	}

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

	// Invalidate unified seeded data cache
	h.invalidateSeededDataCache(ctx)
}

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

	var specialties []models.ContractorSpecialty
	if err := h.db.Order("display_order ASC, name ASC").Find(&specialties).Error; err != nil {
		log.Warn().Err(err).Msg("Failed to fetch specialties for cache refresh")
	}

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

	// Invalidate unified seeded data cache
	h.invalidateSeededDataCache(ctx)
}

// invalidateSeededDataCache invalidates the unified seeded data cache
// This should be called whenever any lookup data changes
func (h *AdminLookupHandler) invalidateSeededDataCache(ctx context.Context) {
	cache := services.GetCache()
	if cache == nil {
		log.Warn().Msg("Cache service unavailable, skipping seeded data cache invalidation")
		return
	}

	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")
}

// ========== Task Categories ==========

type TaskCategoryResponse struct {
	ID           uint   `json:"id"`
	Name         string `json:"name"`
	Description  string `json:"description"`
	Icon         string `json:"icon"`
	Color        string `json:"color"`
	DisplayOrder int    `json:"display_order"`
}

type CreateUpdateCategoryRequest struct {
	Name         string `json:"name" validate:"required,max=50"`
	Description  string `json:"description"`
	Icon         string `json:"icon" validate:"max=50"`
	Color        string `json:"color" validate:"max=7"`
	DisplayOrder *int   `json:"display_order"`
}

func (h *AdminLookupHandler) ListCategories(c echo.Context) error {
	var categories []models.TaskCategory
	if err := h.db.Order("display_order ASC, name ASC").Find(&categories).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch categories"})
	}

	responses := make([]TaskCategoryResponse, len(categories))
	for i, cat := range categories {
		responses[i] = TaskCategoryResponse{
			ID:           cat.ID,
			Name:         cat.Name,
			Description:  cat.Description,
			Icon:         cat.Icon,
			Color:        cat.Color,
			DisplayOrder: cat.DisplayOrder,
		}
	}

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

func (h *AdminLookupHandler) CreateCategory(c echo.Context) error {
	var req CreateUpdateCategoryRequest
	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
	}

	category := models.TaskCategory{
		Name:        req.Name,
		Description: req.Description,
		Icon:        req.Icon,
		Color:       req.Color,
	}
	if req.DisplayOrder != nil {
		category.DisplayOrder = *req.DisplayOrder
	}

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

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

	return c.JSON(http.StatusCreated, TaskCategoryResponse{
		ID:           category.ID,
		Name:         category.Name,
		Description:  category.Description,
		Icon:         category.Icon,
		Color:        category.Color,
		DisplayOrder: category.DisplayOrder,
	})
}

func (h *AdminLookupHandler) UpdateCategory(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 category ID"})
	}

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

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

	category.Name = req.Name
	category.Description = req.Description
	category.Icon = req.Icon
	category.Color = req.Color
	if req.DisplayOrder != nil {
		category.DisplayOrder = *req.DisplayOrder
	}

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

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

	return c.JSON(http.StatusOK, TaskCategoryResponse{
		ID:           category.ID,
		Name:         category.Name,
		Description:  category.Description,
		Icon:         category.Icon,
		Color:        category.Color,
		DisplayOrder: category.DisplayOrder,
	})
}

func (h *AdminLookupHandler) DeleteCategory(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 category ID"})
	}

	// Check if category is in use
	var count int64
	h.db.Model(&models.Task{}).Where("category_id = ?", id).Count(&count)
	if count > 0 {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Cannot delete category that is in use by tasks"})
	}

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

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

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

// ========== Task Priorities ==========

type TaskPriorityResponse struct {
	ID           uint   `json:"id"`
	Name         string `json:"name"`
	Level        int    `json:"level"`
	Color        string `json:"color"`
	DisplayOrder int    `json:"display_order"`
}

type CreateUpdatePriorityRequest struct {
	Name         string `json:"name" validate:"required,max=20"`
	Level        int    `json:"level" validate:"required,min=1,max=10"`
	Color        string `json:"color" validate:"max=7"`
	DisplayOrder *int   `json:"display_order"`
}

func (h *AdminLookupHandler) ListPriorities(c echo.Context) error {
	var priorities []models.TaskPriority
	if err := h.db.Order("display_order ASC, level ASC").Find(&priorities).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch priorities"})
	}

	responses := make([]TaskPriorityResponse, len(priorities))
	for i, p := range priorities {
		responses[i] = TaskPriorityResponse{
			ID:           p.ID,
			Name:         p.Name,
			Level:        p.Level,
			Color:        p.Color,
			DisplayOrder: p.DisplayOrder,
		}
	}

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

func (h *AdminLookupHandler) CreatePriority(c echo.Context) error {
	var req CreateUpdatePriorityRequest
	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
	}

	priority := models.TaskPriority{
		Name:  req.Name,
		Level: req.Level,
		Color: req.Color,
	}
	if req.DisplayOrder != nil {
		priority.DisplayOrder = *req.DisplayOrder
	}

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

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

	return c.JSON(http.StatusCreated, TaskPriorityResponse{
		ID:           priority.ID,
		Name:         priority.Name,
		Level:        priority.Level,
		Color:        priority.Color,
		DisplayOrder: priority.DisplayOrder,
	})
}

func (h *AdminLookupHandler) UpdatePriority(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 priority ID"})
	}

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

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

	priority.Name = req.Name
	priority.Level = req.Level
	priority.Color = req.Color
	if req.DisplayOrder != nil {
		priority.DisplayOrder = *req.DisplayOrder
	}

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

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

	return c.JSON(http.StatusOK, TaskPriorityResponse{
		ID:           priority.ID,
		Name:         priority.Name,
		Level:        priority.Level,
		Color:        priority.Color,
		DisplayOrder: priority.DisplayOrder,
	})
}

func (h *AdminLookupHandler) DeletePriority(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 priority ID"})
	}

	var count int64
	h.db.Model(&models.Task{}).Where("priority_id = ?", id).Count(&count)
	if count > 0 {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Cannot delete priority that is in use by tasks"})
	}

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

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

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

// ========== Task Frequencies ==========

type TaskFrequencyResponse struct {
	ID                   uint   `json:"id"`
	Name                 string `json:"name"`
	Days                 *int   `json:"days"`
	DisplayOrder         int    `json:"display_order"`
	NotificationSchedule string `json:"notification_schedule"`
	ReminderDays         []int  `json:"reminder_days"`
}

type CreateUpdateFrequencyRequest struct {
	Name         string `json:"name" validate:"required,max=20"`
	Days         *int   `json:"days"`
	DisplayOrder *int   `json:"display_order"`
}

func (h *AdminLookupHandler) ListFrequencies(c echo.Context) error {
	var frequencies []models.TaskFrequency
	if err := h.db.Order("display_order ASC, name ASC").Find(&frequencies).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch frequencies"})
	}

	responses := make([]TaskFrequencyResponse, len(frequencies))
	for i, f := range frequencies {
		// Get notification schedule for this frequency
		schedule := notifications.GetScheduleForFrequency(f.Days)
		humanReadable := notifications.GetHumanReadableSchedule(f.Days)

		responses[i] = TaskFrequencyResponse{
			ID:                   f.ID,
			Name:                 f.Name,
			Days:                 f.Days,
			DisplayOrder:         f.DisplayOrder,
			NotificationSchedule: humanReadable,
			ReminderDays:         schedule,
		}
	}

	// Include overdue policy in response
	overduePolicy := map[string]interface{}{
		"daily_reminder_days": notifications.OverdueConfig.DailyReminderDays,
		"taper_interval_days": notifications.OverdueConfig.TaperIntervalDays,
		"max_overdue_days":    notifications.OverdueConfig.MaxOverdueDays,
		"description":         "Daily for first " + strconv.Itoa(notifications.OverdueConfig.DailyReminderDays) + " days, then every " + strconv.Itoa(notifications.OverdueConfig.TaperIntervalDays) + " days, stops after " + strconv.Itoa(notifications.OverdueConfig.MaxOverdueDays) + " days",
		"overdue_days":        notifications.GetOverdueReminderDays(),
	}

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

func (h *AdminLookupHandler) CreateFrequency(c echo.Context) error {
	var req CreateUpdateFrequencyRequest
	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
	}

	frequency := models.TaskFrequency{
		Name: req.Name,
		Days: req.Days,
	}
	if req.DisplayOrder != nil {
		frequency.DisplayOrder = *req.DisplayOrder
	}

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

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

	// Get notification schedule for this frequency
	schedule := notifications.GetScheduleForFrequency(frequency.Days)
	humanReadable := notifications.GetHumanReadableSchedule(frequency.Days)

	return c.JSON(http.StatusCreated, TaskFrequencyResponse{
		ID:                   frequency.ID,
		Name:                 frequency.Name,
		Days:                 frequency.Days,
		DisplayOrder:         frequency.DisplayOrder,
		NotificationSchedule: humanReadable,
		ReminderDays:         schedule,
	})
}

func (h *AdminLookupHandler) UpdateFrequency(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 frequency ID"})
	}

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

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

	frequency.Name = req.Name
	frequency.Days = req.Days
	if req.DisplayOrder != nil {
		frequency.DisplayOrder = *req.DisplayOrder
	}

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

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

	// Get notification schedule for this frequency
	schedule := notifications.GetScheduleForFrequency(frequency.Days)
	humanReadable := notifications.GetHumanReadableSchedule(frequency.Days)

	return c.JSON(http.StatusOK, TaskFrequencyResponse{
		ID:                   frequency.ID,
		Name:                 frequency.Name,
		Days:                 frequency.Days,
		DisplayOrder:         frequency.DisplayOrder,
		NotificationSchedule: humanReadable,
		ReminderDays:         schedule,
	})
}

func (h *AdminLookupHandler) DeleteFrequency(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 frequency ID"})
	}

	var count int64
	h.db.Model(&models.Task{}).Where("frequency_id = ?", id).Count(&count)
	if count > 0 {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Cannot delete frequency that is in use by tasks"})
	}

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

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

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

// ========== Residence Types ==========

type ResidenceTypeResponse struct {
	ID   uint   `json:"id"`
	Name string `json:"name"`
}

type CreateUpdateResidenceTypeRequest struct {
	Name string `json:"name" validate:"required,max=20"`
}

func (h *AdminLookupHandler) ListResidenceTypes(c echo.Context) error {
	var types []models.ResidenceType
	if err := h.db.Order("name ASC").Find(&types).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch residence types"})
	}

	responses := make([]ResidenceTypeResponse, len(types))
	for i, t := range types {
		responses[i] = ResidenceTypeResponse{
			ID:   t.ID,
			Name: t.Name,
		}
	}

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

func (h *AdminLookupHandler) CreateResidenceType(c echo.Context) error {
	var req CreateUpdateResidenceTypeRequest
	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
	}

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

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

	return c.JSON(http.StatusCreated, ResidenceTypeResponse{
		ID:   residenceType.ID,
		Name: residenceType.Name,
	})
}

func (h *AdminLookupHandler) UpdateResidenceType(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 residence type ID"})
	}

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

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

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

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

	return c.JSON(http.StatusOK, ResidenceTypeResponse{
		ID:   residenceType.ID,
		Name: residenceType.Name,
	})
}

func (h *AdminLookupHandler) DeleteResidenceType(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 residence type ID"})
	}

	var count int64
	h.db.Model(&models.Residence{}).Where("property_type_id = ?", id).Count(&count)
	if count > 0 {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Cannot delete residence type that is in use"})
	}

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

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

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

// ========== Contractor Specialties ==========

type ContractorSpecialtyResponse struct {
	ID           uint   `json:"id"`
	Name         string `json:"name"`
	Description  string `json:"description"`
	Icon         string `json:"icon"`
	DisplayOrder int    `json:"display_order"`
}

type CreateUpdateSpecialtyRequest struct {
	Name         string `json:"name" validate:"required,max=50"`
	Description  string `json:"description"`
	Icon         string `json:"icon" validate:"max=50"`
	DisplayOrder *int   `json:"display_order"`
}

func (h *AdminLookupHandler) ListSpecialties(c echo.Context) error {
	var specialties []models.ContractorSpecialty
	if err := h.db.Order("display_order ASC, name ASC").Find(&specialties).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch specialties"})
	}

	responses := make([]ContractorSpecialtyResponse, len(specialties))
	for i, s := range specialties {
		responses[i] = ContractorSpecialtyResponse{
			ID:           s.ID,
			Name:         s.Name,
			Description:  s.Description,
			Icon:         s.Icon,
			DisplayOrder: s.DisplayOrder,
		}
	}

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

func (h *AdminLookupHandler) CreateSpecialty(c echo.Context) error {
	var req CreateUpdateSpecialtyRequest
	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
	}

	specialty := models.ContractorSpecialty{
		Name:        req.Name,
		Description: req.Description,
		Icon:        req.Icon,
	}
	if req.DisplayOrder != nil {
		specialty.DisplayOrder = *req.DisplayOrder
	}

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

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

	return c.JSON(http.StatusCreated, ContractorSpecialtyResponse{
		ID:           specialty.ID,
		Name:         specialty.Name,
		Description:  specialty.Description,
		Icon:         specialty.Icon,
		DisplayOrder: specialty.DisplayOrder,
	})
}

func (h *AdminLookupHandler) UpdateSpecialty(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 specialty ID"})
	}

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

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

	specialty.Name = req.Name
	specialty.Description = req.Description
	specialty.Icon = req.Icon
	if req.DisplayOrder != nil {
		specialty.DisplayOrder = *req.DisplayOrder
	}

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

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

	return c.JSON(http.StatusOK, ContractorSpecialtyResponse{
		ID:           specialty.ID,
		Name:         specialty.Name,
		Description:  specialty.Description,
		Icon:         specialty.Icon,
		DisplayOrder: specialty.DisplayOrder,
	})
}

func (h *AdminLookupHandler) DeleteSpecialty(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 specialty ID"})
	}

	// Check if in use via many-to-many relationship
	var count int64
	h.db.Table("task_contractor_specialties").Where("contractorspecialty_id = ?", id).Count(&count)
	if count > 0 {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Cannot delete specialty that is in use by contractors"})
	}

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

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

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

// ========== Notification Schedules ==========

// FrequencyScheduleResponse represents a frequency with its notification schedule
type FrequencyScheduleResponse struct {
	ID                   uint   `json:"id"`
	Name                 string `json:"name"`
	Days                 *int   `json:"days"`
	NotificationSchedule string `json:"notification_schedule"`
	ReminderDays         []int  `json:"reminder_days"`
}

// OverduePolicyResponse represents the overdue reminder policy
type OverduePolicyResponse struct {
	DailyReminderDays int    `json:"daily_reminder_days"`
	TaperIntervalDays int    `json:"taper_interval_days"`
	MaxOverdueDays    int    `json:"max_overdue_days"`
	Description       string `json:"description"`
	OverdueDays       []int  `json:"overdue_days"`
}

// NotificationSchedulesResponse is the full response for notification schedules
type NotificationSchedulesResponse struct {
	Frequencies   []FrequencyScheduleResponse `json:"frequencies"`
	OverduePolicy OverduePolicyResponse       `json:"overdue_policy"`
}

// GetNotificationSchedules handles GET /api/admin/lookups/notification-schedules
// Returns the notification schedule configuration for all frequencies
func (h *AdminLookupHandler) GetNotificationSchedules(c echo.Context) error {
	// Get all frequencies from database
	var frequencies []models.TaskFrequency
	if err := h.db.Order("display_order ASC, name ASC").Find(&frequencies).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch frequencies"})
	}

	// Build frequency schedules with notification info
	frequencyResponses := make([]FrequencyScheduleResponse, len(frequencies))
	for i, f := range frequencies {
		// Get the notification schedule for this frequency's days
		schedule := notifications.GetScheduleForFrequency(f.Days)
		humanReadable := notifications.GetHumanReadableSchedule(f.Days)

		frequencyResponses[i] = FrequencyScheduleResponse{
			ID:                   f.ID,
			Name:                 f.Name,
			Days:                 f.Days,
			NotificationSchedule: humanReadable,
			ReminderDays:         schedule,
		}
	}

	// Build overdue policy response
	overduePolicy := OverduePolicyResponse{
		DailyReminderDays: notifications.OverdueConfig.DailyReminderDays,
		TaperIntervalDays: notifications.OverdueConfig.TaperIntervalDays,
		MaxOverdueDays:    notifications.OverdueConfig.MaxOverdueDays,
		Description:       "Daily for first " + strconv.Itoa(notifications.OverdueConfig.DailyReminderDays) + " days, then every " + strconv.Itoa(notifications.OverdueConfig.TaperIntervalDays) + " days, stops after " + strconv.Itoa(notifications.OverdueConfig.MaxOverdueDays) + " days",
		OverdueDays:       notifications.GetOverdueReminderDays(),
	}

	response := NotificationSchedulesResponse{
		Frequencies:   frequencyResponses,
		OverduePolicy: overduePolicy,
	}

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

// Ensure dto import is used
var _ = dto.PaginationParams{}
