/**
 * Chat UI Helpers
 *
 * Provides utility methods for creating and managing chat interface DOM elements,
 * including markdown rendering, HTML sanitization, and chat panel structure.
 *
 * @file
 * @since 1.0.0
 * @package AgenticWP
 */

/**
 * Chat UI helpers for creating and managing DOM elements.
 *
 * @class
 * @since 1.0.0
 */
class ChatUIHelpers {
	/**
	 * Creates a DOM element with optional class and text content.
	 *
	 * @param {string} tag - HTML tag name (e.g., 'div', 'span').
	 * @param {string} className - CSS class name(s) to apply.
	 * @param {string} textContent - Text content for the element.
	 * @return {HTMLElement} The created DOM element.
	 */
	createElement(tag, className = '', textContent = '') {
		const element = document.createElement(tag);
		if (className) element.className = className;
		if (textContent) element.textContent = textContent;
		return element;
	}

	/**
	 * Creates a styled message element for the chat interface.
	 *
	 * @param {string} content - The message content to display.
	 * @param {string} type - Message type ('user' or 'assistant').
	 * @return {HTMLElement} The formatted message element.
	 */
	createMessageElement(content, type) {
		const messageElement = this.createElement('div', `agenticwp-message ${type}`);
		const messageContent = this.createElement('div', 'agenticwp-message-content');
        
		if (type === 'assistant' && this.containsMarkdown(content)) {
			messageContent.innerHTML = this.renderMarkdown(content);
		} else {
			messageContent.textContent = content;
		}
        
		messageElement.appendChild(messageContent);
		return messageElement;
	}

	/**
	 * Creates an HTML string for a loading indicator with animated dots.
	 *
	 * @param {string} text - Loading message text to display.
	 * @return {string} HTML string containing the loading indicator.
	 */
	createLoadingIndicator(text = 'Assistant is typing') {
		return `
            <span>${this.escapeHtml(text)}</span>
            <div class="agenticwp-loading-dots">
                <span></span>
                <span></span>
                <span></span>
            </div>
        `;
	}

	/**
	 * Checks if content contains markdown syntax.
	 *
	 * @param {string} content - Content to check for markdown.
	 * @return {boolean} True if markdown patterns are detected.
	 */
	containsMarkdown(content) {
		return /[#*`\[\]_~]/.test(content) || content.includes('\n\n');
	}

	/**
	 * Renders markdown content to sanitized HTML using marked and DOMPurify.
	 *
	 * @param {string} content - Markdown content to render.
	 * @return {string} Sanitized HTML output, or escaped plain text if libraries unavailable.
	 */
	renderMarkdown(content) {
		try {
			if (typeof marked === 'undefined' || typeof DOMPurify === 'undefined') {
				return this.escapeHtml(content);
			}

			marked.setOptions({
				breaks: true,
				gfm: true,
				headerIds: false,
				mangle: false
			});

			const html = marked.parse(content);

			return DOMPurify.sanitize(html, {
				ALLOWED_TAGS: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'br',
					'strong', 'em', 'ul', 'ol', 'li', 'a', 'code',
					'pre', 'blockquote'],
				ALLOWED_ATTR: ['href', 'title'],
				FORBID_TAGS: ['script', 'object', 'embed', 'iframe', 'form'],
				FORBID_ATTR: ['style', 'onerror', 'onload', 'onclick'],
				USE_PROFILES: { html: true },
				SANITIZE_DOM: true
			});
		} catch (error) {
			return this.escapeHtml(content);
		}
	}

	/**
	 * Automatically resizes a textarea based on its content, with a max height.
	 *
	 * @param {HTMLTextAreaElement} textarea - The textarea element to resize.
	 * @return {void}
	 */
	autoResizeTextarea(textarea) {
		textarea.style.height = 'auto';
		textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px';
	}

	/**
	 * Escapes HTML special characters to prevent XSS attacks.
	 *
	 * @param {string} text - Text to escape.
	 * @return {string} HTML-escaped text.
	 */
	escapeHtml(text) {
		const div = document.createElement('div');
		div.textContent = text;
		return div.innerHTML;
	}

