package handlers

import (
	"net/http"
	"strconv"

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

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

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

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

// CompletionImageResponse represents an image in a completion
type CompletionImageResponse struct {
	ID       uint   `json:"id"`
	ImageURL string `json:"image_url"`
	Caption  string `json:"caption"`
}

// CompletionResponse represents a task completion in API responses
type CompletionResponse struct {
	ID            uint                      `json:"id"`
	TaskID        uint                      `json:"task_id"`
	TaskTitle     string                    `json:"task_title"`
	ResidenceID   uint                      `json:"residence_id"`
	ResidenceName string                    `json:"residence_name"`
	CompletedByID uint                      `json:"completed_by_id"`
	CompletedBy   string                    `json:"completed_by"`
	CompletedAt   string                    `json:"completed_at"`
	Notes         string                    `json:"notes"`
	ActualCost    *string                   `json:"actual_cost"`
	Rating        *int                      `json:"rating"`
	Images        []CompletionImageResponse `json:"images"`
	CreatedAt     string                    `json:"created_at"`
}

// CompletionFilters extends PaginationParams with completion-specific filters
type CompletionFilters struct {
	dto.PaginationParams
	TaskID      *uint `form:"task_id"`
	ResidenceID *uint `form:"residence_id"`
	UserID      *uint `form:"user_id"`
}

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

	var completions []models.TaskCompletion
	var total int64

	query := h.db.Model(&models.TaskCompletion{}).
		Preload("Task").
		Preload("Task.Residence").
		Preload("CompletedBy").
		Preload("Images")

	// Apply search
	if filters.Search != "" {
		search := "%" + filters.Search + "%"
		query = query.Joins("JOIN task_task ON task_task.id = task_taskcompletion.task_id").
			Joins("JOIN auth_user ON auth_user.id = task_taskcompletion.completed_by_id").
			Where(
				"task_task.title ILIKE ? OR auth_user.username ILIKE ? OR task_taskcompletion.notes ILIKE ?",
				search, search, search,
			)
	}

	// Apply filters
	if filters.TaskID != nil {
		query = query.Where("task_id = ?", *filters.TaskID)
	}
	if filters.ResidenceID != nil {
		query = query.Joins("JOIN task_task t ON t.id = task_taskcompletion.task_id").
			Where("t.residence_id = ?", *filters.ResidenceID)
	}
	if filters.UserID != nil {
		query = query.Where("completed_by_id = ?", *filters.UserID)
	}

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

	// Apply sorting (allowlist prevents SQL injection via sort_by parameter)
	sortBy := filters.GetSafeSortBy([]string{
		"id", "task_id", "completed_by_id", "completed_at",
		"created_at", "notes", "actual_cost", "rating",
	}, "completed_at")
	sortDir := "DESC"
	if filters.SortDir != "" {
		sortDir = filters.GetSortDir()
	}
	query = query.Order(sortBy + " " + sortDir)

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

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

	// Build response
	responses := make([]CompletionResponse, len(completions))
	for i, completion := range completions {
		responses[i] = h.toCompletionResponse(&completion)
	}

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

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

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

	return c.JSON(http.StatusOK, h.toCompletionResponse(&completion))
}

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

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

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

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

// BulkDelete handles DELETE /api/admin/completions/bulk
func (h *AdminCompletionHandler) 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.TaskCompletion{})
	if result.Error != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete completions"})
	}

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

// UpdateCompletionRequest represents the request to update a completion
type UpdateCompletionRequest struct {
	Notes      *string `json:"notes"`
	ActualCost *string `json:"actual_cost"`
}

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

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

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

	if req.Notes != nil {
		completion.Notes = *req.Notes
	}
	if req.ActualCost != nil {
		if *req.ActualCost == "" {
			completion.ActualCost = nil
		} else {
			cost, err := decimal.NewFromString(*req.ActualCost)
			if err == nil {
				completion.ActualCost = &cost
			}
		}
	}

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

	h.db.Preload("Task").Preload("Task.Residence").Preload("CompletedBy").Preload("Images").First(&completion, id)
	return c.JSON(http.StatusOK, h.toCompletionResponse(&completion))
}

// toCompletionResponse converts a TaskCompletion model to CompletionResponse
func (h *AdminCompletionHandler) toCompletionResponse(completion *models.TaskCompletion) CompletionResponse {
	response := CompletionResponse{
		ID:            completion.ID,
		TaskID:        completion.TaskID,
		CompletedByID: completion.CompletedByID,
		CompletedAt:   completion.CompletedAt.Format("2006-01-02T15:04:05Z"),
		Notes:         completion.Notes,
		Rating:        completion.Rating,
		Images:        make([]CompletionImageResponse, 0),
		CreatedAt:     completion.CreatedAt.Format("2006-01-02T15:04:05Z"),
	}

	if completion.Task.ID != 0 {
		response.TaskTitle = completion.Task.Title
		response.ResidenceID = completion.Task.ResidenceID
		if completion.Task.Residence.ID != 0 {
			response.ResidenceName = completion.Task.Residence.Name
		}
	}

	if completion.CompletedBy.ID != 0 {
		response.CompletedBy = completion.CompletedBy.Username
	}

	if completion.ActualCost != nil {
		cost := completion.ActualCost.String()
		response.ActualCost = &cost
	}

	// Convert images
	for _, img := range completion.Images {
		response.Images = append(response.Images, CompletionImageResponse{
			ID:       img.ID,
			ImageURL: img.ImageURL,
			Caption:  img.Caption,
		})
	}

	return response
}
