package api

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/go-chi/chi/v5"
	"github.com/insertr/insertr/internal/auth"
	"github.com/insertr/insertr/internal/content"
	"github.com/insertr/insertr/internal/db"
	"github.com/insertr/insertr/internal/db/postgresql"
	"github.com/insertr/insertr/internal/db/sqlite"
	"github.com/insertr/insertr/internal/engine"
)

// ContentHandler handles all content-related HTTP requests
type ContentHandler struct {
	database    *db.Database
	authService *auth.AuthService
	siteManager *content.SiteManager
	engine      *engine.ContentEngine
}

// NewContentHandler creates a new content handler
func NewContentHandler(database *db.Database, authService *auth.AuthService) *ContentHandler {
	// Create database client for engine
	dbClient := engine.NewDatabaseClient(database)

	return &ContentHandler{
		database:    database,
		authService: authService,
		siteManager: nil, // Will be set via SetSiteManager
		engine:      engine.NewContentEngine(dbClient),
	}
}

// SetSiteManager sets the site manager for file enhancement
func (h *ContentHandler) SetSiteManager(siteManager *content.SiteManager) {
	h.siteManager = siteManager
}

// EnhanceSite handles POST /api/enhance - manual site enhancement trigger
func (h *ContentHandler) EnhanceSite(w http.ResponseWriter, r *http.Request) {
	siteID := r.URL.Query().Get("site_id")
	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	if h.siteManager == nil {
		http.Error(w, "Site manager not available", http.StatusServiceUnavailable)
		return
	}

	// Check if site is registered
	site, exists := h.siteManager.GetSite(siteID)
	if !exists {
		http.Error(w, fmt.Sprintf("Site %s is not registered", siteID), http.StatusNotFound)
		return
	}

	// Perform enhancement
	err := h.siteManager.EnhanceSite(siteID)
	if err != nil {
		log.Printf("❌ Manual enhancement failed for site %s: %v", siteID, err)
		http.Error(w, fmt.Sprintf("Enhancement failed: %v", err), http.StatusInternalServerError)
		return
	}

	// Get enhancement statistics
	stats := h.siteManager.GetStats()

	// Return success response with details
	response := map[string]interface{}{
		"success":   true,
		"site_id":   siteID,
		"site_path": site.Path,
		"message":   fmt.Sprintf("Successfully enhanced site %s", siteID),
		"stats":     stats,
		"timestamp": time.Now().Format(time.RFC3339),
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)

	log.Printf("✅ Manual enhancement completed for site %s", siteID)
}

