package engine

import (
	"fmt"
	"strings"

	"golang.org/x/net/html"
)

// AuthProvider represents authentication provider information
type AuthProvider struct {
	Type string // "mock", "jwt", "authentik"
}

// ContentEngine is the unified content processing engine
type ContentEngine struct {
	idGenerator  *IDGenerator
	client       ContentClient
	authProvider *AuthProvider
	injector     *Injector
}

// NewContentEngine creates a new content processing engine
func NewContentEngine(client ContentClient) *ContentEngine {
	authProvider := &AuthProvider{Type: "mock"} // default
	return &ContentEngine{
		idGenerator:  NewIDGenerator(),
		client:       client,
		authProvider: authProvider,
		injector:     NewInjector(client, ""), // siteID will be set per operation
	}
}

// NewContentEngineWithAuth creates a new content processing engine with auth config
func NewContentEngineWithAuth(client ContentClient, authProvider *AuthProvider) *ContentEngine {
	if authProvider == nil {
		authProvider = &AuthProvider{Type: "mock"}
	}
	return &ContentEngine{
		idGenerator:  NewIDGenerator(),
		client:       client,
		authProvider: authProvider,
		injector:     NewInjectorWithAuth(client, "", authProvider), // siteID will be set per operation
	}
}

// ProcessContent processes HTML content according to the specified mode
func (e *ContentEngine) ProcessContent(input ContentInput) (*ContentResult, error) {
	// 1. Parse HTML
	doc, err := html.Parse(strings.NewReader(string(input.HTML)))
	if err != nil {
		return nil, fmt.Errorf("parsing HTML: %w", err)
	}

	// 2. Find insertr and collection elements
	insertrElements, collectionElements := e.findEditableElements(doc)

	// 3. Process regular .insertr elements
	generatedIDs := make(map[string]string)
	processedElements := make([]ProcessedElement, len(insertrElements))

	for i, elem := range insertrElements {
		// Generate structural ID (always deterministic)
		id := e.idGenerator.Generate(elem.Node, input.FilePath)

		// Database-first approach: Check if content already exists
		existingContent, err := e.client.GetContent(input.SiteID, id)
		contentExists := (err == nil && existingContent != nil)

		generatedIDs[fmt.Sprintf("element_%d", i)] = id

		processedElements[i] = ProcessedElement{
			Node:      elem.Node,
			ID:        id,
			Generated: !contentExists, // Mark as generated only if new to database
			Tag:       elem.Node.Data,
			Classes:   GetClasses(elem.Node),
		}

		// Add/update content attributes to the node (only content-id now)
		e.addContentAttributes(elem.Node, id)

		// Store content only for truly new elements (database-first check)
		if !contentExists && (input.Mode == Enhancement || input.Mode == ContentInjection) {
			// Extract content and template from the unprocessed element
			htmlContent := e.extractHTMLContent(elem.Node)
			originalTemplate := e.extractOriginalTemplate(elem.Node)

			// Store in database via content client
			_, err := e.client.CreateContent(input.SiteID, id, htmlContent, originalTemplate, "system")
			if err != nil {
				// Log error but don't fail the enhancement - content just won't be stored
				fmt.Printf("⚠️ Failed to store content for %s: %v\n", id, err)
			} else {
				fmt.Printf("✅ Created new content: %s (html)\n", id)
			}
		}
	}

	// 4. Process .insertr-add collection elements
	for _, collectionElem := range collectionElements {
		// Generate structural ID for the collection container
		collectionID := e.idGenerator.Generate(collectionElem.Node, input.FilePath)

		// Add data-collection-id attribute to the collection container
		e.setAttribute(collectionElem.Node, "data-collection-id", collectionID)

		// Process collection during enhancement or content injection
		if input.Mode == Enhancement || input.Mode == ContentInjection {
			err := e.processCollection(collectionElem.Node, collectionID, input.SiteID)
			if err != nil {
				fmt.Printf("⚠️ Failed to process collection %s: %v\n", collectionID, err)
			} else {
				fmt.Printf("✅ Processed collection: %s\n", collectionID)
			}
		}
	}

	// 5. Inject content if required by mode
	if input.Mode == Enhancement || input.Mode == ContentInjection {
		err = e.injectContent(processedElements, input.SiteID)
		if err != nil {
			return nil, fmt.Errorf("injecting content: %w", err)
		}
	}

	// TODO: Implement collection-specific content injection here if needed

	// 6. Inject editor assets for enhancement mode (development)
	if input.Mode == Enhancement {
		injector := NewInjectorWithAuth(e.client, input.SiteID, e.authProvider)
		injector.InjectEditorAssets(doc, true, "")
	}

	return &ContentResult{
		Document:     doc,
		Elements:     processedElements,
		GeneratedIDs: generatedIDs,
	}, nil
}

