// ==========================================
// ChatPane Kit — MessageInput Component
// ==========================================
// CM6-powered chat input with markdown highlighting,
// emoji picker, and stop button.
// Independently importable.
//
// v0.37.10: Added MarkdownToolbar, EmojiPicker, stop overlay, aria.
// v0.37.14: Replaced textarea + toolbar with CM.chatInput().
//
// Usage:
//   const inputHandle = useRef(null);
//   html`<${MessageInput} onSend=${fn} onStop=${fn} disabled=${false}
//         streaming=${false} handleRef=${inputHandle} />`

import { EmojiPicker } from './emoji-picker.js';

const { useRef, useState, useCallback, useEffect } = window.hooks;
const html = window.html;

const SEND_SVG = html`
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"
         stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <line x1="22" y1="2" x2="11" y2="13"/>
        <polygon points="22 2 15 22 11 13 2 9 22 2"/>
    </svg>`;

const STOP_SVG = html`
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"
         stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <rect x="4" y="4" width="16" height="16" rx="2"/>
    </svg>`;

const EMOJI_SVG = html`
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"
         stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <circle cx="12" cy="12" r="10"/>
        <path d="M8 14s1.5 2 4 2 4-2 4-2"/>
        <line x1="9" y1="9" x2="9.01" y2="9"/>
        <line x1="15" y1="9" x2="15.01" y2="9"/>
    </svg>`;

