package handlers

import (
	"net/http"
	"strconv"

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

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

// AdminCompletionImageHandler handles admin task completion image management endpoints
type AdminCompletionImageHandler struct {
	db *gorm.DB
}

// NewAdminCompletionImageHandler creates a new admin completion image handler
func NewAdminCompletionImageHandler(db *gorm.DB) *AdminCompletionImageHandler {
	return &AdminCompletionImageHandler{db: db}
}

// AdminCompletionImageResponse represents the response for a task completion image in admin
type AdminCompletionImageResponse struct {
	ID           uint   `json:"id"`
	CompletionID uint   `json:"completion_id"`
	TaskID       uint   `json:"task_id"`
	TaskTitle    string `json:"task_title"`
	ImageURL     string `json:"image_url"`
	Caption      string `json:"caption"`
	CreatedAt    string `json:"created_at"`
	UpdatedAt    string `json:"updated_at"`
}

// CreateCompletionImageRequest represents the request to create a completion image
type CreateCompletionImageRequest struct {
	CompletionID uint   `json:"completion_id" validate:"required"`
	ImageURL     string `json:"image_url" validate:"required"`
	Caption      string `json:"caption"`
}

// UpdateCompletionImageRequest represents the request to update a completion image
type UpdateCompletionImageRequest struct {
	ImageURL *string `json:"image_url"`
	Caption  *string `json:"caption"`
}

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

	// Optional completion_id filter
	completionIDStr := c.QueryParam("completion_id")

	var images []models.TaskCompletionImage
	var total int64

	query := h.db.Model(&models.TaskCompletionImage{})

	// Apply completion_id filter if provided
	if completionIDStr != "" {
		completionID, err := strconv.ParseUint(completionIDStr, 10, 32)
		if err == nil {
			query = query.Where("completion_id = ?", completionID)
		}
	}

	// Apply search
	if filters.Search != "" {
		search := "%" + filters.Search + "%"
		query = query.Where("image_url ILIKE ? OR caption ILIKE ?", search, search)
	}

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

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

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

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

	// Batch-load completion+task info to avoid N+1 queries
	completionIDs := make([]uint, 0, len(images))
	for _, img := range images {
		completionIDs = append(completionIDs, img.CompletionID)
	}

	completionMap := make(map[uint]models.TaskCompletion)
	if len(completionIDs) > 0 {
		var completions []models.TaskCompletion
		h.db.Preload("Task").Where("id IN ?", completionIDs).Find(&completions)
		for _, c := range completions {
			completionMap[c.ID] = c
		}
	}

	// Build response with task info
	responses := make([]AdminCompletionImageResponse, len(images))
	for i, image := range images {
		response := AdminCompletionImageResponse{
			ID:           image.ID,
			CompletionID: image.CompletionID,
			ImageURL:     image.ImageURL,
			Caption:      image.Caption,
			CreatedAt:    image.CreatedAt.Format("2006-01-02T15:04:05Z"),
			UpdatedAt:    image.UpdatedAt.Format("2006-01-02T15:04:05Z"),
		}
		if comp, ok := completionMap[image.CompletionID]; ok {
			response.TaskID = comp.TaskID
			if comp.Task.ID != 0 {
				response.TaskTitle = comp.Task.Title
			}
		}
		responses[i] = response
	}

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

// Get handles GET /api/admin/completion-images/:id
func (h *AdminCompletionImageHandler) 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 image ID"})
	}

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

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

// Create handles POST /api/admin/completion-images
func (h *AdminCompletionImageHandler) Create(c echo.Context) error {
	var req CreateCompletionImageRequest
	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
	}

	// Verify completion exists
	var completion models.TaskCompletion
	if err := h.db.First(&completion, req.CompletionID).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Task completion not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to verify completion"})
	}

	image := models.TaskCompletionImage{
		CompletionID: req.CompletionID,
		ImageURL:     req.ImageURL,
		Caption:      req.Caption,
	}

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

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

// Update handles PUT /api/admin/completion-images/:id
func (h *AdminCompletionImageHandler) 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 image ID"})
	}

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

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

	if req.ImageURL != nil {
		image.ImageURL = *req.ImageURL
	}
	if req.Caption != nil {
		image.Caption = *req.Caption
	}

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

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

// Delete handles DELETE /api/admin/completion-images/:id
func (h *AdminCompletionImageHandler) Delete(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 image ID"})
	}

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

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

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

// BulkDelete handles DELETE /api/admin/completion-images/bulk
func (h *AdminCompletionImageHandler) BulkDelete(c echo.Context) error {
	var req dto.BulkDeleteRequest
	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}

	result := h.db.Where("id IN ?", req.IDs).Delete(&models.TaskCompletionImage{})
	if result.Error != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete completion images"})
	}

	return c.JSON(http.StatusOK, map[string]interface{}{"message": "Completion images deleted successfully", "count": result.RowsAffected})
}

// toResponse converts a TaskCompletionImage model to AdminCompletionImageResponse
func (h *AdminCompletionImageHandler) toResponse(image *models.TaskCompletionImage) AdminCompletionImageResponse {
	response := AdminCompletionImageResponse{
		ID:           image.ID,
		CompletionID: image.CompletionID,
		ImageURL:     image.ImageURL,
		Caption:      image.Caption,
		CreatedAt:    image.CreatedAt.Format("2006-01-02T15:04:05Z"),
		UpdatedAt:    image.UpdatedAt.Format("2006-01-02T15:04:05Z"),
	}

	// Get task info via completion
	var completion models.TaskCompletion
	if err := h.db.Preload("Task").First(&completion, image.CompletionID).Error; err == nil {
		response.TaskID = completion.TaskID
		if completion.Task.ID != 0 {
			response.TaskTitle = completion.Task.Title
		}
	}

	return response
}