// InsertrElement represents an insertr element found in HTML
type InsertrElement struct {
	Node *html.Node
}

// CollectionElement represents an insertr-add collection element found in HTML
type CollectionElement struct {
	Node *html.Node
}

// findEditableElements finds all editable elements (.insertr and .insertr-add)
func (e *ContentEngine) findEditableElements(doc *html.Node) ([]InsertrElement, []CollectionElement) {
	var insertrElements []InsertrElement
	var collectionElements []CollectionElement
	var containersToTransform []*html.Node

	// First pass: find all .insertr and .insertr-add elements
	e.walkNodes(doc, func(n *html.Node) {
		if n.Type == html.ElementNode {
			if e.hasInsertrClass(n) {
				if isContainer(n) {
					// Container element - mark for transformation
					containersToTransform = append(containersToTransform, n)
				} else {
					// Regular element - add directly
					insertrElements = append(insertrElements, InsertrElement{
						Node: n,
					})
				}
			} else if e.hasInsertrAddClass(n) {
				// Collection element - add directly (no container transformation for collections)
				collectionElements = append(collectionElements, CollectionElement{
					Node: n,
				})
			}
		}
	})

	// Second pass: transform .insertr containers (remove .insertr from container, add to children)
	for _, container := range containersToTransform {
		// Remove .insertr class from container
		e.removeClass(container, "insertr")

		// Find viable children and add .insertr class to them
		viableChildren := FindViableChildren(container)
		for _, child := range viableChildren {
			e.addClass(child, "insertr")
			insertrElements = append(insertrElements, InsertrElement{
				Node: child,
			})
		}
	}

	return insertrElements, collectionElements
}

// findInsertrElements finds all elements with class="insertr" and applies container transformation
// This implements the "syntactic sugar transformation" from CLASSES.md:
// - Containers with .insertr get their .insertr class removed
// - Viable children of those containers get .insertr class added
// - Regular elements with .insertr are kept as-is
func (e *ContentEngine) findInsertrElements(doc *html.Node) []InsertrElement {
	insertrElements, _ := e.findEditableElements(doc)
	return insertrElements
}

// walkNodes walks through all nodes in the document
func (e *ContentEngine) walkNodes(n *html.Node, fn func(*html.Node)) {
	fn(n)
	for c := n.FirstChild; c != nil; c = c.NextSibling {
		e.walkNodes(c, fn)
	}
}

// hasInsertrClass checks if node has class="insertr"
func (e *ContentEngine) hasInsertrClass(node *html.Node) bool {
	classes := GetClasses(node)
	for _, class := range classes {
		if class == "insertr" {
			return true
		}
	}
	return false
}

// hasInsertrAddClass checks if node has class="insertr-add" (collection)
func (e *ContentEngine) hasInsertrAddClass(node *html.Node) bool {
	classes := GetClasses(node)
	for _, class := range classes {
		if class == "insertr-add" {
			return true
		}
	}
	return false
}

// addContentAttributes adds data-content-id attribute only
// HTML-first approach: no content-type attribute needed
func (e *ContentEngine) addContentAttributes(node *html.Node, contentID string) {
	// Add data-content-id attribute
	e.setAttribute(node, "data-content-id", contentID)
}

