/**
 * AI Help Widget
 * Floating chat assistant for Powder Coating Logix.
 *
 * Persistence: panel open/closed state, conversation history, rendered messages,
 * and panel height are all stored in sessionStorage so they survive page navigation.
 * Everything resets when the browser tab/session ends.
 */
(function () {
    'use strict';

    const CHAT_ENDPOINT = '/AiHelp/Chat';
    const STORAGE_KEY   = 'aiHelpState';
    const MIN_HEIGHT    = 300;
    const MAX_HEIGHT_VH = 0.85; // 85vh

    // Conversation history for API: [{role:'user'|'assistant', content:'...'}]
    let history = [];

    // Rendered message store for restoring across navigation: [{role, content, html}]
    let renderedMessages = [];

    let isOpen        = false;
    let isSending     = false;
    let startersShown = true;
    let panelHeight   = 520;

    // DOM refs
    let btn, panel, messagesEl, inputEl, sendBtn, clearBtn, closeBtn,
        typingEl, startersEl, tokenEl, resizeHandle;

    // ── Init ─────────────────────────────────────────────────────────────────

    function init() {
        btn          = document.getElementById('ai-help-btn');
        panel        = document.getElementById('ai-help-panel');
        messagesEl   = document.getElementById('ai-help-messages');
        inputEl      = document.getElementById('ai-help-input');
        sendBtn      = document.getElementById('ai-help-send');
        clearBtn     = document.getElementById('ai-help-clear');
        closeBtn     = document.getElementById('ai-help-close');
        typingEl     = document.getElementById('ai-help-typing');
        startersEl   = document.getElementById('ai-help-starters');
        tokenEl      = document.getElementById('ai-help-token');
        resizeHandle = document.getElementById('ai-help-resize');

        if (!btn || !panel) return;

        btn.addEventListener('click', togglePanel);
        closeBtn.addEventListener('click', closePanel);
        clearBtn.addEventListener('click', clearChat);
        sendBtn.addEventListener('click', sendMessage);

        inputEl.addEventListener('keydown', function (e) {
            if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                sendMessage();
            }
        });

        document.querySelectorAll('.ai-help-starter-btn').forEach(function (b) {
            b.addEventListener('click', function () {
                inputEl.value = b.dataset.q;
                sendMessage();
            });
        });

        // Intercept help links inside the widget — navigate without closing
        messagesEl.addEventListener('click', function (e) {
            const link = e.target.closest('[data-help-link]');
            if (link) {
                e.preventDefault();
                const href = link.getAttribute('href');
                if (href) window.location.href = href;
            }
        });

        // Save accurate open state right before any navigation so the new page
        // can restore correctly. This runs after any click handlers that might
        // have changed isOpen, giving us the true final state.
        window.addEventListener('beforeunload', saveState);

        initResize();
        restoreState();
    }

    // ── Resize ───────────────────────────────────────────────────────────────

    function initResize() {
        if (!resizeHandle) return;

        let startY    = 0;
        let startH    = 0;
        let dragging  = false;

        resizeHandle.addEventListener('mousedown', function (e) {
            e.preventDefault();
            dragging = true;
            startY   = e.clientY;
            startH   = panel.offsetHeight;
            resizeHandle.classList.add('dragging');
            document.body.style.userSelect = 'none';
        });

        document.addEventListener('mousemove', function (e) {
            if (!dragging) return;
            // Panel grows upward: dragging mouse UP increases height
            const delta  = startY - e.clientY;
            const maxH   = Math.floor(window.innerHeight * MAX_HEIGHT_VH);
            panelHeight  = Math.min(maxH, Math.max(MIN_HEIGHT, startH + delta));
            panel.style.height = panelHeight + 'px';
        });

        document.addEventListener('mouseup', function () {
            if (!dragging) return;
            dragging = false;
            resizeHandle.classList.remove('dragging');
            document.body.style.userSelect = '';
            saveState();
        });

        // Touch support
        resizeHandle.addEventListener('touchstart', function (e) {
            const touch = e.touches[0];
            startY  = touch.clientY;
            startH  = panel.offsetHeight;
            dragging = true;
        }, { passive: true });

        document.addEventListener('touchmove', function (e) {
            if (!dragging) return;
            const touch  = e.touches[0];
            const delta  = startY - touch.clientY;
            const maxH   = Math.floor(window.innerHeight * MAX_HEIGHT_VH);
            panelHeight  = Math.min(maxH, Math.max(MIN_HEIGHT, startH + delta));
            panel.style.height = panelHeight + 'px';
        }, { passive: true });

        document.addEventListener('touchend', function () {
            if (!dragging) return;
            dragging = false;
            saveState();
        });
    }

    // ── Panel open/close ─────────────────────────────────────────────────────

    function togglePanel() {
        if (isOpen) { closePanel(); } else { openPanel(); }
    }

    function openPanel() {
        panel.hidden = false;
        panel.style.height = panelHeight + 'px';
        isOpen = true;
        btn.setAttribute('aria-expanded', 'true');
        inputEl.focus();
        scrollToBottom();
        saveState();
    }

    function closePanel() {
        panel.hidden = true;
        isOpen = false;
        btn.setAttribute('aria-expanded', 'false');
        saveState();
    }

    // ── Clear chat ───────────────────────────────────────────────────────────

    function clearChat() {
        history          = [];
        renderedMessages = [];
        startersShown    = true;

        // Remove all messages except the static welcome message (first child)
        const msgs = Array.from(messagesEl.children);
        msgs.slice(1).forEach(function (el) { el.remove(); });

        startersEl.hidden = false;
        inputEl.value     = '';
        inputEl.focus();
        saveState();
    }

    // ── Send message ─────────────────────────────────────────────────────────

    async function sendMessage() {
        if (isSending) return;
        const text = inputEl.value.trim();
        if (!text) return;

        startersEl.hidden = true;
        startersShown     = false;
        inputEl.value     = '';

        appendMessage('user', text, escapeHtml(text));
        scrollToBottom();
        saveState();

        isSending         = true;
        sendBtn.disabled  = true;
        typingEl.classList.remove('d-none');
        scrollToBottom();

        try {
            const token   = tokenEl ? tokenEl.value : '';
            // Send history BEFORE appending the current user message
            // (appendMessage already pushed it, so slice off the last entry)
            const payload = {
                message: text,
                history: history.slice(0, -1)
            };

            const res = await fetch(CHAT_ENDPOINT, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'RequestVerificationToken': token
                },
                body: JSON.stringify(payload)
            });

            typingEl.classList.add('d-none');

            if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                const msg = err.error || 'Something went wrong. Please try again.';
                appendMessage('assistant', msg, renderMarkdown(msg));
            } else {
                const data  = await res.json();
                const reply = data.response || 'No response received.';
                appendMessage('assistant', reply, renderMarkdown(reply));
            }
        } catch (err) {
            typingEl.classList.add('d-none');
            const msg = 'Unable to connect. Please check your connection and try again.';
            appendMessage('assistant', msg, renderMarkdown(msg));
        } finally {
            isSending        = false;
            sendBtn.disabled = false;
            scrollToBottom();
            saveState();
            inputEl.focus();
        }
    }

    // ── Append a message bubble ───────────────────────────────────────────────

    function appendMessage(role, content, html) {
        history.push({ role: role, content: content });
        renderedMessages.push({ role: role, content: content, html: html });

        const wrapper = document.createElement('div');
        wrapper.className = 'ai-help-msg ai-help-msg--' + role;

        const bubble = document.createElement('div');
        bubble.className = 'ai-help-msg-bubble';
        bubble.innerHTML = html;

        wrapper.appendChild(bubble);
        messagesEl.appendChild(wrapper);
    }

    // ── Restore bubble from stored HTML (safe — came from our own renderer) ──

    function restoreMessage(role, html) {
        const wrapper = document.createElement('div');
        wrapper.className = 'ai-help-msg ai-help-msg--' + role;

        const bubble = document.createElement('div');
        bubble.className = 'ai-help-msg-bubble';
        bubble.innerHTML = html;

        wrapper.appendChild(bubble);
        messagesEl.appendChild(wrapper);
    }

    // ── sessionStorage persistence ────────────────────────────────────────────

    function saveState() {
        try {
            sessionStorage.setItem(STORAGE_KEY, JSON.stringify({
                open:             isOpen,
                history:          history,
                renderedMessages: renderedMessages,
                startersShown:    startersShown,
                panelHeight:      panelHeight
            }));
        } catch (_) { /* sessionStorage full or unavailable — ignore */ }
    }

    function restoreState() {
        let saved;
        try {
            const raw = sessionStorage.getItem(STORAGE_KEY);
            if (!raw) return;
            saved = JSON.parse(raw);
        } catch (_) { return; }

        if (!saved) return;

        // Restore height first (before showing panel to avoid flicker)
        if (saved.panelHeight && saved.panelHeight >= MIN_HEIGHT) {
            panelHeight = saved.panelHeight;
            panel.style.height = panelHeight + 'px';
        }

        // Restore messages (skip if only the welcome message was ever shown)
        if (saved.renderedMessages && saved.renderedMessages.length > 0) {
            history          = saved.history          || [];
            renderedMessages = saved.renderedMessages || [];

            saved.renderedMessages.forEach(function (m) {
                restoreMessage(m.role, m.html);
            });

            if (!saved.startersShown) {
                startersEl.hidden = true;
                startersShown     = false;
            }
        }

        // Restore open state last
        if (saved.open) {
            openPanel();
        }
    }

    // ── Minimal markdown renderer ─────────────────────────────────────────────

    function renderMarkdown(text) {
        let html = escapeHtml(text);

        // Fenced code blocks
        html = html.replace(/```[\s\S]*?```/g, function (match) {
            const code = match.slice(3, -3).replace(/^\n/, '');
            return '<pre style="font-size:0.8rem;overflow-x:auto;"><code>' + code + '</code></pre>';
        });

        // Inline code
        html = html.replace(/`([^`]+)`/g, '<code>$1</code>');

        // Bold
        html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');

        // Italic
        html = html.replace(/\*([^*]+)\*/g, '<em>$1</em>');

        // Markdown links — only /relative or https:// allowed
        html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, function (_, linkText, url) {
            const safe = url.startsWith('/') || url.startsWith('https://') || url.startsWith('http://');
            if (!safe) return escapeHtml(linkText);
            return '<a href="' + escapeAttr(url) + '" data-help-link="true">' + linkText + '</a>';
        });

        // Build line-by-line for lists
        const lines  = html.split('\n');
        const result = [];
        let inUl = false, inOl = false;

        for (let i = 0; i < lines.length; i++) {
            const line    = lines[i];
            const ulMatch = line.match(/^(\s*)[-*]\s+(.+)/);
            const olMatch = line.match(/^(\s*)\d+\.\s+(.+)/);

            if (ulMatch) {
                if (!inUl) { if (inOl) { result.push('</ol>'); inOl = false; } result.push('<ul>'); inUl = true; }
                result.push('<li>' + ulMatch[2] + '</li>');
            } else if (olMatch) {
                if (!inOl) { if (inUl) { result.push('</ul>'); inUl = false; } result.push('<ol>'); inOl = true; }
                result.push('<li>' + olMatch[2] + '</li>');
            } else {
                if (inUl) { result.push('</ul>'); inUl = false; }
                if (inOl) { result.push('</ol>'); inOl = false; }
                result.push(line.trim() === '' ? '<br>' : '<p>' + line + '</p>');
            }
        }
        if (inUl) result.push('</ul>');
        if (inOl) result.push('</ol>');

        return result.join('\n')
            .replace(/(<br>\s*){2,}/g, '<br>')
            .replace(/<p>\s*<\/p>/g, '');
    }

    function escapeHtml(str) {
        return str
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;');
    }

    function escapeAttr(str) {
        return str.replace(/"/g, '&quot;').replace(/'/g, '&#39;');
    }

    function scrollToBottom() {
        requestAnimationFrame(function () {
            messagesEl.scrollTop = messagesEl.scrollHeight;
        });
    }

    // ── Bootstrap ─────────────────────────────────────────────────────────────

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();
