/**
 * InlineMessageEditor — fluxer-style inline edit UI for a message.
 *
 * Renders a rounded contenteditable box in place of the normal
 * message body. Keyboard model matches fluxer: Enter saves, Escape
 * cancels, Shift+Enter inserts a newline. A secondary "escape to
 * cancel • enter to save" hint sits under the box and doubles as
 * clickable shortcuts (the words `cancel` and `save` are buttons).
 *
 * The editor is a contenteditable `div` rather than a textarea so
 * future work can drop mention pills / custom emoji into the same
 * edit path (matching the composer's behaviour). For v1 we just
 * serialise `innerText` back to plain text on save.
 */
import { useCallback, useEffect, useRef, useState } from 'react';
import { Smiley } from '@phosphor-icons/react';
import styles from './InlineMessageEditor.module.css';

export interface InlineMessageEditorProps {
	/** Current body we're editing — pre-filled into the box. For
	 *  attachments this is the existing caption (MSC2530 `body` is
	 *  the caption when `filename` is set). */
	initialContent: string;
	/** Called with the new text when the user commits. Empty
	 *  strings are allowed (clearing a caption, or blanking a text
	 *  message to effectively delete it — the caller decides). */
	onSave: (newContent: string) => Promise<void> | void;
	/** Called when the user escapes or clicks "cancel". Parent
	 *  should clear its `editingEventId` state. */
	onCancel: () => void;
	/** Placeholder shown when the box is empty. Callers typically
	 *  pass a type-specific hint ("Add a caption…" for attachments,
	 *  "Message" for text). */
	placeholder?: string;
}

export function InlineMessageEditor({
	initialContent,
	onSave,
	onCancel,
	placeholder = 'Message',
}: InlineMessageEditorProps) {
	const editorRef = useRef<HTMLDivElement>(null);
	const [saving, setSaving] = useState(false);
	const [error, setError] = useState<string | null>(null);

	// Seed the editor once on mount with the existing content, then
	// drop the caret at the end so the user can keep typing. A ref
	// rather than React-controlled content so React doesn't fight
	// the contenteditable on every keystroke.
	useEffect(() => {
		const el = editorRef.current;
		if (!el) return;
		el.textContent = initialContent;
		el.focus();
		// Move caret to end of content.
		const range = document.createRange();
		range.selectNodeContents(el);
		range.collapse(false);
		const sel = window.getSelection();
		if (sel) {
			sel.removeAllRanges();
			sel.addRange(range);
		}
		// Intentionally depend on nothing so this only runs once —
		// we don't want to clobber the user's typing if `initialContent`
		// ever changes identity during an edit session.
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, []);

	const handleSave = useCallback(async () => {
		if (saving) return;
		const next = editorRef.current?.innerText ?? '';
		// Trim trailing whitespace but preserve interior newlines so
		// multi-line edits survive round-tripping.
		const trimmed = next.replace(/\s+$/g, '');
		setError(null);
		setSaving(true);
		try {
			await onSave(trimmed);
		} catch (err: any) {
			setError(err?.message || 'Failed to save edit.');
			setSaving(false);
			return;
		}
		setSaving(false);
	}, [onSave, saving]);

	const handleKeyDown = useCallback(
		(e: React.KeyboardEvent<HTMLDivElement>) => {
			if (e.key === 'Escape') {
				e.preventDefault();
				onCancel();
				return;
			}
			if (e.key === 'Enter' && !e.shiftKey) {
				e.preventDefault();
				void handleSave();
				return;
			}
			// Shift+Enter falls through so the contenteditable inserts a
			// line break normally.
		},
		[handleSave, onCancel],
	);

	return (
		<div className={styles.wrapper}>
			<div className={styles.box}>
				<div
					ref={editorRef}
					className={styles.editor}
					contentEditable
					suppressContentEditableWarning
					data-placeholder={placeholder}
					role="textbox"
					aria-multiline="true"
					onKeyDown={handleKeyDown}
				/>
				<button
					type="button"
					className={styles.emojiButton}
					aria-label="Insert emoji"
					// Emoji picker integration for the inline editor
					// is a follow-up — for v1 the button is decorative
					// so the surface visually matches fluxer. Wiring it
					// would reuse the EmojiPicker popover pattern from
					// ChannelTextarea.
					onClick={(e) => e.preventDefault()}
				>
					<Smiley size={18} weight="fill" />
				</button>
			</div>
			{error ? (
				<div className={styles.error}>{error}</div>
			) : (
				<div className={styles.hint}>
					<span>escape to</span>
					<strong onClick={onCancel}>cancel</strong>
					<span className={styles.hintSeparator} />
					<span>enter to</span>
					<strong onClick={() => void handleSave()}>save</strong>
				</div>
			)}
		</div>
	);
}