// setAttribute sets an attribute on an HTML node
func (e *ContentEngine) setAttribute(node *html.Node, key, value string) {
	// Remove existing attribute if it exists
	for i, attr := range node.Attr {
		if attr.Key == key {
			node.Attr[i].Val = value
			return
		}
	}
	// Add new attribute
	node.Attr = append(node.Attr, html.Attribute{
		Key: key,
		Val: value,
	})
}

// addClass safely adds a class to an HTML node
func (e *ContentEngine) addClass(node *html.Node, className string) {
	var classAttr *html.Attribute
	var classIndex int = -1

	// Find existing class attribute
	for idx, attr := range node.Attr {
		if attr.Key == "class" {
			classAttr = &attr
			classIndex = idx
			break
		}
	}

	var classes []string
	if classAttr != nil {
		classes = strings.Fields(classAttr.Val)
	}

	// Check if class already exists
	for _, class := range classes {
		if class == className {
			return // Class already exists
		}
	}

	// Add new class
	classes = append(classes, className)
	newClassValue := strings.Join(classes, " ")

	if classIndex >= 0 {
		// Update existing class attribute
		node.Attr[classIndex].Val = newClassValue
	} else {
		// Add new class attribute
		node.Attr = append(node.Attr, html.Attribute{
			Key: "class",
			Val: newClassValue,
		})
	}
}

// removeClass safely removes a class from an HTML node
func (e *ContentEngine) removeClass(node *html.Node, className string) {
	var classIndex int = -1

	// Find existing class attribute
	for idx, attr := range node.Attr {
		if attr.Key == "class" {
			classIndex = idx
			break
		}
	}

	if classIndex == -1 {
		return // No class attribute found
	}

	// Parse existing classes
	classes := strings.Fields(node.Attr[classIndex].Val)

	// Filter out the target class
	var newClasses []string
	for _, class := range classes {
		if class != className {
			newClasses = append(newClasses, class)
		}
	}

	// Update or remove class attribute
	if len(newClasses) == 0 {
		// Remove class attribute entirely if no classes remain
		node.Attr = append(node.Attr[:classIndex], node.Attr[classIndex+1:]...)
	} else {
		// Update class attribute with remaining classes
		node.Attr[classIndex].Val = strings.Join(newClasses, " ")
	}
}

// injectContent injects content from database into elements
func (e *ContentEngine) injectContent(elements []ProcessedElement, siteID string) error {
	for i := range elements {
		elem := &elements[i]

		// Try to get content from database
		contentItem, err := e.client.GetContent(siteID, elem.ID)
		if err != nil {
			// Content not found is not an error - element just won't have injected content
			continue
		}

		if contentItem != nil {
			// Inject the content into the element
			elem.Content = contentItem.HTMLContent

			// Update injector siteID for this operation
			e.injector.siteID = siteID
			e.injector.injectHTMLContent(elem.Node, contentItem.HTMLContent)
		}
	}
	return nil
}

// extractHTMLContent extracts the inner HTML content from a node
func (e *ContentEngine) extractHTMLContent(node *html.Node) string {
	var content strings.Builder

	// Render all child nodes in order to preserve HTML structure
	for child := node.FirstChild; child != nil; child = child.NextSibling {
		if err := html.Render(&content, child); err == nil {
			// All nodes (text and element) rendered in correct order
		}
	}

	return strings.TrimSpace(content.String())
}

// extractOriginalTemplate extracts the outer HTML of the element (including the element itself)
func (e *ContentEngine) extractOriginalTemplate(node *html.Node) string {
	var buf strings.Builder
	if err := html.Render(&buf, node); err != nil {
		return ""
	}
	return buf.String()
}