	/**
	 * Generates the complete HTML structure for the chat panel.
	 *
	 * @return {string} HTML string for the entire chat panel interface.
	 */
	getChatPanelHTML() {
		return `
            <div class="agenticwp-chat-panel" aria-hidden="true" role="dialog" aria-labelledby="agenticwp-chat-title">
                ${this.getChatHeaderHTML()}
                <div class="agenticwp-chat-main">
                    <div class="agenticwp-messages-section">
                        <div class="agenticwp-messages" aria-live="polite" aria-label="Chat messages"></div>
                        ${this.getChatInputAreaHTML()}
                    </div>
                    ${this.getActionsSidebarHTML()}
                </div>
            </div>
        `;
	}
    
	/**
	 * Generates the HTML for the chat panel header with logo and controls.
	 *
	 * @return {string} HTML string for the chat header section.
	 */
	getChatHeaderHTML() {
		return `
            <div class="agenticwp-chat-header">
                <div class="agenticwp-drag-handle">
					<img class="agenticwp-chat-logo" src="/wp-content/plugins/agenticwp/assets/images/agenticWP-logo.png" alt="AgenticWP Logo">
                    <h3 class="agenticwp-chat-title" id="agenticwp-chat-title">AgenticWP</h3>
                </div>
                <div class="agenticwp-header-buttons">
                    <button class="agenticwp-chat-clear" aria-label="Clear chat history" type="button">
                        Clear History
                    </button>
                    <button class="agenticwp-chat-close" aria-label="Close chat" type="button">
                        <svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true">
                            <path fill="currentColor" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
                        </svg>
                    </button>
                </div>
            </div>
        `;
	}
    
	/**
	 * Generates the HTML for the message input area and send button.
	 *
	 * @return {string} HTML string for the input area section.
	 */
	getChatInputAreaHTML() {
		return `
            <div class="agenticwp-input-area">
                <div class="agenticwp-input-controls">
                    <button
                        class="agenticwp-actions-toggle"
                        aria-expanded="false"
                        aria-controls="agenticwp-actions-sidebar"
                        aria-label="Open quick actions"
                        title="Quick Actions"
                    >
                        <span class="dashicons dashicons-menu-alt3"></span>
                    </button>
                </div>
                <div class="agenticwp-input-wrapper">
                    <textarea
                        class="agenticwp-message-input"
                        placeholder="Type your message..."
                        aria-label="Type your message"
                        rows="1"
                        maxlength="1000"
                    ></textarea>
                    <button class="agenticwp-send-button" type="button" aria-label="Send message">
                        <span class="agenticwp-send-text">Send</span>
                    </button>
                </div>
            </div>
        `;
	}
	/**
	 * Generates the HTML for the quick actions sidebar.
	 *
	 * @return {string} HTML string for the actions sidebar section.
	 */
	getActionsSidebarHTML() {
		return `
            <aside
                class="agenticwp-actions-sidebar"
                id="agenticwp-actions-sidebar"
                role="complementary"
                aria-labelledby="agenticwp-actions-title"
                aria-hidden="true"
                tabindex="-1"
            >
                <header class="agenticwp-actions-header">
                    <h3 id="agenticwp-actions-title">Quick Actions</h3>
                    <button
                        class="agenticwp-actions-close"
                        aria-label="Close actions sidebar"
                        title="Close"
                    >
                        <span class="dashicons dashicons-no-alt"></span>
                    </button>
                </header>
                <div class="agenticwp-actions-content">
                    <div class="agenticwp-actions-loading">
                        <span class="spinner is-active"></span>
                        <span>Loading actions...</span>
                    </div>
                </div>
            </aside>
        `;
	}
}

/**
 * Handles drag-and-drop functionality for the chat panel.
 *
 * @class
 * @since 1.0.0
 */