// Convert display name to @mention handle (mirrors Go HandleFromName)
function _toHandle(name) {
    return (name || '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
}

/**
 * @param {{
 *   onSend: (text: string) => void,
 *   onStop?: () => void,
 *   disabled?: boolean,
 *   streaming?: boolean,
 *   handleRef?: { current: any },
 *   channelId?: string,
 * }} props
 */
export function MessageInput({ onSend, onStop, disabled, streaming, handleRef, channelId, onTyping }) {
    const containerRef = useRef(null);
    const editorRef = useRef(null);
    const taRef = useRef(null);  // fallback textarea
    const [emojiOpen, setEmojiOpen] = useState(false);
    const onSendRef = useRef(onSend);
    onSendRef.current = onSend;
    const disabledRef = useRef(disabled);
    disabledRef.current = disabled;
    const participantsCache = useRef({ channelId: null, list: null });
    const onTypingRef = useRef(onTyping);
    onTypingRef.current = onTyping;
    const typingTimerRef = useRef(null);
    const isTypingRef = useRef(false);

    // ── CM6 editor lifecycle ────────────────────
    useEffect(() => {
        if (!window.CM?.chatInput || !containerRef.current) return;

        // Build @mention completer bound to current channelId
        const mentionCompleter = async (query) => {
            if (!channelId || !window.sw?.api?.channels?.participants) return [];

            // Fetch and cache participants per channel
            if (participantsCache.current.channelId !== channelId) {
                try {
                    const resp = await window.sw.api.channels.participants(channelId);
                    participantsCache.current = {
                        channelId,
                        list: (resp || []).map(p => ({
                            label: p.display_name || p.participant_id,
                            handle: _toHandle(p.display_name || p.participant_id),
                            type: p.participant_type || 'user',
                        })),
                    };
                } catch (e) {
                    console.warn('[mention] Failed to fetch participants:', e);
                    return [];
                }
            }

            const q = query.toLowerCase();
            const results = participantsCache.current.list.filter(p =>
                p.handle.startsWith(q) || p.label.toLowerCase().includes(q)
            );

            // Add @all option
            if (!q || 'all'.startsWith(q)) {
                results.unshift({ label: 'All users', handle: 'all', type: 'all' });
            }

            return results;
        };

        // Build extensions array with @mention support
        const extraExtensions = window.CM.mentionExtension
            ? window.CM.mentionExtension({ completer: mentionCompleter })
            : [];

        const editor = window.CM.chatInput(containerRef.current, {
            placeholder: 'Type a message\u2026',
            maxHeight: 160,
            extensions: extraExtensions,
            onSubmit: (text) => {
                const trimmed = text?.trim();
                if (trimmed && !disabledRef.current) {
                    onSendRef.current(trimmed);
                    editor.setValue('');
                    // Stop typing on send
                    if (isTypingRef.current) {
                        isTypingRef.current = false;
                        onTypingRef.current?.(false);
                    }
                    if (typingTimerRef.current) clearTimeout(typingTimerRef.current);
                }
            },
            onChange: () => {
                // Emit typing start (debounced: stop after 3s of inactivity)
                if (!isTypingRef.current) {
                    isTypingRef.current = true;
                    onTypingRef.current?.(true);
                }
                if (typingTimerRef.current) clearTimeout(typingTimerRef.current);
                typingTimerRef.current = setTimeout(() => {
                    isTypingRef.current = false;
                    onTypingRef.current?.(false);
                }, 3000);
            },
        });
        editorRef.current = editor;

        return () => {
            editor.destroy();
            editorRef.current = null;
            if (typingTimerRef.current) clearTimeout(typingTimerRef.current);
            if (isTypingRef.current) {
                isTypingRef.current = false;
                onTypingRef.current?.(false);
            }
        };
    }, [channelId]);

    // ── Imperative handle ───────────────────────
    useEffect(() => {
        if (!handleRef) return;
        handleRef.current = {
            getValue() {
                if (editorRef.current) return editorRef.current.getValue();
                return taRef.current?.value || '';
            },
            setValue(val) {
                if (editorRef.current) { editorRef.current.setValue(val || ''); return; }
                if (taRef.current) { taRef.current.value = val || ''; _autoResize(); }
            },
            focus() {
                if (editorRef.current) { editorRef.current.focus(); return; }
                taRef.current?.focus();
            },
            clear() {
                if (editorRef.current) { editorRef.current.setValue(''); return; }
                if (taRef.current) { taRef.current.value = ''; _autoResize(); }
            },
        };
        return () => { handleRef.current = null; };
    }, [handleRef]);

    // ── Fallback textarea helpers ───────────────
    function _autoResize() {
        const ta = taRef.current;
        if (!ta) return;
        ta.style.height = 'auto';
        ta.style.height = Math.min(ta.scrollHeight, 160) + 'px';
    }

    const _onInput = useCallback(() => _autoResize(), []);

    const _onKeyDown = useCallback((e) => {
        if (e.key === 'Enter' && !e.shiftKey) {
            e.preventDefault();
            const text = taRef.current?.value?.trim();
            if (text && !disabled) {
                onSend(text);
                if (taRef.current) { taRef.current.value = ''; _autoResize(); }
            }
        }
    }, [onSend, disabled]);

    const _onClickSend = useCallback(() => {
        const text = editorRef.current
            ? editorRef.current.getValue()?.trim()
            : taRef.current?.value?.trim();
        if (text && !disabled) {
            onSend(text);
            if (editorRef.current) editorRef.current.setValue('');
            else if (taRef.current) { taRef.current.value = ''; _autoResize(); }
        }
    }, [onSend, disabled]);

    // ── Emoji ───────────────────────────────────
    const _insertEmoji = useCallback((emoji) => {
        if (editorRef.current) {
            const view = editorRef.current.getView();
            const pos = view.state.selection.main.head;
            view.dispatch({ changes: { from: pos, insert: emoji } });
            view.focus();
            return;
        }
        // Fallback: textarea
        const ta = taRef.current;
        if (!ta) return;
        ta.focus();
        const start = ta.selectionStart;
        const hasExecCommand = document.queryCommandSupported?.('insertText');
        if (hasExecCommand) {
            document.execCommand('insertText', false, emoji);
        } else {
            ta.value = ta.value.slice(0, start) + emoji + ta.value.slice(ta.selectionEnd);
        }
        const pos = start + emoji.length;
        ta.setSelectionRange(pos, pos);
        _autoResize();
    }, []);

    const _toggleEmoji = useCallback(() => setEmojiOpen(v => !v), []);
    const _closeEmoji = useCallback(() => setEmojiOpen(false), []);

    // ── Render ──────────────────────────────────
    const useCM = !!window.CM?.chatInput;

    return html`
        <div class="sw-chat-pane__input-bar">
            <div class="sw-msg-input__wrap">
                ${useCM
                    ? html`<div ref=${containerRef} class="sw-msg-input__cm-container" />`
                    : html`<textarea
                        ref=${taRef}
                        class="sw-msg-input__textarea"
                        placeholder="Type a message\u2026"
                        rows="1"
                        disabled=${disabled}
                        onInput=${_onInput}
                        onKeyDown=${_onKeyDown}
                        aria-label="Message input"
                    />`}
                <div class="sw-msg-input__buttons">
                    <div class="sw-msg-input__emoji-wrap">
                        <button
                            class="sw-msg-input__emoji-btn"
                            title="Emoji"
                            onClick=${_toggleEmoji}
                            type="button"
                            aria-label="Open emoji picker"
                            aria-expanded=${emojiOpen}
                        >${EMOJI_SVG}</button>
                        <${EmojiPicker}
                            open=${emojiOpen}
                            onSelect=${_insertEmoji}
                            onClose=${_closeEmoji} />
                    </div>
                    ${streaming && onStop
                        ? html`<button
                            class="sw-msg-input__stop"
                            title="Stop generating"
                            onClick=${onStop}
                            aria-label="Stop generating"
                          >${STOP_SVG}</button>`
                        : html`<button
                            class="sw-msg-input__send"
                            title="Send"
                            disabled=${disabled}
                            onClick=${_onClickSend}
                            aria-label="Send message"
                          >${SEND_SVG}</button>`}
                </div>
            </div>
        </div>`;
}