// extractCleanTemplate extracts a clean template without data-content-id attributes and with placeholder content
func (e *ContentEngine) extractCleanTemplate(node *html.Node) string {
	// Clone the node to avoid modifying the original
	clonedNode := e.cloneNode(node)

	// Remove all data-content-id attributes and replace content with placeholders
	e.walkNodes(clonedNode, func(n *html.Node) {
		if n.Type == html.ElementNode {
			// Remove data-content-id attribute
			e.removeAttribute(n, "data-content-id")

			// If this is an .insertr element, replace content with placeholder
			if e.hasClass(n, "insertr") {
				placeholderText := e.getPlaceholderForElement(n.Data)
				// Clear existing children and add placeholder text
				for child := n.FirstChild; child != nil; {
					next := child.NextSibling
					n.RemoveChild(child)
					child = next
				}
				n.AppendChild(&html.Node{
					Type: html.TextNode,
					Data: placeholderText,
				})
			}
		}
	})

	var buf strings.Builder
	if err := html.Render(&buf, clonedNode); err != nil {
		return ""
	}
	return buf.String()
}

// removeAttribute removes an attribute from an HTML node
func (e *ContentEngine) removeAttribute(n *html.Node, key string) {
	for i, attr := range n.Attr {
		if attr.Key == key {
			n.Attr = append(n.Attr[:i], n.Attr[i+1:]...)
			break
		}
	}
}

// hasClass checks if an HTML node has a specific class
func (e *ContentEngine) hasClass(n *html.Node, className string) bool {
	for _, attr := range n.Attr {
		if attr.Key == "class" {
			classes := strings.Fields(attr.Val)
			for _, class := range classes {
				if class == className {
					return true
				}
			}
		}
	}
	return false
}

// getPlaceholderForElement returns appropriate placeholder text for an element type
func (e *ContentEngine) getPlaceholderForElement(elementType string) string {
	placeholders := map[string]string{
		"blockquote": "Enter your quote here...",
		"cite":       "Enter author name...",
		"h1":         "Enter heading...",
		"h2":         "Enter heading...",
		"h3":         "Enter heading...",
		"p":          "Enter text...",
		"span":       "Enter text...",
		"div":        "Enter content...",
		"a":          "Enter link text...",
	}

	if placeholder, exists := placeholders[elementType]; exists {
		return placeholder
	}
	return "Enter content..."
}

// processCollection handles collection detection, persistence and reconstruction
func (e *ContentEngine) processCollection(collectionNode *html.Node, collectionID, siteID string) error {
	// 1. Check if collection exists in database
	existingCollection, err := e.client.GetCollection(siteID, collectionID)
	collectionExists := (err == nil && existingCollection != nil)

	if !collectionExists {
		// 2. New collection: extract container HTML and create collection record
		containerHTML := e.extractOriginalTemplate(collectionNode)

		_, err := e.client.CreateCollection(siteID, collectionID, containerHTML, "system")
		if err != nil {
			return fmt.Errorf("failed to create collection %s: %w", collectionID, err)
		}

		// 3. Extract templates and store initial items from existing children
		err = e.extractAndStoreTemplatesAndItems(collectionNode, collectionID, siteID)
		if err != nil {
			return fmt.Errorf("failed to extract templates and items for collection %s: %w", collectionID, err)
		}

		fmt.Printf("✅ Created new collection: %s with templates and initial items\n", collectionID)
	} else {
		// 4. Existing collection: Always reconstruct from database (database is source of truth)
		err = e.reconstructCollectionItems(collectionNode, collectionID, siteID)
		if err != nil {
			return fmt.Errorf("failed to reconstruct collection %s: %w", collectionID, err)
		}

		// Get final item count for logging
		existingItems, _ := e.client.GetCollectionItems(siteID, collectionID)
		fmt.Printf("✅ Reconstructed collection: %s from database (%d items)\n", collectionID, len(existingItems))
	}

	return nil
}