class ChatDragHandler {
	/**
	 * Initializes the drag handler for a chat panel.
	 *
	 * @param {HTMLElement} panel - The chat panel element to make draggable.
	 */
	constructor(panel) {
		this.panel = panel;
		this.drag = {
			isDragging: false,
			startX: 0,
			startY: 0,
			offsetX: 0,
			offsetY: 0
		};
	}

	/**
	 * Initiates drag operation when user clicks and holds the drag handle.
	 *
	 * @param {MouseEvent} event - The mousedown event.
	 * @return {void}
	 */
	startDrag(event) {
		event.preventDefault();
        
		this.drag.isDragging = true;
		this.drag.startX = event.clientX;
		this.drag.startY = event.clientY;
        
		const rect = this.panel.getBoundingClientRect();
		this.drag.offsetX = event.clientX - rect.left;
		this.drag.offsetY = event.clientY - rect.top;
        
		this.panel.classList.add('agenticwp-dragging');
	}

	/**
	 * Updates panel position during drag operation, constraining to viewport.
	 *
	 * @param {MouseEvent} event - The mousemove event.
	 * @return {void}
	 */
	onDrag(event) {
		if (!this.drag.isDragging) return;
        
		event.preventDefault();
        
		let newX = event.clientX - this.drag.offsetX;
		let newY = event.clientY - this.drag.offsetY;
        
		const panelRect = this.panel.getBoundingClientRect();
		const viewportWidth = window.innerWidth;
		const viewportHeight = window.innerHeight;
        
		newX = Math.max(0, Math.min(newX, viewportWidth - panelRect.width));
		newY = Math.max(0, Math.min(newY, viewportHeight - panelRect.height));
        
		this.panel.style.left = `${newX}px`;
		this.panel.style.top = `${newY}px`;
		this.panel.style.right = 'auto';
	}

	/**
	 * Finalizes drag operation and returns the final position.
	 *
	 * @return {Object|void} Object with x and y coordinates, or void if not dragging.
	 */
	endDrag() {
		if (!this.drag.isDragging) return;
        
		this.drag.isDragging = false;
		this.panel.classList.remove('agenticwp-dragging');
        
		return {
			x: this.panel.getBoundingClientRect().left,
			y: this.panel.getBoundingClientRect().top
		};
	}
}

/**
 * Wrapper for localStorage with error handling and JSON serialization.
 *
 * @class
 * @since 1.0.0
 */
class StorageWrapper {
	/**
	 * Retrieves and parses a value from localStorage.
	 *
	 * @param {string} key - Storage key to retrieve.
	 * @param {*} defaultValue - Default value if key doesn't exist or parsing fails.
	 * @return {*} Parsed value from storage or defaultValue.
	 */
	get(key, defaultValue = null) {
		try {
			const stored = localStorage.getItem(key);
			return stored ? JSON.parse(stored) : defaultValue;
		} catch (error) {
			return defaultValue;
		}
	}

	/**
	 * Stores a value in localStorage with JSON serialization.
	 *
	 * @param {string} key - Storage key.
	 * @param {*} value - Value to store (will be JSON stringified).
	 * @return {boolean} True if storage succeeded, false on error.
	 */
	set(key, value) {
		try {
			localStorage.setItem(key, JSON.stringify(value));
			return true;
		} catch (error) {
			return false;
		}
	}

	/**
	 * Removes a value from localStorage.
	 *
	 * @param {string} key - Storage key to remove.
	 * @return {boolean} True if removal succeeded, false on error.
	 */
	remove(key) {
		try {
			localStorage.removeItem(key);
			return true;
		} catch (error) {
			return false;
		}
	}
    
	/**
	 * Automatically removes a DOM element after a delay.
	 *
	 * @param {HTMLElement} element - Element to remove.
	 * @param {number} delay - Delay in milliseconds before removal.
	 * @return {void}
	 */
	autoRemove(element, delay = 10000) {
		setTimeout(() => {
			if (element.parentNode) {
				element.remove();
			}
		}, delay);
	}
}

window.ChatUIHelpers = ChatUIHelpers;
window.ChatDragHandler = ChatDragHandler;
window.StorageWrapper = StorageWrapper;