import React, { useState, useRef, useEffect, useCallback } from 'react';
import ReactDOM from 'react-dom';
import ReactMarkdown from 'react-markdown';
import remarkBreaks from 'remark-breaks';
import remarkGfm from 'remark-gfm';

const config = window.saiapSeoAgentChat || {};
const { i18n = {} } = config;

// localStorage key based on site domain (from PHP config).
const STORAGE_KEY = `clearpost-chat-${config.domain || 'default'}`;
const MAX_STORED_MESSAGES = 200;

/**
 * Load persisted chat state from localStorage.
 * Returns { messages, compactionSummary } or null on failure.
 */
function loadPersistedChat() {
	try {
		const raw = localStorage.getItem(STORAGE_KEY);
		if (!raw) return null;
		const data = JSON.parse(raw);
		if (!Array.isArray(data.messages) || !data.messages.length) return null;
		return {
			messages: data.messages.slice(-MAX_STORED_MESSAGES),
			compactionSummary: data.compactionSummary || null,
		};
	} catch {
		return null;
	}
}

/**
 * Persist chat state to localStorage.
 */
function persistChat(messages, compactionSummary) {
	try {
		localStorage.setItem(STORAGE_KEY, JSON.stringify({
			messages: messages.slice(-MAX_STORED_MESSAGES),
			compactionSummary: compactionSummary || null,
		}));
	} catch {
		// Silently fail — localStorage full or unavailable
	}
}

/**
 * Suggested prompt chips.
 */
const SUGGESTED_PROMPTS = [
	'What keywords do I have?',
	'Show my calendar this week',
	'Check my rankings',
	'Look up a keyword for me',
];

/**
 * Model selector dropdown.
 */
function ModelSelector({ provider, model, onChangeProvider, onChangeModel }) {
	const models = config.availableModels || {};
	const providerNames = { openai: 'OpenAI', anthropic: 'Anthropic', gemini: 'Google Gemini' };

	const options = [];
	Object.keys(models).forEach((prov) => {
		Object.entries(models[prov]).forEach(([modelId, modelName]) => {
			options.push({ provider: prov, modelId, label: modelName });
		});
	});

	const currentValue = `${provider}::${model}`;

	const handleChange = (e) => {
		const [newProvider, newModel] = e.target.value.split('::');
		onChangeProvider(newProvider);
		onChangeModel(newModel);
		sessionStorage.setItem('saiap-seo-agent-provider', newProvider);
		sessionStorage.setItem('saiap-seo-agent-model', newModel);
	};

	return (
		<select
			className="saiap-seo-agent-model-select"
			value={currentValue}
			onChange={handleChange}
		>
			{options.map(({ provider: prov, modelId, label }) => (
				<option key={`${prov}::${modelId}`} value={`${prov}::${modelId}`}>
					{label}
				</option>
			))}
		</select>
	);
}

/**
 * Single chat message bubble.
 */
function ChatMessage({ role, content }) {
	const isUser = role === 'user';
	return (
		<div className={`saiap-seo-agent-message saiap-seo-agent-message--${isUser ? 'user' : 'assistant'}`}>
			<div className="saiap-seo-agent-message__bubble">
				{isUser ? (
					<p>{content}</p>
				) : (
					<ReactMarkdown remarkPlugins={[remarkBreaks, remarkGfm]}>{content}</ReactMarkdown>
				)}
			</div>
		</div>
	);
}

/**
 * Main SEO Agent Chat component.
 */