// extractAndStoreTemplatesAndItems extracts templates and stores initial items from existing collection children
func (e *ContentEngine) extractAndStoreTemplatesAndItems(collectionNode *html.Node, collectionID, siteID string) error {
	// Find existing children elements to use as templates
	var templateElements []*html.Node

	// Walk through direct children of the collection
	for child := collectionNode.FirstChild; child != nil; child = child.NextSibling {
		if child.Type == html.ElementNode {
			templateElements = append(templateElements, child)
		}
	}

	if len(templateElements) == 0 {
		// No existing children - create a default empty template
		_, err := e.client.CreateCollectionTemplate(siteID, collectionID, "default", "<div>New item</div>", true)
		if err != nil {
			return fmt.Errorf("failed to create default template: %w", err)
		}
		fmt.Printf("✅ Created default template for collection %s\n", collectionID)
		return nil
	}

	// Extract templates from existing children and store them
	var templateIDs []int
	for i, templateElement := range templateElements {
		templateHTML := e.extractCleanTemplate(templateElement)
		templateName := fmt.Sprintf("template-%d", i+1)
		isDefault := (i == 0) // First template is default

		template, err := e.client.CreateCollectionTemplate(siteID, collectionID, templateName, templateHTML, isDefault)
		if err != nil {
			return fmt.Errorf("failed to create template %s: %w", templateName, err)
		}

		templateIDs = append(templateIDs, template.TemplateID)
		fmt.Printf("✅ Created template '%s' for collection %s\n", templateName, collectionID)
	}

	// Store original children as initial collection items (database-first approach)
	err := e.storeChildrenAsCollectionItems(collectionNode, collectionID, siteID, templateIDs)
	if err != nil {
		return fmt.Errorf("failed to store initial collection items: %w", err)
	}

	// Reconstruct items from database to ensure proper data-item-id injection
	err = e.reconstructCollectionItems(collectionNode, collectionID, siteID)
	if err != nil {
		return fmt.Errorf("failed to reconstruct initial collection items: %w", err)
	}

	return nil
}

// reconstructCollectionItems rebuilds collection items from database and adds them to DOM
func (e *ContentEngine) reconstructCollectionItems(collectionNode *html.Node, collectionID, siteID string) error {
	// Get all items for this collection from database
	items, err := e.client.GetCollectionItems(siteID, collectionID)
	if err != nil {
		return fmt.Errorf("failed to get collection items: %w", err)
	}

	// Get templates for this collection
	templates, err := e.client.GetCollectionTemplates(siteID, collectionID)
	if err != nil {
		return fmt.Errorf("failed to get collection templates: %w", err)
	}

	// Create a template map for quick lookup
	templateMap := make(map[int]string)
	for _, template := range templates {
		templateMap[template.TemplateID] = template.HTMLTemplate
	}

	// Clear existing children (they will be replaced with database items)
	for child := collectionNode.FirstChild; child != nil; {
		next := child.NextSibling
		collectionNode.RemoveChild(child)
		child = next
	}

	// Add items from database in position order using unified .insertr approach
	for _, item := range items {
		// Parse the stored structural HTML with content IDs (no template needed for reconstruction)
		structuralDoc, err := html.Parse(strings.NewReader(item.HTMLContent))
		if err != nil {
			fmt.Printf("⚠️ Failed to parse stored HTML for %s: %v\n", item.ItemID, err)
			continue
		}

		var structuralBody *html.Node
		e.walkNodes(structuralDoc, func(n *html.Node) {
			if n.Type == html.ElementNode && n.Data == "body" {
				structuralBody = n
			}
		})

		if structuralBody != nil {
			// Process each .insertr element using Injector pattern (unified approach)
			injector := NewInjector(e.client, siteID)

			// Walk through structural elements and hydrate with content from content table
			e.walkNodes(structuralBody, func(n *html.Node) {
				if n.Type == html.ElementNode && e.hasClass(n, "insertr") {
					// Get content ID from data attribute
					contentID := GetAttribute(n, "data-content-id")
					if contentID != "" {
						// Use Injector to hydrate content (unified .insertr approach)
						element := &Element{Node: n, Type: "html"}
						err := injector.InjectContent(element, contentID)
						if err != nil {
							fmt.Printf("⚠️ Failed to inject content for %s: %v\n", contentID, err)
						}
					}
				}
			})

			// Add hydrated structural elements directly to collection (stored HTML has complete structure)
			for structuralChild := structuralBody.FirstChild; structuralChild != nil; {
				next := structuralChild.NextSibling
				structuralBody.RemoveChild(structuralChild)

				// Inject data-item-id attribute for collection item identification
				if structuralChild.Type == html.ElementNode {
					e.setAttribute(structuralChild, "data-item-id", item.ItemID)
				}

				collectionNode.AppendChild(structuralChild)
				structuralChild = next
			}
		}
	}

	fmt.Printf("✅ Reconstructed %d items for collection %s\n", len(items), collectionID)
	return nil
}

