/**
 * Frontend JavaScript for Algolia Agent Chat block.
 * Uses Algolia Agent Studio API directly (HTTP API approach).
 */

( function() {
	const BLOCK_SELECTOR = '.wp-block-wlc-algolia-agent-chat';
	
	function init() {
		const blocks = document.querySelectorAll( BLOCK_SELECTOR );
		if ( ! blocks.length ) return;

		blocks.forEach( ( block ) => {
			if ( block.dataset.initialized ) return;
			block.dataset.initialized = '1';

			const config = JSON.parse( block.dataset.config || '{}' );
			const container = block.querySelector( '[data-role="chat-container"]' );

			if ( ! container || ! config.agentId || ! config.appId || ! config.apiKey ) {
				return;
			}

			initChat( container, config );
		} );
	}

	function initChat( container, config ) {
		const messages = [];
		let isLoading = false;

		// Create chat UI
		const chatHTML = `
			<div class="wp-block-wlc-algolia-agent-chat__messages" data-role="messages"></div>
			<div class="wp-block-wlc-algolia-agent-chat__input-wrapper">
				<input 
					type="text" 
					class="wp-block-wlc-algolia-agent-chat__input" 
					placeholder="Ask me anything..."
					data-role="input"
				/>
				<button type="button" class="wp-block-wlc-algolia-agent-chat__send" data-role="send">
					<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
						<line x1="22" y1="2" x2="11" y2="13"></line>
						<polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
					</svg>
				</button>
			</div>
		`;

		container.innerHTML = chatHTML;

		const messagesEl = container.querySelector( '[data-role="messages"]' );
		const inputEl = container.querySelector( '[data-role="input"]' );
		const sendBtn = container.querySelector( '[data-role="send"]' );
		inputEl.placeholder = String( config.placeholder || 'Ask me anything...' );

		function addMessage( role, text ) {
			const messageEl = document.createElement( 'div' );
			messageEl.className = `wp-block-wlc-algolia-agent-chat__message wp-block-wlc-algolia-agent-chat__message--${ role }`;
			// For assistant messages, render markdown (links, bold, italic),
			// then run the whitelist sanitizer right before innerHTML insertion.
			// For user messages, escape HTML for security.
			const content = role === 'assistant' ? sanitizeMessageHtml( markdownToHtml( text ) ) : escapeHtml( text );
			messageEl.innerHTML = `
				<div class="wp-block-wlc-algolia-agent-chat__message-content">${ content }</div>
			`;
			messagesEl.appendChild( messageEl );
			messagesEl.scrollTop = messagesEl.scrollHeight;
		}

		function setLoading( loading ) {
			isLoading = loading;
			sendBtn.disabled = loading;
			inputEl.disabled = loading;
			
			if ( loading ) {
				const loadingEl = document.createElement( 'div' );
				loadingEl.className = 'wp-block-wlc-algolia-agent-chat__message wp-block-wlc-algolia-agent-chat__message--assistant wp-block-wlc-algolia-agent-chat__message--loading';
				loadingEl.innerHTML = '<div class="wp-block-wlc-algolia-agent-chat__message-content">Thinking...</div>';
				loadingEl.dataset.loadingId = Date.now();
				messagesEl.appendChild( loadingEl );
				messagesEl.scrollTop = messagesEl.scrollHeight;
			} else {
				const loadingMsg = messagesEl.querySelector( '[data-loading-id]' );
				if ( loadingMsg ) {
					loadingMsg.remove();
				}
			}
		}

		async function sendMessage( text ) {
			if ( ! text.trim() || isLoading ) return;

			// Add user message
			addMessage( 'user', text );
			// Store message in format compatible with Algolia Agent Studio API
			// Format: { role: 'user', parts: [{ text: '...' }] }
			// For ai-sdk-5, parts should NOT include 'type' field in the request
			messages.push( {
				role: 'user',
				parts: [ { text: text.trim() } ]
			} );

			inputEl.value = '';
			setLoading( true );

			try {
				// Prepare messages in correct format for Algolia Agent Studio API
				// According to Algolia docs: https://algolia.com/doc/guides/algolia-ai/agent-studio/how-to/integration/
				// Format: { role: 'user'|'assistant', parts: [{ text: '...' }] }
				// For compatibilityMode=ai-sdk-5, the format matches AI SDK v5
				const apiMessages = messages.map( ( msg ) => {
					// Extract text from parts array or text property
					let text = '';
					if ( msg.parts && Array.isArray( msg.parts ) && msg.parts.length > 0 ) {
						// Extract text from parts - parts can be [{ text: '...' }] or [{ type: 'text', text: '...' }]
						msg.parts.forEach( ( part ) => {
							if ( part.text !== undefined && part.text !== null && part.text !== '' ) {
								text += String( part.text ).trim() + ' ';
							} else if ( part.type === 'text' && part.text !== undefined && part.text !== null ) {
								text += String( part.text ).trim() + ' ';
							}
						} );
						text = text.trim();
					} else if ( msg.text !== undefined && msg.text !== null && msg.text !== '' ) {
						text = String( msg.text ).trim();
					}

					// Skip empty messages
					if ( ! text || text.length === 0 ) {
						return null;
					}

					// Format according to Algolia Agent Studio API documentation
					// Request format for compatibilityMode=ai-sdk-5: { role: 'user', parts: [{ text: '...' }] }
					// For ai-sdk-5, parts should NOT include 'type' field in the request
					// The 'type' field appears in responses, but not in requests for ai-sdk-5
					return {
						role: msg.role,
						parts: [
							{
								text: text
							}
						]
					};
				} ).filter( ( msg ) => {
					// Filter out invalid messages
					if ( ! msg || ! msg.parts || ! Array.isArray( msg.parts ) || msg.parts.length === 0 ) {
						return false;
					}
					// Check if first part has text (can be { text: '...' } or { type: 'text', text: '...' } from responses)
					const firstPart = msg.parts[0];
					const textValue = firstPart?.text || ( firstPart?.type === 'text' ? firstPart?.text : null );
					return textValue && String( textValue ).trim().length > 0;
				} );

				if ( apiMessages.length === 0 ) {
					throw new Error( 'No valid messages to send' );
				}

				// Validate Agent ID format (should be UUID)
				const agentId = String( config.agentId || '' ).trim();
				if ( ! agentId || agentId.length < 30 ) {
					throw new Error( 'Invalid Agent ID format. Please check your Agent ID in block settings.' );
				}

				// Build API URL - ensure appId is lowercase in URL (Algolia requires lowercase in domain)
				// According to Algolia docs, the endpoint format is:
				// https://{appId}.algolia.net/agent-studio/1/agents/{agentId}/completions
				// Try ai-sdk-5 first (more common), fallback to ai-sdk-4 if needed
				const appIdLower = String( config.appId || '' ).toLowerCase();
				const apiUrl = `https://${ appIdLower }.algolia.net/agent-studio/1/agents/${ agentId }/completions?stream=false&compatibilityMode=ai-sdk-5`;
				
				// Debug: verify we have all required data
				if ( ! config.appId || ! config.apiKey || ! agentId ) {
					throw new Error( 'Missing required configuration: appId, apiKey, or agentId' );
				}
				
				const requestBody = {
					messages: apiMessages
				};

				console.log( '[Algolia Agent Chat] Sending request to:', apiUrl );
				console.log( '[Algolia Agent Chat] Agent ID:', agentId );
				console.log( '[Algolia Agent Chat] App ID:', config.appId );
				console.log( '[Algolia Agent Chat] API Key (first 10 chars):', config.apiKey ? config.apiKey.substring( 0, 10 ) + '...' : 'MISSING' );
				console.log( '[Algolia Agent Chat] Request body:', JSON.stringify( requestBody, null, 2 ) );

				const response = await fetch( apiUrl, {
					method: 'POST',
					headers: {
						'Content-Type': 'application/json',
						'x-algolia-application-id': config.appId, // Keep original case in header
						'X-Algolia-API-Key': config.apiKey,
					},
					body: JSON.stringify( requestBody ),
				} );

				// Log response headers for debugging
				console.log( '[Algolia Agent Chat] Response status:', response.status );
				console.log( '[Algolia Agent Chat] Response headers:', Object.fromEntries( response.headers.entries() ) );

				if ( ! response.ok ) {
					const errorText = await response.text();
					console.error( '[Algolia Agent Chat] HTTP error:', response.status, errorText );
					throw new Error( `HTTP error! status: ${ response.status }, body: ${ errorText }` );
				}

				const data = await response.json();
				console.log( '[Algolia Agent Chat] Response:', data );
				
				// Extract text from response - Algolia returns { role: 'assistant', parts: [...] }
				// Format: { role: 'assistant', parts: [{ type: 'text', text: '...' }] }
				let assistantText = '';
				if ( data.parts && Array.isArray( data.parts ) ) {
					data.parts.forEach( ( part ) => {
						if ( part.type === 'text' && part.text ) {
							assistantText += part.text;
						} else if ( part.text && ! part.type ) {
							// Fallback if part doesn't have type
							assistantText += part.text;
						}
					} );
				} else if ( data.text ) {
					assistantText = data.text;
				} else if ( typeof data === 'string' ) {
					assistantText = data;
				}

				if ( assistantText.trim() ) {
					addMessage( 'assistant', assistantText.trim() );
					// Store assistant response in correct format for next request
					// Keep the original parts structure if available, otherwise create it
					// Format: { role: 'assistant', parts: [{ text: '...' }] }
					// For ai-sdk-5, parts should NOT include 'type' field in the request
					messages.push( {
						role: 'assistant',
						parts: data.parts && Array.isArray( data.parts ) && data.parts.length > 0
							? data.parts.map( ( part ) => {
								// Normalize to { text: '...' } format (remove type field for request)
								if ( part.type === 'text' && part.text ) {
									return { text: part.text };
								} else if ( part.text ) {
									return { text: part.text };
								}
								return null;
							} ).filter( ( part ) => part !== null && part.text && part.text.trim().length > 0 )
							: [ { text: assistantText.trim() } ]
					} );
				} else {
					console.warn( '[Algolia Agent Chat] Unexpected response format:', data );
					addMessage( 'assistant', 'I received your message, but the response format was unexpected. Check console for details.' );
				}
			} catch ( error ) {
				console.error( '[Algolia Agent Chat] Error:', error );
				addMessage( 'assistant', 'Sorry, I encountered an error: ' + ( error.message || 'Unknown error' ) + '. Please check console for details.' );
			} finally {
				setLoading( false );
			}
		}

		// Event listeners
		sendBtn.addEventListener( 'click', () => {
			const text = inputEl.value.trim();
			if ( text ) {
				sendMessage( text );
			}
		} );

		inputEl.addEventListener( 'keypress', ( e ) => {
			if ( e.key === 'Enter' && ! e.shiftKey ) {
				e.preventDefault();
				const text = inputEl.value.trim();
				if ( text ) {
					sendMessage( text );
				}
			}
		} );

		// Focus input
		inputEl.focus();
	}

	function escapeHtml( text ) {
		const div = document.createElement( 'div' );
		div.textContent = text;
		return div.innerHTML;
	}

	/**
	 * Last-line-of-defense sanitizer applied right before innerHTML assignment.
	 *
	 * markdownToHtml() already escapes the whole text before applying its
	 * transforms, but this whitelist pass guarantees that only <a>, <strong>,
	 * <em> and <br> (with safe attributes) can ever reach the DOM, even if
	 * the markdown transforms change in the future.
	 */
	function sanitizeMessageHtml( html ) {
		const template = document.createElement( 'template' );
		template.innerHTML = String( html );

		const ALLOWED_ATTRS = {
			A: [ 'href', 'target', 'rel' ],
			STRONG: [],
			EM: [],
			BR: [],
		};

		const walk = ( node ) => {
			Array.from( node.children ).forEach( ( el ) => {
				const allowed = ALLOWED_ATTRS[ el.tagName ];
				if ( ! allowed ) {
					// Disallowed element: replace it with its plain text content.
					el.replaceWith( document.createTextNode( el.textContent ) );
					return;
				}
				Array.from( el.attributes ).forEach( ( attr ) => {
					if ( ! allowed.includes( attr.name ) ) {
						el.removeAttribute( attr.name );
					}
				} );
				if ( el.tagName === 'A' ) {
					el.setAttribute( 'href', sanitizeHref( el.getAttribute( 'href' ) || '' ) );
					el.setAttribute( 'target', '_blank' );
					el.setAttribute( 'rel', 'noopener noreferrer' );
				}
				walk( el );
			} );
		};
		walk( template.content );

		return template.innerHTML;
	}

	function sanitizeHref( input ) {
		if ( typeof input !== 'string' ) {
			return '#';
		}
		const value = input.trim();
		if ( ! value || value === '#' ) {
			return '#';
		}
		if ( typeof window === 'undefined' ) {
			return value;
		}
		try {
			const parsed = new URL( value, window.location.origin );
			if ( parsed.protocol !== 'http:' && parsed.protocol !== 'https:' ) {
				return '#';
			}
			return parsed.toString();
		} catch {
			return '#';
		}
	}

	/**
	 * Convert basic markdown to HTML
	 * Supports: links [text](url), bold **text**, italic *text*, line breaks
	 */
	function markdownToHtml( text ) {
		if ( ! text ) return '';
		
		let html = String( text );
		
		// Escape HTML first to prevent XSS, then convert markdown
		html = escapeHtml( html );
		
		// Convert markdown links: [text](url) to <a href="url">text</a> with strict href sanitization.
		html = html.replace( /\[([^\]]+)\]\(([^)]+)\)/g, ( _, label, rawUrl ) => {
			const safeHref = sanitizeHref( String( rawUrl ) );
			return `<a href="${ safeHref }" target="_blank" rel="noopener noreferrer">${ label }</a>`;
		} );
		
		// Convert bold: **text** to <strong>text</strong>
		html = html.replace( /\*\*([^*]+)\*\*/g, '<strong>$1</strong>' );
		
		// Convert italic: *text* to <em>text</em> (but not if it's part of **text**)
		html = html.replace( /(?<!\*)\*([^*]+)\*(?!\*)/g, '<em>$1</em>' );
		
		// Convert line breaks: \n to <br>
		html = html.replace( /\n/g, '<br>' );
		
		return html;
	}

	// Initialize on DOM ready
	if ( document.readyState === 'loading' ) {
		document.addEventListener( 'DOMContentLoaded', init );
	} else {
		init();
	}
} )();