function SeoAgentChat() {
	const [isOpen, setIsOpen] = useState(false);
	const [messages, setMessages] = useState(() => {
		const persisted = loadPersistedChat();
		if (persisted) return persisted.messages;
		return [{ role: 'assistant', content: i18n.welcome || "Hi! I'm your SEO assistant." }];
	});
	const [compactionSummary, setCompactionSummary] = useState(() => {
		const persisted = loadPersistedChat();
		return persisted?.compactionSummary || null;
	});
	const [input, setInput] = useState('');
	const [isLoading, setIsLoading] = useState(false);
	const [provider, setProvider] = useState(
		() => sessionStorage.getItem('saiap-seo-agent-provider') || config.currentProvider || 'anthropic'
	);
	const [model, setModel] = useState(
		() => sessionStorage.getItem('saiap-seo-agent-model') || config.currentModel || 'claude-sonnet-4-6'
	);
	const [toolProgress, setToolProgress] = useState([]);
	const messagesEndRef = useRef(null);
	const inputRef = useRef(null);
	const pollTimerRef = useRef(null);

	// Persist messages to localStorage whenever they change.
	useEffect(() => {
		if (messages.length > 1 || messages[0]?.role === 'user') {
			persistChat(messages, compactionSummary);
		}
	}, [messages, compactionSummary]);

	// Whether to show suggested prompts (only when just the welcome message exists).
	const showSuggestions = messages.length === 1 && messages[0]?.role === 'assistant' && !isLoading;

	// Auto-scroll to bottom on new messages or tool progress updates.
	useEffect(() => {
		if (messagesEndRef.current) {
			messagesEndRef.current.scrollIntoView({ behavior: 'smooth' });
		}
	}, [messages, isLoading, toolProgress]);

	// Focus input when drawer opens.
	useEffect(() => {
		if (isOpen && inputRef.current) {
			inputRef.current.focus();
		}
	}, [isOpen]);

	// Cleanup poll timer on unmount.
	useEffect(() => {
		return () => {
			if (pollTimerRef.current) {
				clearTimeout(pollTimerRef.current);
			}
		};
	}, []);

	/**
	 * Poll for job completion.
	 */
	const pollJobStatus = useCallback((jobId, attempts = 0) => {
		const maxAttempts = 180; // 3 minutes at 1s intervals
		if (attempts >= maxAttempts) {
			setIsLoading(false);
			setToolProgress([]);
			setMessages((prev) => [
				...prev,
				{ role: 'assistant', content: 'Sorry, the request timed out. Please try again.' },
			]);
			return;
		}

		const formData = new FormData();
		formData.append('action', 'saiap_seo_agent_chat_status');
		formData.append('nonce', config.nonce);
		formData.append('job_id', jobId);

		fetch(config.ajaxurl, { method: 'POST', body: formData })
			.then((res) => res.json())
			.then((res) => {
				if (!res.success) {
					setIsLoading(false);
					setMessages((prev) => [
						...prev,
						{ role: 'assistant', content: res.data?.message || i18n.error },
					]);
					return;
				}

				const { status, result, error, tool_progress } = res.data;

				if (status === 'completed' && result) {
					setIsLoading(false);
					setToolProgress([]);
					if (result.compaction_summary) {
						// Backend compacted: trim local messages to recent window + new response.
						// This prevents re-firing compaction on every subsequent message.
						setMessages((prev) => {
							const recent = prev.slice(-6); // match backend RECENT_MESSAGES_TO_KEEP
							return [...recent, { role: 'assistant', content: result.chat_message || 'No response.' }];
						});
						setCompactionSummary(result.compaction_summary);
					} else {
						setMessages((prev) => [
							...prev,
							{ role: 'assistant', content: result.chat_message || 'No response.' },
						]);
					}
					// If mutation tools were used, notify the dashboard to refresh.
					const mutationTools = ['update_keyword_status', 'add_keywords', 'update_seo_settings', 'update_calendar_item', 'set_keyword_tracking'];
					const hadMutation = (tool_progress || []).some((t) => mutationTools.includes(t.tool));
					if (hadMutation) {
						window.dispatchEvent(new CustomEvent('clearpost:data-changed'));
					}
				} else if (status === 'error') {
					setIsLoading(false);
					setToolProgress([]);
					setMessages((prev) => [
						...prev,
						{ role: 'assistant', content: error || i18n.error },
					]);
				} else {
					// Update tool progress indicators.
					if (tool_progress && tool_progress.length) {
						setToolProgress(tool_progress);
					}
					// Still pending — poll again (fast to catch tool progress).
					pollTimerRef.current = setTimeout(() => pollJobStatus(jobId, attempts + 1), 1000);
				}
			})
			.catch(() => {
				setIsLoading(false);
				setMessages((prev) => [
					...prev,
					{ role: 'assistant', content: i18n.error },
				]);
			});
	}, []);

	/**
	 * Send a message (from input or programmatically).
	 */
	const sendMessage = useCallback((text) => {
		if (!text || isLoading) return;

		const newMessages = [...messages, { role: 'user', content: text }];
		setMessages(newMessages);
		setInput('');
		setIsLoading(true);

		// Build conversation for the backend (skip the initial welcome).
		const conversationMessages = newMessages
			.filter((m) => !(m.role === 'assistant' && m === messages[0] && messages.length > 1 && newMessages.indexOf(m) === 0))
			.map((m) => ({ role: m.role, content: m.content }));

		const formData = new FormData();
		formData.append('action', 'saiap_seo_agent_chat_send');
		formData.append('nonce', config.nonce);
		formData.append('messages', JSON.stringify(conversationMessages));
		formData.append('provider', provider);
		formData.append('model', model);
		if (compactionSummary) {
			formData.append('compaction_summary', compactionSummary);
		}

		fetch(config.ajaxurl, { method: 'POST', body: formData })
			.then((res) => res.json())
			.then((res) => {
				if (res.success && res.data?.job_id) {
					pollJobStatus(res.data.job_id);
				} else {
					setIsLoading(false);
					setMessages((prev) => [
						...prev,
						{ role: 'assistant', content: res.data?.message || i18n.error },
					]);
				}
			})
			.catch(() => {
				setIsLoading(false);
				setMessages((prev) => [
					...prev,
					{ role: 'assistant', content: i18n.error },
				]);
			});
	}, [isLoading, messages, provider, model, compactionSummary, pollJobStatus]);

	const handleSend = useCallback(() => {
		sendMessage(input.trim());
	}, [input, sendMessage]);

	// Keep a ref to sendMessage so the public API always uses the latest version.
	const sendMessageRef = useRef(sendMessage);
	useEffect(() => { sendMessageRef.current = sendMessage; }, [sendMessage]);

	// Expose a public API for programmatic message sending (e.g., GSC auto-review).
	useEffect(() => {
		window.saiapSeoAgentSendMessage = (text) => {
			if (!text) return;
			setIsOpen(true);
			// Small delay to ensure drawer is rendered before sending.
			setTimeout(() => sendMessageRef.current(text), 150);
		};
		return () => { delete window.saiapSeoAgentSendMessage; };
	}, []);

	// Show a one-time tooltip nudge for new users.
	const [showNudge, setShowNudge] = useState(() => {
		try { return !localStorage.getItem('clearpost-chat-nudge-dismissed'); } catch { return false; }
	});

	const dismissNudge = () => {
		setShowNudge(false);
		try { localStorage.setItem('clearpost-chat-nudge-dismissed', '1'); } catch {}
	};

	const handleNewChat = useCallback(() => {
		if (isLoading) return;
		if (pollTimerRef.current) {
			clearTimeout(pollTimerRef.current);
		}
		// Build a lightweight summary from current messages + existing summary to preserve context.
		const conversationMessages = messages.filter((m) => m.role === 'user' || m.role === 'assistant');
		let newSummary = compactionSummary || null;
		if (conversationMessages.length > 1) {
			const parts = [];
			if (compactionSummary) parts.push(compactionSummary);
			// Summarize recent messages as bullet points
			const recent = conversationMessages.slice(-10);
			const lines = recent.map((m) => `${m.role}: ${m.content.substring(0, 200)}`);
			parts.push(lines.join('\n'));
			newSummary = parts.join('\n\n');
			// Cap at 2000 chars
			if (newSummary.length > 2000) newSummary = newSummary.slice(-2000);
		}
		const clearedMessages = newSummary
			? [{ role: 'assistant', content: 'Chat cleared. I still remember what we discussed — just ask if you want to pick up where we left off.' }]
			: [{ role: 'assistant', content: i18n.welcome || "Hi! I'm your SEO assistant." }];
		setMessages(clearedMessages);
		setCompactionSummary(newSummary);
		setToolProgress([]);
		setInput('');
		persistChat(clearedMessages, newSummary);
	}, [isLoading, messages, compactionSummary]);

	const handleKeyDown = (e) => {
		if (e.key === 'Enter' && !e.shiftKey) {
			e.preventDefault();
			handleSend();
		}
	};

	return (
		<>
			{/* One-time nudge tooltip */}
			{showNudge && !isOpen && (
				<div className="saiap-seo-agent-nudge">
					<span>Meet Clarence, your AI SEO agent. Click to chat!</span>
					<button className="saiap-seo-agent-nudge__close" onClick={dismissNudge} aria-label="Dismiss">
						<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
							<line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" />
						</svg>
					</button>
				</div>
			)}

			{/* Floating trigger button */}
			<button
				className={`saiap-seo-agent-fab ${isOpen ? 'saiap-seo-agent-fab--open' : ''}`}
				onClick={() => { setIsOpen(!isOpen); if (showNudge) dismissNudge(); }}
				title={i18n.title}
				aria-label={i18n.title}
			>
				{isOpen ? (
					<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
						<line x1="18" y1="6" x2="6" y2="18" />
						<line x1="6" y1="6" x2="18" y2="18" />
					</svg>
				) : (
					<svg width="24" height="24" viewBox="-10 -50 481 379" fill="currentColor" style={{ marginTop: '-3px' }}>
						<rect x="17" y="236" width="426" height="43" rx="21.5" />
						<rect x="13.3154" y="142" width="65" height="43" rx="21.5" transform="rotate(18.0386 13.3154 142)" />
						<rect x="108.858" y="32.6328" width="65" height="43" rx="21.5" transform="rotate(52.5368 108.858 32.6328)" />
						<rect x="251.577" y="0.382324" width="65" height="43" rx="21.5" transform="rotate(90.5097 251.577 0.382324)" />
						<rect x="384.875" y="56.9009" width="65" height="43" rx="21.5" transform="rotate(123.768 384.875 56.9009)" />
						<rect x="460.145" y="182.293" width="65" height="43" rx="21.5" transform="rotate(160.788 460.145 182.293)" />
						<path d="M230.5 108C295.393 108 348 160.83 348 226C348 245.06 343.498 263.064 335.507 279H125.493C117.502 263.064 113 245.06 113 226C113 160.83 165.607 108 230.5 108Z" />
					</svg>
				)}
			</button>

			{/* Chat drawer */}
			{isOpen && (
				<div className="saiap-seo-agent-drawer">
					{/* Header */}
					<div className="saiap-seo-agent-drawer__header">
						<div className="saiap-seo-agent-drawer__title-group">
							<span className="saiap-seo-agent-drawer__title">{i18n.title}</span>
							{i18n.subtitle && <span className="saiap-seo-agent-drawer__badge">{i18n.subtitle}</span>}
						</div>
						<div className="saiap-seo-agent-drawer__actions">
							<button
								className="saiap-seo-agent-new-chat"
								onClick={handleNewChat}
								disabled={isLoading || showSuggestions}
								title="Clear chat"
								aria-label="Clear chat"
							>
								Clear
							</button>
							<ModelSelector
								provider={provider}
								model={model}
								onChangeProvider={setProvider}
								onChangeModel={setModel}
							/>
						</div>
					</div>

					{/* Messages */}
					<div className="saiap-seo-agent-drawer__messages">
						{messages.map((msg, idx) => (
							<ChatMessage key={idx} role={msg.role} content={msg.content} />
						))}
						{showSuggestions && (
							<div className="saiap-seo-agent-suggestions">
								{SUGGESTED_PROMPTS.map((prompt) => (
									<button
										key={prompt}
										className="saiap-seo-agent-suggestion-chip"
										onClick={() => sendMessage(prompt)}
									>
										{prompt}
									</button>
								))}
							</div>
						)}
						{isLoading && (
							<div className="saiap-seo-agent-message saiap-seo-agent-message--assistant">
								<div className="saiap-seo-agent-message__bubble saiap-seo-agent-message__bubble--thinking">
									{toolProgress.length > 0 && (
										<div className="saiap-seo-agent-tool-progress">
											{toolProgress.map((step, idx) => (
												<div key={idx} className={`saiap-seo-agent-tool-step saiap-seo-agent-tool-step--${step.status}`}>
													{step.status === 'running' ? (
														<svg className="saiap-seo-agent-tool-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2">
															<circle cx="8" cy="8" r="6" strokeDasharray="20 12" />
														</svg>
													) : (
														<svg className="saiap-seo-agent-tool-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2">
															<polyline points="3 8 6.5 11.5 13 5" />
														</svg>
													)}
													{step.label}
												</div>
											))}
										</div>
									)}
									<div className="saiap-seo-agent-tool-step saiap-seo-agent-tool-step--running">
										<span className="saiap-seo-agent-typing">
											<span /><span /><span />
										</span>
										{i18n.thinking}
									</div>
								</div>
							</div>
						)}
						<div ref={messagesEndRef} />
					</div>

					{/* Input */}
					<div className="saiap-seo-agent-drawer__input">
						<textarea
							ref={inputRef}
							className="saiap-seo-agent-input"
							value={input}
							onChange={(e) => setInput(e.target.value)}
							onKeyDown={handleKeyDown}
							placeholder={i18n.placeholder}
							rows={1}
							disabled={isLoading}
						/>
						<button
							className="saiap-seo-agent-send"
							onClick={handleSend}
							disabled={isLoading || !input.trim()}
						>
							<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
								<line x1="22" y1="2" x2="11" y2="13" />
								<polygon points="22 2 15 22 11 13 2 9 22 2" />
							</svg>
						</button>
					</div>
				</div>
			)}
		</>
	);
}

// Mount when DOM is ready.
document.addEventListener('DOMContentLoaded', () => {
	// While automated trial setup is streaming, the narration view in the main
	// content area is the only chat surface — suppress the drawer FAB so the
	// user isn't presented with two competing chats. (FEAT-ChatDrivenSetup)
	if (config.hidden) {
		return;
	}
	const root = document.getElementById('saiap-seo-agent-chat-root');
	if (root) {
		ReactDOM.render(<SeoAgentChat />, root);
	}
});