// processChildElementsAsContent processes .insertr elements within a collection child and stores them as individual content
func (e *ContentEngine) processChildElementsAsContent(childElement *html.Node, siteID, itemID string) ([]ContentEntry, error) {
	var contentEntries []ContentEntry
	elementIndex := 0

	// Walk through child element to find .insertr elements
	e.walkNodes(childElement, func(n *html.Node) {
		if n.Type == html.ElementNode && e.hasClass(n, "insertr") {
			// Use core IDGenerator for unified ID generation (like individual .insertr elements)
			contentID := e.idGenerator.Generate(n, "collection-item")

			// Extract actual content from the element
			actualContent := ExtractTextContent(n)

			// Store as individual content entry (unified .insertr approach)
			_, err := e.client.CreateContent(siteID, contentID, actualContent, "", "system")
			if err != nil {
				fmt.Printf("⚠️ Failed to create content %s: %v\n", contentID, err)
				return
			}

			// Add to content entries for structural template generation
			contentEntries = append(contentEntries, ContentEntry{
				ID:          contentID,
				SiteID:      siteID,
				HTMLContent: actualContent,
				Template:    e.extractOriginalTemplate(n),
			})

			elementIndex++
		}
	})

	return contentEntries, nil
}

// generateStructuralTemplateFromChild creates structure-only HTML from child element with content IDs
func (e *ContentEngine) generateStructuralTemplateFromChild(childElement *html.Node, contentEntries []ContentEntry) (string, error) {
	// Clone the child element to avoid modifying original
	clonedChild := e.cloneNode(childElement)
	entryIndex := 0

	// Walk through cloned element and replace content with content IDs
	e.walkNodes(clonedChild, func(n *html.Node) {
		if n.Type == html.ElementNode && e.hasClass(n, "insertr") {
			if entryIndex < len(contentEntries) {
				// Set the data-content-id attribute
				e.setAttribute(n, "data-content-id", contentEntries[entryIndex].ID)

				// Clear content - this will be hydrated during reconstruction
				for child := n.FirstChild; child != nil; {
					next := child.NextSibling
					n.RemoveChild(child)
					child = next
				}

				entryIndex++
			}
		}
	})

	// Render the complete structural template including container
	var sb strings.Builder
	html.Render(&sb, clonedChild)

	return sb.String(), nil
}

// createVirtualElementFromTemplate creates a virtual DOM element from template HTML for API usage
// This allows API path to use the same structure extraction as enhancement path
func (e *ContentEngine) createVirtualElementFromTemplate(templateHTML string) (*html.Node, error) {
	// Parse the template HTML
	templateDoc, err := html.Parse(strings.NewReader(templateHTML))
	if err != nil {
		return nil, fmt.Errorf("failed to parse template HTML: %w", err)
	}

	// Find the body element and extract the template structure
	var templateBody *html.Node
	e.walkNodes(templateDoc, func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "body" {
			templateBody = n
		}
	})

	if templateBody != nil && templateBody.FirstChild != nil {
		// Return the first child of body (the actual template element)
		return templateBody.FirstChild, nil
	}

	return nil, fmt.Errorf("template does not contain valid structure")
}

