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

// AdminDocumentImageHandler handles admin document image management endpoints
type AdminDocumentImageHandler struct {
	db *gorm.DB
}

// NewAdminDocumentImageHandler creates a new admin document image handler
func NewAdminDocumentImageHandler(db *gorm.DB) *AdminDocumentImageHandler {
	return &AdminDocumentImageHandler{db: db}
}

// DocumentImageResponse represents the response for a document image
type DocumentImageResponse struct {
	ID            uint   `json:"id"`
	DocumentID    uint   `json:"document_id"`
	DocumentTitle string `json:"document_title"`
	ResidenceID   uint   `json:"residence_id"`
	ResidenceName string `json:"residence_name"`
	ImageURL      string `json:"image_url"`
	Caption       string `json:"caption"`
	CreatedAt     string `json:"created_at"`
	UpdatedAt     string `json:"updated_at"`
}

// CreateDocumentImageRequest represents the request to create a document image
type CreateDocumentImageRequest struct {
	DocumentID uint   `json:"document_id" validate:"required"`
	ImageURL   string `json:"image_url" validate:"required"`
	Caption    string `json:"caption"`
}

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

// List handles GET /api/admin/document-images
func (h *AdminDocumentImageHandler) 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 document_id filter
	documentIDStr := c.QueryParam("document_id")

	var images []models.DocumentImage
	var total int64

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

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

	// 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", "document_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 document images"})
	}

	// Build response with document info
	responses := make([]DocumentImageResponse, len(images))
	for i, image := range images {
		responses[i] = h.toResponse(&image)
	}

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

// Get handles GET /api/admin/document-images/:id
func (h *AdminDocumentImageHandler) 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.DocumentImage
	if err := h.db.First(&image, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Document image not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch document image"})
	}

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

// Create handles POST /api/admin/document-images
func (h *AdminDocumentImageHandler) Create(c echo.Context) error {
	var req CreateDocumentImageRequest
	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 document exists
	var document models.Document
	if err := h.db.First(&document, req.DocumentID).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Document not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to verify document"})
	}

	image := models.DocumentImage{
		DocumentID: req.DocumentID,
		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 document image"})
	}

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

// Update handles PUT /api/admin/document-images/:id
func (h *AdminDocumentImageHandler) 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.DocumentImage
	if err := h.db.First(&image, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Document image not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch document image"})
	}

	var req UpdateDocumentImageRequest
	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 document image"})
	}

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

// Delete handles DELETE /api/admin/document-images/:id
func (h *AdminDocumentImageHandler) 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.DocumentImage
	if err := h.db.First(&image, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Document image not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch document image"})
	}

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

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

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

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

// toResponse converts a DocumentImage model to DocumentImageResponse
func (h *AdminDocumentImageHandler) toResponse(image *models.DocumentImage) DocumentImageResponse {
	response := DocumentImageResponse{
		ID:         image.ID,
		DocumentID: image.DocumentID,
		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 document info
	var document models.Document
	if err := h.db.Preload("Residence").First(&document, image.DocumentID).Error; err == nil {
		response.DocumentTitle = document.Title
		response.ResidenceID = document.ResidenceID
		if document.Residence.ID != 0 {
			response.ResidenceName = document.Residence.Name
		}
	}

	return response
}