// GetContent handles GET /api/content/{id}
func (h *ContentHandler) GetContent(w http.ResponseWriter, r *http.Request) {
	contentID := chi.URLParam(r, "id")
	siteID := r.URL.Query().Get("site_id")

	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	var content interface{}
	var err error

	switch h.database.GetDBType() {
	case "sqlite3":
		content, err = h.database.GetSQLiteQueries().GetContent(context.Background(), sqlite.GetContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
	case "postgresql":
		content, err = h.database.GetPostgreSQLQueries().GetContent(context.Background(), postgresql.GetContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Content not found", http.StatusNotFound)
			return
		}
		http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
		return
	}

	item := h.convertToAPIContent(content)

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(item)
}

// GetAllContent handles GET /api/content
func (h *ContentHandler) GetAllContent(w http.ResponseWriter, r *http.Request) {
	siteID := r.URL.Query().Get("site_id")
	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	var dbContent interface{}
	var err error

	switch h.database.GetDBType() {
	case "sqlite3":
		dbContent, err = h.database.GetSQLiteQueries().GetAllContent(context.Background(), siteID)
	case "postgresql":
		dbContent, err = h.database.GetPostgreSQLQueries().GetAllContent(context.Background(), siteID)
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
		return
	}

	items := h.convertToAPIContentList(dbContent)
	response := ContentResponse{Content: items}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

// GetBulkContent handles GET /api/content/bulk
func (h *ContentHandler) GetBulkContent(w http.ResponseWriter, r *http.Request) {
	siteID := r.URL.Query().Get("site_id")
	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	// Parse ids parameter
	idsParam := r.URL.Query()["ids[]"]
	if len(idsParam) == 0 {
		// Try single ids parameter
		idsStr := r.URL.Query().Get("ids")
		if idsStr == "" {
			http.Error(w, "ids parameter is required", http.StatusBadRequest)
			return
		}
		idsParam = strings.Split(idsStr, ",")
	}

	var dbContent interface{}
	var err error

	switch h.database.GetDBType() {
	case "sqlite3":
		dbContent, err = h.database.GetSQLiteQueries().GetBulkContent(context.Background(), sqlite.GetBulkContentParams{
			SiteID: siteID,
			Ids:    idsParam,
		})
	case "postgresql":
		dbContent, err = h.database.GetPostgreSQLQueries().GetBulkContent(context.Background(), postgresql.GetBulkContentParams{
			SiteID: siteID,
			Ids:    idsParam,
		})
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
		return
	}

	items := h.convertToAPIContentList(dbContent)
	response := ContentResponse{Content: items}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

// CreateContent handles POST /api/content
func (h *ContentHandler) CreateContent(w http.ResponseWriter, r *http.Request) {
	var req CreateContentRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid JSON", http.StatusBadRequest)
		return
	}

	siteID := r.URL.Query().Get("site_id")
	if siteID == "" {
		siteID = req.SiteID // fallback to request body
	}
	if siteID == "" || siteID == "__MISSING_SITE_ID__" {
		http.Error(w, "site_id parameter is required and must be configured", http.StatusBadRequest)
		return
	}

	// Generate content ID using the unified engine
	if req.HTMLMarkup == "" {
		http.Error(w, "html_markup is required", http.StatusBadRequest)
		return
	}

	result, engineErr := h.engine.ProcessContent(engine.ContentInput{
		HTML:     []byte(req.HTMLMarkup),
		FilePath: req.FilePath,
		SiteID:   siteID,
		Mode:     engine.IDGeneration,
	})
	if engineErr != nil {
		http.Error(w, fmt.Sprintf("ID generation failed: %v", engineErr), http.StatusInternalServerError)
		return
	}

	if len(result.Elements) == 0 {
		http.Error(w, "No insertr elements found in HTML markup", http.StatusBadRequest)
		return
	}

	// Use the ID generated by the engine for the first element
	contentID := result.Elements[0].ID

	// Extract user from request using authentication service
	userInfo, authErr := h.authService.ExtractUserFromRequest(r)
	if authErr != nil {
		http.Error(w, fmt.Sprintf("Authentication error: %v", authErr), http.StatusUnauthorized)
		return
	}
	userID := userInfo.ID

	// Check if content exists for version history (non-blocking)
	var existingContent interface{}
	var contentExists bool

	switch h.database.GetDBType() {
	case "sqlite3":
		existingContent, _ = h.database.GetSQLiteQueries().GetContent(context.Background(), sqlite.GetContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
		contentExists = existingContent != nil
	case "postgresql":
		existingContent, _ = h.database.GetPostgreSQLQueries().GetContent(context.Background(), postgresql.GetContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
		contentExists = existingContent != nil
	}

	// Archive existing version before upsert (only if content already exists)
	if contentExists {
		if err := h.createContentVersion(existingContent); err != nil {
			// Log error but don't fail the request - version history is non-critical
			fmt.Printf("Warning: Failed to create content version: %v\n", err)
		}
	}

	// HTML-first approach: no content type needed

	var content interface{}
	var err error

	switch h.database.GetDBType() {
	case "sqlite3":
		content, err = h.database.GetSQLiteQueries().UpsertContent(context.Background(), sqlite.UpsertContentParams{
			ID:               contentID,
			SiteID:           siteID,
			HtmlContent:      req.HTMLContent,
			OriginalTemplate: engine.ToNullString(req.OriginalTemplate),
			LastEditedBy:     userID,
		})
	case "postgresql":
		content, err = h.database.GetPostgreSQLQueries().UpsertContent(context.Background(), postgresql.UpsertContentParams{
			ID:               contentID,
			SiteID:           siteID,
			HtmlContent:      req.HTMLContent,
			OriginalTemplate: engine.ToNullString(req.OriginalTemplate),
			LastEditedBy:     userID,
		})
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to upsert content: %v", err), http.StatusInternalServerError)
		return
	}

	item := h.convertToAPIContent(content)

	// Trigger file enhancement if site is registered for auto-enhancement
	log.Printf("🔍 Checking auto-enhancement for site: %s", siteID)
	if h.siteManager == nil {
		log.Printf("❌ No site manager configured")
	} else if !h.siteManager.IsAutoEnhanceEnabled(siteID) {
		log.Printf("❌ Auto-enhancement not enabled for site: %s", siteID)
	} else {
		log.Printf("✅ Triggering auto-enhancement for site: %s", siteID)
		go func() {
			log.Printf("🔄 Starting enhancement for site: %s", siteID)
			if err := h.siteManager.EnhanceSite(siteID); err != nil {
				log.Printf("⚠️ Failed to enhance site %s: %v", siteID, err)
			} else {
				log.Printf("✅ Enhanced files for site %s", siteID)
			}
		}()
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(item)
}

// UpdateContent handles PUT /api/content/{id}
func (h *ContentHandler) UpdateContent(w http.ResponseWriter, r *http.Request) {
	contentID := chi.URLParam(r, "id")
	siteID := r.URL.Query().Get("site_id")

	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	var req struct {
		HTMLContent string `json:"html_content"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid JSON", http.StatusBadRequest)
		return
	}

	// Extract user from request using authentication service
	userInfo, authErr := h.authService.ExtractUserFromRequest(r)
	if authErr != nil {
		http.Error(w, fmt.Sprintf("Authentication error: %v", authErr), http.StatusUnauthorized)
		return
	}
	userID := userInfo.ID

	// Get existing content for version history
	var existingContent interface{}
	var err error

	switch h.database.GetDBType() {
	case "sqlite3":
		existingContent, err = h.database.GetSQLiteQueries().GetContent(context.Background(), sqlite.GetContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
	case "postgresql":
		existingContent, err = h.database.GetPostgreSQLQueries().GetContent(context.Background(), postgresql.GetContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Content not found", http.StatusNotFound)
			return
		}
		http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
		return
	}

	// Archive existing version before update
	if err := h.createContentVersion(existingContent); err != nil {
		fmt.Printf("Warning: Failed to create content version: %v\n", err)
	}

	// Update content
	var updatedContent interface{}

	switch h.database.GetDBType() {
	case "sqlite3":
		updatedContent, err = h.database.GetSQLiteQueries().UpdateContent(context.Background(), sqlite.UpdateContentParams{
			HtmlContent:  req.HTMLContent,
			LastEditedBy: userID,
			ID:           contentID,
			SiteID:       siteID,
		})
	case "postgresql":
		updatedContent, err = h.database.GetPostgreSQLQueries().UpdateContent(context.Background(), postgresql.UpdateContentParams{
			HtmlContent:  req.HTMLContent,
			LastEditedBy: userID,
			ID:           contentID,
			SiteID:       siteID,
		})
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to update content: %v", err), http.StatusInternalServerError)
		return
	}

	item := h.convertToAPIContent(updatedContent)

	// Trigger file enhancement if site is registered for auto-enhancement
	if h.siteManager != nil && h.siteManager.IsAutoEnhanceEnabled(siteID) {
		go func() {
			if err := h.siteManager.EnhanceSite(siteID); err != nil {
				log.Printf("⚠️ Failed to enhance site %s: %v", siteID, err)
			}
		}()
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(item)
}

// DeleteContent handles DELETE /api/content/{id}
func (h *ContentHandler) DeleteContent(w http.ResponseWriter, r *http.Request) {
	contentID := chi.URLParam(r, "id")
	siteID := r.URL.Query().Get("site_id")

	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	var err error

	switch h.database.GetDBType() {
	case "sqlite3":
		err = h.database.GetSQLiteQueries().DeleteContent(context.Background(), sqlite.DeleteContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
	case "postgresql":
		err = h.database.GetPostgreSQLQueries().DeleteContent(context.Background(), postgresql.DeleteContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to delete content: %v", err), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

// GetContentVersions handles GET /api/content/{id}/versions
func (h *ContentHandler) GetContentVersions(w http.ResponseWriter, r *http.Request) {
	contentID := chi.URLParam(r, "id")
	siteID := r.URL.Query().Get("site_id")

	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	// Parse limit parameter (default to 10)
	limit := int64(10)
	if limitStr := r.URL.Query().Get("limit"); limitStr != "" {
		if parsedLimit, err := strconv.ParseInt(limitStr, 10, 64); err == nil {
			limit = parsedLimit
		}
	}

	var dbVersions interface{}
	var err error

	switch h.database.GetDBType() {
	case "sqlite3":
		dbVersions, err = h.database.GetSQLiteQueries().GetContentVersionHistory(context.Background(), sqlite.GetContentVersionHistoryParams{
			ContentID:  contentID,
			SiteID:     siteID,
			LimitCount: limit,
		})
	case "postgresql":
		// Note: PostgreSQL uses different parameter names due to int32 vs int64
		dbVersions, err = h.database.GetPostgreSQLQueries().GetContentVersionHistory(context.Background(), postgresql.GetContentVersionHistoryParams{
			ContentID:  contentID,
			SiteID:     siteID,
			LimitCount: int32(limit),
		})
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
		return
	}

	versions := h.convertToAPIVersionList(dbVersions)
	response := ContentVersionsResponse{Versions: versions}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

// RollbackContent handles POST /api/content/{id}/rollback
func (h *ContentHandler) RollbackContent(w http.ResponseWriter, r *http.Request) {
	contentID := chi.URLParam(r, "id")
	siteID := r.URL.Query().Get("site_id")

	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	var req RollbackContentRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid JSON", http.StatusBadRequest)
		return
	}

	// Get the target version
	var targetVersion interface{}
	var err error

	switch h.database.GetDBType() {
	case "sqlite3":
		targetVersion, err = h.database.GetSQLiteQueries().GetContentVersion(context.Background(), req.VersionID)
	case "postgresql":
		targetVersion, err = h.database.GetPostgreSQLQueries().GetContentVersion(context.Background(), int32(req.VersionID))
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Version not found", http.StatusNotFound)
			return
		}
		http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
		return
	}

	// Verify the version belongs to the correct content
	if !h.versionMatches(targetVersion, contentID, siteID) {
		http.Error(w, "Version does not match content", http.StatusBadRequest)
		return
	}

	// Extract user from request using authentication service
	userInfo, authErr := h.authService.ExtractUserFromRequest(r)
	if authErr != nil {
		http.Error(w, fmt.Sprintf("Authentication error: %v", authErr), http.StatusUnauthorized)
		return
	}
	userID := userInfo.ID

	// Archive current version before rollback
	var currentContent interface{}

	switch h.database.GetDBType() {
	case "sqlite3":
		currentContent, err = h.database.GetSQLiteQueries().GetContent(context.Background(), sqlite.GetContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
	case "postgresql":
		currentContent, err = h.database.GetPostgreSQLQueries().GetContent(context.Background(), postgresql.GetContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to get current content: %v", err), http.StatusInternalServerError)
		return
	}

	err = h.createContentVersion(currentContent)
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to create version: %v", err), http.StatusInternalServerError)
		return
	}

	// Rollback to target version
	var updatedContent interface{}

	switch h.database.GetDBType() {
	case "sqlite3":
		sqliteVersion := targetVersion.(sqlite.ContentVersion)
		updatedContent, err = h.database.GetSQLiteQueries().UpdateContent(context.Background(), sqlite.UpdateContentParams{
			HtmlContent:  sqliteVersion.HtmlContent,
			LastEditedBy: userID,
			ID:           contentID,
			SiteID:       siteID,
		})
	case "postgresql":
		pgVersion := targetVersion.(postgresql.ContentVersion)
		updatedContent, err = h.database.GetPostgreSQLQueries().UpdateContent(context.Background(), postgresql.UpdateContentParams{
			HtmlContent:  pgVersion.HtmlContent,
			LastEditedBy: userID,
			ID:           contentID,
			SiteID:       siteID,
		})
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to rollback content: %v", err), http.StatusInternalServerError)
		return
	}

	item := h.convertToAPIContent(updatedContent)

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(item)
}

// Helper functions for type conversion
func (h *ContentHandler) convertToAPIContent(content interface{}) ContentItem {
	switch h.database.GetDBType() {
	case "sqlite3":
		c := content.(sqlite.Content)
		return ContentItem{
			ID:               c.ID,
			SiteID:           c.SiteID,
			HTMLContent:      c.HtmlContent,
			OriginalTemplate: engine.FromNullString(c.OriginalTemplate),
			CreatedAt:        time.Unix(c.CreatedAt, 0),
			UpdatedAt:        time.Unix(c.UpdatedAt, 0),
			LastEditedBy:     c.LastEditedBy,
		}
	case "postgresql":
		c := content.(postgresql.Content)
		return ContentItem{
			ID:               c.ID,
			SiteID:           c.SiteID,
			HTMLContent:      c.HtmlContent,
			OriginalTemplate: engine.FromNullString(c.OriginalTemplate),
			CreatedAt:        time.Unix(c.CreatedAt, 0),
			UpdatedAt:        time.Unix(c.UpdatedAt, 0),
			LastEditedBy:     c.LastEditedBy,
		}
	}
	return ContentItem{} // Should never happen
}

func (h *ContentHandler) convertToAPIContentList(contentList interface{}) []ContentItem {
	switch h.database.GetDBType() {
	case "sqlite3":
		list := contentList.([]sqlite.Content)
		items := make([]ContentItem, len(list))
		for i, content := range list {
			items[i] = h.convertToAPIContent(content)
		}
		return items
	case "postgresql":
		list := contentList.([]postgresql.Content)
		items := make([]ContentItem, len(list))
		for i, content := range list {
			items[i] = h.convertToAPIContent(content)
		}
		return items
	}
	return []ContentItem{} // Should never happen
}

func (h *ContentHandler) convertToAPIVersionList(versionList interface{}) []ContentVersion {
	switch h.database.GetDBType() {
	case "sqlite3":
		list := versionList.([]sqlite.ContentVersion)
		versions := make([]ContentVersion, len(list))
		for i, version := range list {
			versions[i] = ContentVersion{
				VersionID:        version.VersionID,
				ContentID:        version.ContentID,
				SiteID:           version.SiteID,
				HTMLContent:      version.HtmlContent,
				OriginalTemplate: engine.FromNullString(version.OriginalTemplate),
				CreatedAt:        time.Unix(version.CreatedAt, 0),
				CreatedBy:        version.CreatedBy,
			}
		}
		return versions
	case "postgresql":
		list := versionList.([]postgresql.ContentVersion)
		versions := make([]ContentVersion, len(list))
		for i, version := range list {
			versions[i] = ContentVersion{
				VersionID:        int64(version.VersionID),
				ContentID:        version.ContentID,
				SiteID:           version.SiteID,
				HTMLContent:      version.HtmlContent,
				OriginalTemplate: engine.FromNullString(version.OriginalTemplate),
				CreatedAt:        time.Unix(version.CreatedAt, 0),
				CreatedBy:        version.CreatedBy,
			}
		}
		return versions
	}
	return []ContentVersion{} // Should never happen
}

func (h *ContentHandler) createContentVersion(content interface{}) error {
	switch h.database.GetDBType() {
	case "sqlite3":
		c := content.(sqlite.Content)
		return h.database.GetSQLiteQueries().CreateContentVersion(context.Background(), sqlite.CreateContentVersionParams{
			ContentID:        c.ID,
			SiteID:           c.SiteID,
			HtmlContent:      c.HtmlContent,
			OriginalTemplate: c.OriginalTemplate,
			CreatedBy:        c.LastEditedBy,
		})
	case "postgresql":
		c := content.(postgresql.Content)
		return h.database.GetPostgreSQLQueries().CreateContentVersion(context.Background(), postgresql.CreateContentVersionParams{
			ContentID:        c.ID,
			SiteID:           c.SiteID,
			HtmlContent:      c.HtmlContent,
			OriginalTemplate: c.OriginalTemplate,
			CreatedBy:        c.LastEditedBy,
		})
	}
	return fmt.Errorf("unsupported database type")
}

func (h *ContentHandler) versionMatches(version interface{}, contentID, siteID string) bool {
	switch h.database.GetDBType() {
	case "sqlite3":
		v := version.(sqlite.ContentVersion)
		return v.ContentID == contentID && v.SiteID == siteID
	case "postgresql":
		v := version.(postgresql.ContentVersion)
		return v.ContentID == contentID && v.SiteID == siteID
	}
	return false
}

// generateContentID function removed - using unified ContentEngine instead

// ServeInsertrJS handles GET /insertr.js - serves the insertr JavaScript library
func (h *ContentHandler) ServeInsertrJS(w http.ResponseWriter, r *http.Request) {
	// Path to the built insertr.js file
	jsPath := "lib/dist/insertr.js"

	// Check if file exists
	if _, err := os.Stat(jsPath); os.IsNotExist(err) {
		http.Error(w, "insertr.js not found - run 'just build-lib' to build the library", http.StatusNotFound)
		return
	}

	// Open and serve the file
	file, err := os.Open(jsPath)
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to open insertr.js: %v", err), http.StatusInternalServerError)
		return
	}
	defer file.Close()

	// Set appropriate headers
	w.Header().Set("Content-Type", "application/javascript")
	w.Header().Set("Cache-Control", "no-cache") // For development

	// Copy file contents to response
	io.Copy(w, file)
}

// ServeInsertrCSS handles GET /insertr.css - serves the insertr CSS stylesheet
func (h *ContentHandler) ServeInsertrCSS(w http.ResponseWriter, r *http.Request) {
	// Path to the built insertr.css file
	cssPath := "lib/dist/insertr.css"

	// Check if file exists
	if _, err := os.Stat(cssPath); os.IsNotExist(err) {
		http.Error(w, "insertr.css not found - run 'just build-lib' to build the library", http.StatusNotFound)
		return
	}

	// Open and serve the file
	file, err := os.Open(cssPath)
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to open insertr.css: %v", err), http.StatusInternalServerError)
		return
	}
	defer file.Close()

	// Set appropriate headers
	w.Header().Set("Content-Type", "text/css")
	w.Header().Set("Cache-Control", "no-cache") // For development

	// Copy file contents to response
	io.Copy(w, file)
}

// Collection API handlers

// GetCollection handles GET /api/collections/{id}
func (h *ContentHandler) GetCollection(w http.ResponseWriter, r *http.Request) {
	collectionID := chi.URLParam(r, "id")
	siteID := r.URL.Query().Get("site_id")

	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	var collection interface{}
	var err error

	switch h.database.GetDBType() {
	case "sqlite3":
		collection, err = h.database.GetSQLiteQueries().GetCollection(context.Background(), sqlite.GetCollectionParams{
			ID:     collectionID,
			SiteID: siteID,
		})
	case "postgresql":
		collection, err = h.database.GetPostgreSQLQueries().GetCollection(context.Background(), postgresql.GetCollectionParams{
			ID:     collectionID,
			SiteID: siteID,
		})
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Collection not found", http.StatusNotFound)
			return
		}
		http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
		return
	}

	apiCollection := h.convertToAPICollection(collection)

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(apiCollection)
}

// GetAllCollections handles GET /api/collections
func (h *ContentHandler) GetAllCollections(w http.ResponseWriter, r *http.Request) {
	siteID := r.URL.Query().Get("site_id")
	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	var collections interface{}
	var err error

	switch h.database.GetDBType() {
	case "sqlite3":
		collections, err = h.database.GetSQLiteQueries().GetAllCollections(context.Background(), siteID)
	case "postgresql":
		collections, err = h.database.GetPostgreSQLQueries().GetAllCollections(context.Background(), siteID)
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
		return
	}

	apiCollections := h.convertToAPICollectionList(collections)
	response := CollectionResponse{Collections: apiCollections}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

// GetCollectionItems handles GET /api/collections/{id}/items
func (h *ContentHandler) GetCollectionItems(w http.ResponseWriter, r *http.Request) {
	collectionID := chi.URLParam(r, "id")
	siteID := r.URL.Query().Get("site_id")

	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	var items interface{}
	var err error

	switch h.database.GetDBType() {
	case "sqlite3":
		items, err = h.database.GetSQLiteQueries().GetCollectionItemsWithTemplate(context.Background(), sqlite.GetCollectionItemsWithTemplateParams{
			CollectionID: collectionID,
			SiteID:       siteID,
		})
	case "postgresql":
		items, err = h.database.GetPostgreSQLQueries().GetCollectionItemsWithTemplate(context.Background(), postgresql.GetCollectionItemsWithTemplateParams{
			CollectionID: collectionID,
			SiteID:       siteID,
		})
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
		return
	}

	apiItems := h.convertToAPICollectionItemList(items)

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"items": apiItems,
	})
}

// CreateCollectionItem handles POST /api/collections/{id}/items
func (h *ContentHandler) CreateCollectionItem(w http.ResponseWriter, r *http.Request) {
	collectionID := chi.URLParam(r, "id")

	var req CreateCollectionItemRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid JSON", http.StatusBadRequest)
		return
	}

	// Set defaults
	if req.SiteID == "" {
		req.SiteID = r.URL.Query().Get("site_id")
	}
	if req.SiteID == "" {
		http.Error(w, "site_id is required", http.StatusBadRequest)
		return
	}
	if req.CreatedBy == "" {
		req.CreatedBy = "api"
	}
	if req.CollectionID == "" {
		req.CollectionID = collectionID
	}
	if req.TemplateID == 0 {
		req.TemplateID = 1 // Default to first template
	}

	// Create database client for atomic operations
	dbClient := engine.NewDatabaseClient(h.database)

	// Use atomic collection item creation
	createdItem, err := dbClient.CreateCollectionItemAtomic(
		req.SiteID,
		req.CollectionID,
		req.TemplateID,
		req.CreatedBy,
	)
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to create collection item: %v", err), http.StatusInternalServerError)
		return
	}

	// Convert to API response format
	apiItem := CollectionItemData{
		ItemID:       createdItem.ItemID,
		CollectionID: createdItem.CollectionID,
		SiteID:       createdItem.SiteID,
		TemplateID:   createdItem.TemplateID,
		HTMLContent:  createdItem.HTMLContent,
		Position:     createdItem.Position,
		CreatedAt:    time.Now(),
		UpdatedAt:    time.Now(),
		LastEditedBy: createdItem.LastEditedBy,
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(apiItem)
}

// UpdateCollectionItem handles PUT /api/collections/{id}/items/{item_id}
func (h *ContentHandler) UpdateCollectionItem(w http.ResponseWriter, r *http.Request) {
	collectionID := chi.URLParam(r, "id")
	itemID := chi.URLParam(r, "item_id")
	siteID := r.URL.Query().Get("site_id")

	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	var req UpdateCollectionItemRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid JSON", http.StatusBadRequest)
		return
	}

	if req.UpdatedBy == "" {
		req.UpdatedBy = "api"
	}

	var updatedItem interface{}
	var err error

	// Validate position bounds if position update is requested
	if req.Position > 0 {
		var maxPos int64
		switch h.database.GetDBType() {
		case "sqlite3":
			result, err := h.database.GetSQLiteQueries().GetMaxPosition(context.Background(), sqlite.GetMaxPositionParams{
				CollectionID: collectionID,
				SiteID:       siteID,
			})
			if err != nil {
				http.Error(w, "Failed to get max position", http.StatusInternalServerError)
				return
			}
			// Convert interface{} to int64
			switch v := result.(type) {
			case int64:
				maxPos = v
			case int:
				maxPos = int64(v)
			default:
				maxPos = 0
			}
		case "postgresql":
			result, err := h.database.GetPostgreSQLQueries().GetMaxPosition(context.Background(), postgresql.GetMaxPositionParams{
				CollectionID: collectionID,
				SiteID:       siteID,
			})
			if err != nil {
				http.Error(w, "Failed to get max position", http.StatusInternalServerError)
				return
			}
			// Convert interface{} to int64
			switch v := result.(type) {
			case int64:
				maxPos = v
			case int32:
				maxPos = int64(v)
			case int:
				maxPos = int64(v)
			default:
				maxPos = 0
			}
		}

		// Check if position is valid (1-based, within bounds)
		if int64(req.Position) > maxPos {
			http.Error(w, fmt.Sprintf("Invalid position: %d exceeds max position %d", req.Position, maxPos), http.StatusBadRequest)
			return
		}
	}

	switch h.database.GetDBType() {
	case "sqlite3":
		// Update position if provided
		if req.Position > 0 {
			err = h.database.GetSQLiteQueries().UpdateCollectionItemPosition(context.Background(), sqlite.UpdateCollectionItemPositionParams{
				ItemID:       itemID,
				CollectionID: collectionID,
				SiteID:       siteID,
				Position:     int64(req.Position),
			})
			if err != nil {
				http.Error(w, fmt.Sprintf("Failed to update position: %v", err), http.StatusInternalServerError)
				return
			}
		}

		// If only position update (no html_content), just get the updated item
		if req.HTMLContent == "" {
			updatedItem, err = h.database.GetSQLiteQueries().GetCollectionItem(context.Background(), sqlite.GetCollectionItemParams{
				ItemID:       itemID,
				CollectionID: collectionID,
				SiteID:       siteID,
			})
		} else {
			// Update content and metadata
			updatedItem, err = h.database.GetSQLiteQueries().UpdateCollectionItem(context.Background(), sqlite.UpdateCollectionItemParams{
				ItemID:       itemID,
				CollectionID: collectionID,
				SiteID:       siteID,
				HtmlContent:  req.HTMLContent,
				LastEditedBy: req.UpdatedBy,
			})
		}
	case "postgresql":
		// Update position if provided
		if req.Position > 0 {
			err = h.database.GetPostgreSQLQueries().UpdateCollectionItemPosition(context.Background(), postgresql.UpdateCollectionItemPositionParams{
				ItemID:       itemID,
				CollectionID: collectionID,
				SiteID:       siteID,
				Position:     int32(req.Position),
			})
			if err != nil {
				http.Error(w, fmt.Sprintf("Failed to update position: %v", err), http.StatusInternalServerError)
				return
			}
		}

		// If only position update (no html_content), just get the updated item
		if req.HTMLContent == "" {
			updatedItem, err = h.database.GetPostgreSQLQueries().GetCollectionItem(context.Background(), postgresql.GetCollectionItemParams{
				ItemID:       itemID,
				CollectionID: collectionID,
				SiteID:       siteID,
			})
		} else {
			// Update content and metadata
			updatedItem, err = h.database.GetPostgreSQLQueries().UpdateCollectionItem(context.Background(), postgresql.UpdateCollectionItemParams{
				ItemID:       itemID,
				CollectionID: collectionID,
				SiteID:       siteID,
				HtmlContent:  req.HTMLContent,
				LastEditedBy: req.UpdatedBy,
			})
		}
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		if err == sql.ErrNoRows {
			http.Error(w, "Collection item not found", http.StatusNotFound)
			return
		}
		http.Error(w, fmt.Sprintf("Failed to update collection item: %v", err), http.StatusInternalServerError)
		return
	}

	apiItem := h.convertToAPICollectionItem(updatedItem)

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(apiItem)
}

// DeleteCollectionItem handles DELETE /api/collections/{id}/items/{item_id}
func (h *ContentHandler) DeleteCollectionItem(w http.ResponseWriter, r *http.Request) {
	collectionID := chi.URLParam(r, "id")
	itemID := chi.URLParam(r, "item_id")
	siteID := r.URL.Query().Get("site_id")

	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	var err error

	switch h.database.GetDBType() {
	case "sqlite3":
		err = h.database.GetSQLiteQueries().DeleteCollectionItem(context.Background(), sqlite.DeleteCollectionItemParams{
			ItemID:       itemID,
			CollectionID: collectionID,
			SiteID:       siteID,
		})
	case "postgresql":
		err = h.database.GetPostgreSQLQueries().DeleteCollectionItem(context.Background(), postgresql.DeleteCollectionItemParams{
			ItemID:       itemID,
			CollectionID: collectionID,
			SiteID:       siteID,
		})
	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to delete collection item: %v", err), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

// ReorderCollection handles PUT /api/collections/{id}/reorder
func (h *ContentHandler) ReorderCollection(w http.ResponseWriter, r *http.Request) {
	collectionID := chi.URLParam(r, "id")
	siteID := r.URL.Query().Get("site_id")

	if siteID == "" {
		http.Error(w, "site_id parameter is required", http.StatusBadRequest)
		return
	}

	var req ReorderCollectionRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "Invalid JSON", http.StatusBadRequest)
		return
	}

	if req.UpdatedBy == "" {
		req.UpdatedBy = "api"
	}

	// Validate that all items belong to the collection and have valid positions
	if len(req.Items) == 0 {
		http.Error(w, "Items array cannot be empty", http.StatusBadRequest)
		return
	}

	// Update positions for all items in a transaction for atomicity
	switch h.database.GetDBType() {
	case "sqlite3":
		// Use transaction for atomic bulk updates
		tx, err := h.database.GetSQLiteDB().Begin()
		if err != nil {
			http.Error(w, "Failed to begin transaction", http.StatusInternalServerError)
			return
		}
		defer tx.Rollback()

		// Create queries with transaction context
		qtx := h.database.GetSQLiteQueries().WithTx(tx)

		for _, item := range req.Items {
			err = qtx.UpdateCollectionItemPosition(context.Background(), sqlite.UpdateCollectionItemPositionParams{
				ItemID:       item.ItemID,
				CollectionID: collectionID,
				SiteID:       siteID,
				Position:     int64(item.Position),
				LastEditedBy: req.UpdatedBy,
			})
			if err != nil {
				http.Error(w, fmt.Sprintf("Failed to update position for item %s: %v", item.ItemID, err), http.StatusInternalServerError)
				return
			}
		}

		// Commit transaction
		if err = tx.Commit(); err != nil {
			http.Error(w, "Failed to commit bulk reorder transaction", http.StatusInternalServerError)
			return
		}

	case "postgres":
		// Use transaction for atomic bulk updates
		tx, err := h.database.GetPostgreSQLDB().Begin()
		if err != nil {
			http.Error(w, "Failed to begin transaction", http.StatusInternalServerError)
			return
		}
		defer tx.Rollback()

		// Create queries with transaction context
		qtx := h.database.GetPostgreSQLQueries().WithTx(tx)

		for _, item := range req.Items {
			err = qtx.UpdateCollectionItemPosition(context.Background(), postgresql.UpdateCollectionItemPositionParams{
				ItemID:       item.ItemID,
				CollectionID: collectionID,
				SiteID:       siteID,
				Position:     int32(item.Position),
				LastEditedBy: req.UpdatedBy,
			})
			if err != nil {
				http.Error(w, fmt.Sprintf("Failed to update position for item %s: %v", item.ItemID, err), http.StatusInternalServerError)
				return
			}
		}

		// Commit transaction
		if err = tx.Commit(); err != nil {
			http.Error(w, "Failed to commit bulk reorder transaction", http.StatusInternalServerError)
			return
		}

	default:
		http.Error(w, "Unsupported database type", http.StatusInternalServerError)
		return
	}

	// Return success response
	w.Header().Set("Content-Type", "application/json")
	response := map[string]interface{}{
		"success": true,
		"message": fmt.Sprintf("Successfully reordered %d items", len(req.Items)),
	}
	json.NewEncoder(w).Encode(response)
}

// Collection conversion helpers

// convertToAPICollection converts database collection to API model
func (h *ContentHandler) convertToAPICollection(dbCollection interface{}) CollectionItem {
	switch h.database.GetDBType() {
	case "sqlite3":
		collection := dbCollection.(sqlite.Collection)
		return CollectionItem{
			ID:            collection.ID,
			SiteID:        collection.SiteID,
			ContainerHTML: collection.ContainerHtml,
			CreatedAt:     time.Unix(collection.CreatedAt, 0),
			UpdatedAt:     time.Unix(collection.UpdatedAt, 0),
			LastEditedBy:  collection.LastEditedBy,
		}
	case "postgresql":
		collection := dbCollection.(postgresql.Collection)
		return CollectionItem{
			ID:            collection.ID,
			SiteID:        collection.SiteID,
			ContainerHTML: collection.ContainerHtml,
			CreatedAt:     time.Unix(collection.CreatedAt, 0),
			UpdatedAt:     time.Unix(collection.UpdatedAt, 0),
			LastEditedBy:  collection.LastEditedBy,
		}
	default:
		return CollectionItem{}
	}
}

// convertToAPICollectionList converts database collection list to API models
func (h *ContentHandler) convertToAPICollectionList(dbCollections interface{}) []CollectionItem {
	switch h.database.GetDBType() {
	case "sqlite3":
		collections := dbCollections.([]sqlite.Collection)
		result := make([]CollectionItem, len(collections))
		for i, collection := range collections {
			result[i] = CollectionItem{
				ID:            collection.ID,
				SiteID:        collection.SiteID,
				ContainerHTML: collection.ContainerHtml,
				CreatedAt:     time.Unix(collection.CreatedAt, 0),
				UpdatedAt:     time.Unix(collection.UpdatedAt, 0),
				LastEditedBy:  collection.LastEditedBy,
			}
		}
		return result
	case "postgresql":
		collections := dbCollections.([]postgresql.Collection)
		result := make([]CollectionItem, len(collections))
		for i, collection := range collections {
			result[i] = CollectionItem{
				ID:            collection.ID,
				SiteID:        collection.SiteID,
				ContainerHTML: collection.ContainerHtml,
				CreatedAt:     time.Unix(collection.CreatedAt, 0),
				UpdatedAt:     time.Unix(collection.UpdatedAt, 0),
				LastEditedBy:  collection.LastEditedBy,
			}
		}
		return result
	default:
		return []CollectionItem{}
	}
}

// convertToAPICollectionItem converts database collection item to API model
func (h *ContentHandler) convertToAPICollectionItem(dbItem interface{}) CollectionItemData {
	switch h.database.GetDBType() {
	case "sqlite3":
		item := dbItem.(sqlite.CollectionItem)
		return CollectionItemData{
			ItemID:       item.ItemID,
			CollectionID: item.CollectionID,
			SiteID:       item.SiteID,
			TemplateID:   int(item.TemplateID),
			HTMLContent:  item.HtmlContent,
			Position:     int(item.Position),
			CreatedAt:    time.Unix(item.CreatedAt, 0),
			UpdatedAt:    time.Unix(item.UpdatedAt, 0),
			LastEditedBy: item.LastEditedBy,
		}
	case "postgresql":
		item := dbItem.(postgresql.CollectionItem)
		return CollectionItemData{
			ItemID:       item.ItemID,
			CollectionID: item.CollectionID,
			SiteID:       item.SiteID,
			TemplateID:   int(item.TemplateID),
			HTMLContent:  item.HtmlContent,
			Position:     int(item.Position),
			CreatedAt:    time.Unix(item.CreatedAt, 0),
			UpdatedAt:    time.Unix(item.UpdatedAt, 0),
			LastEditedBy: item.LastEditedBy,
		}
	default:
		return CollectionItemData{}
	}
}

// convertToAPICollectionItemList converts database collection item list to API models
func (h *ContentHandler) convertToAPICollectionItemList(dbItems interface{}) []CollectionItemData {
	switch h.database.GetDBType() {
	case "sqlite3":
		items := dbItems.([]sqlite.GetCollectionItemsWithTemplateRow)
		result := make([]CollectionItemData, len(items))
		for i, item := range items {
			result[i] = CollectionItemData{
				ItemID:       item.ItemID,
				CollectionID: item.CollectionID,
				SiteID:       item.SiteID,
				TemplateID:   int(item.TemplateID),
				HTMLContent:  item.HtmlContent,
				Position:     int(item.Position),
				CreatedAt:    time.Unix(item.CreatedAt, 0),
				UpdatedAt:    time.Unix(item.UpdatedAt, 0),
				LastEditedBy: item.LastEditedBy,
				TemplateName: item.TemplateName,
			}
		}
		return result
	case "postgresql":
		items := dbItems.([]postgresql.GetCollectionItemsWithTemplateRow)
		result := make([]CollectionItemData, len(items))
		for i, item := range items {
			result[i] = CollectionItemData{
				ItemID:       item.ItemID,
				CollectionID: item.CollectionID,
				SiteID:       item.SiteID,
				TemplateID:   int(item.TemplateID),
				HTMLContent:  item.HtmlContent,
				Position:     int(item.Position),
				CreatedAt:    time.Unix(item.CreatedAt, 0),
				UpdatedAt:    time.Unix(item.UpdatedAt, 0),
				LastEditedBy: item.LastEditedBy,
				TemplateName: item.TemplateName,
			}
		}
		return result
	default:
		return []CollectionItemData{}
	}
}