// CreateCollectionItemFromTemplate creates a collection item using the unified engine approach
// This replaces TemplateProcessor with engine-native functionality
func (e *ContentEngine) CreateCollectionItemFromTemplate(
	siteID, collectionID string,
	templateID int,
	templateHTML string,
	lastEditedBy string,
) (*CollectionItemWithTemplate, error) {
	// Create virtual element from template (like enhancement path)
	virtualElement, err := e.createVirtualElementFromTemplate(templateHTML)
	if err != nil {
		return nil, fmt.Errorf("failed to create virtual element: %w", err)
	}

	// Generate unique item ID using unified generator with collection context
	itemID := e.idGenerator.Generate(virtualElement, "collection-item")
	if err != nil {
		return nil, fmt.Errorf("failed to create virtual element: %w", err)
	}

	// Process .insertr elements and create content entries (unified approach)
	contentEntries, err := e.processChildElementsAsContent(virtualElement, siteID, itemID)
	if err != nil {
		return nil, fmt.Errorf("failed to process content entries: %w", err)
	}

	// Generate structural template using unified engine method
	structuralTemplate, err := e.generateStructuralTemplateFromChild(virtualElement, contentEntries)
	if err != nil {
		return nil, fmt.Errorf("failed to generate structural template: %w", err)
	}

	// Create collection item with structural template
	collectionItem, err := e.client.CreateCollectionItem(
		siteID, collectionID, itemID, templateID, structuralTemplate, 0, lastEditedBy,
	)
	if err != nil {
		return nil, fmt.Errorf("failed to create collection item: %w", err)
	}

	return collectionItem, nil
}

// cloneNode creates a deep copy of an HTML node
func (e *ContentEngine) cloneNode(node *html.Node) *html.Node {
	cloned := &html.Node{
		Type:      node.Type,
		Data:      node.Data,
		DataAtom:  node.DataAtom,
		Namespace: node.Namespace,
	}

	// Clone attributes
	for _, attr := range node.Attr {
		cloned.Attr = append(cloned.Attr, html.Attribute{
			Namespace: attr.Namespace,
			Key:       attr.Key,
			Val:       attr.Val,
		})
	}

	// Clone children recursively
	for child := node.FirstChild; child != nil; child = child.NextSibling {
		clonedChild := e.cloneNode(child)
		cloned.AppendChild(clonedChild)
	}

	return cloned
}

// storeChildrenAsCollectionItems stores HTML children as collection items in database
func (e *ContentEngine) storeChildrenAsCollectionItems(collectionNode *html.Node, collectionID, siteID string, templateIDs []int) error {
	// Find existing children elements to store as items
	var childElements []*html.Node

	// Walk through direct children of the collection
	for child := collectionNode.FirstChild; child != nil; child = child.NextSibling {
		if child.Type == html.ElementNode {
			childElements = append(childElements, child)
		}
	}

	if len(childElements) == 0 {
		fmt.Printf("ℹ️ No children found to store as collection items for %s\n", collectionID)
		return nil
	}

	// Store each child using unified .insertr approach (content table + structural template)
	for i, childElement := range childElements {
		// Generate item ID using unified generator with collection context
		itemID := e.idGenerator.Generate(childElement, "collection-item")

		// Process .insertr elements within this child (unified approach)
		contentEntries, err := e.processChildElementsAsContent(childElement, siteID, itemID)
		if err != nil {
			return fmt.Errorf("failed to process content for item %s: %w", itemID, err)
		}

		// Generate structural template with content IDs (no actual content)
		structuralTemplate, err := e.generateStructuralTemplateFromChild(childElement, contentEntries)
		if err != nil {
			return fmt.Errorf("failed to generate structural template for item %s: %w", itemID, err)
		}

		// Use appropriate template ID (cycle through available templates)
		templateID := templateIDs[i%len(templateIDs)]

		// Store structural template in collection_items (content lives in content table)
		_, err = e.client.CreateCollectionItem(siteID, collectionID, itemID, templateID, structuralTemplate, i+1, "system")
		if err != nil {
			return fmt.Errorf("failed to create collection item %s: %w", itemID, err)
		}

		fmt.Printf("✅ Stored initial collection item: %s (template %d) with %d content entries\n", itemID, templateID, len(contentEntries))
	}

	return nil
}
