(() => {
    'use strict';

    /*
     * ========================================================
     * OPENAI BD USER JS V3
     * Sidebar + ONE clean text-chat submit owner
     * ========================================================
     */

    const body = document.body;

    const menuButton =
        document.getElementById('oabdMenuButton');

    const closeButton =
        document.getElementById('oabdSidebarClose');

    const overlay =
        document.getElementById('oabdSidebarOverlay');

    const openSidebar = () => {
        body.classList.add('oabd-sidebar-open');
    };

    const closeSidebar = () => {
        body.classList.remove('oabd-sidebar-open');
    };

    menuButton?.addEventListener(
        'click',
        openSidebar
    );

    closeButton?.addEventListener(
        'click',
        closeSidebar
    );

    overlay?.addEventListener(
        'click',
        closeSidebar
    );

    document.addEventListener(
        'keydown',
        (event) => {
            if (event.key === 'Escape') {
                closeSidebar();
            }
        }
    );


    /*
     * ========================================================
     * TEXT CHAT
     * ========================================================
     */

    const form =
        document.getElementById('oabdComposer');

    const textarea =
        document.getElementById('oabdMessage');

    const sendButton =
        document.getElementById('oabdSendButton');

    const thread =
        document.getElementById('oabdChatThread');

    const welcome =
        document.getElementById('oabdWelcome');

    const conversationInput =
        document.getElementById('oabdConversationId');

    const errorBox =
        document.getElementById('oabdChatError');

    const guestStatus =
        document.getElementById('oabdGuestStatus');

    if (
        !form ||
        !textarea ||
        !sendButton ||
        !thread
    ) {
        window.OpenAIBD = {
            version: 'user-v3',
            ready: true,
            chat: false
        };

        return;
    }


    let sending = false;


    const escapeText = (value) => {
        return String(value ?? '');
    };


    const hideWelcome = () => {
        if (welcome) {
            welcome.hidden = true;
        }
    };


    const scrollToBottom = () => {
        window.requestAnimationFrame(() => {
            window.scrollTo({
                top: document.documentElement.scrollHeight,
                behavior: 'smooth'
            });
        });
    };


    const addMessage = (role, content) => {
        const value =
            escapeText(content).trim();

        if (!value) {
            return;
        }

        hideWelcome();

        const row =
            document.createElement('div');

        row.className =
            'oabd-message ' +
            (
                role === 'user'
                    ? 'oabd-message-user'
                    : 'oabd-message-assistant'
            );

        const bubble =
            document.createElement('div');

        bubble.className =
            'oabd-message-bubble';

        bubble.textContent = value;

        row.appendChild(bubble);
        thread.appendChild(row);

        scrollToBottom();
    };



    /*
     * OPENAI BD STEP 8.6
     * Render a successfully selected attachment
     * inside the user side of the conversation.
     */
    const addUserAttachment = (attachment) => {

        if (
            !attachment ||
            !attachment.file
        ) {
            return;
        }

        const file = attachment.file;

        hideWelcome();

        const row =
            document.createElement('div');

        row.className =
            'oabd-message oabd-message-user oabd-message-attachment-row';

        const card =
            document.createElement('div');

        card.className =
            'oabd-sent-attachment';

        const icon =
            document.createElement('div');

        icon.className =
            'oabd-sent-attachment-icon';

        const ext =
            (
                file.name &&
                file.name.includes('.')
            )
                ? file.name
                    .split('.')
                    .pop()
                    .toUpperCase()
                    .slice(0, 5)
                : 'FILE';

        icon.textContent = ext || 'FILE';

        const info =
            document.createElement('div');

        info.className =
            'oabd-sent-attachment-info';

        const name =
            document.createElement('div');

        name.className =
            'oabd-sent-attachment-name';

        name.textContent =
            file.name || 'Attachment';

        const meta =
            document.createElement('div');

        meta.className =
            'oabd-sent-attachment-meta';

        meta.textContent =
            (ext || 'FILE') +
            ' · ' +
            formatBytes(file.size || 0);

        info.appendChild(name);
        info.appendChild(meta);

        card.appendChild(icon);
        card.appendChild(info);

        row.appendChild(card);
        thread.appendChild(row);

        scrollToBottom();
    };


    const showError = (message) => {
        const value =
            escapeText(message).trim();

        if (!value) {
            errorBox.hidden = true;
            errorBox.textContent = '';
            return;
        }

        errorBox.textContent = value;
        errorBox.hidden = false;
    };


    const updateGuestStatus = (guest) => {
        if (
            !guest ||
            typeof guest !== 'object'
        ) {
            return;
        }

        const remaining =
            Number(guest.remaining ?? 0);

        const limit =
            Number(guest.limit ?? 0);

        if (!limit) {
            return;
        }

        guestStatus.textContent =
            remaining > 0
                ? `${remaining} free message${
                    remaining === 1 ? '' : 's'
                  } remaining`
                : 'Free guest messages used.';

        guestStatus.hidden = false;
    };


    const showAccountRequired = (message) => {
        const box =
            document.createElement('div');

        box.className =
            'oabd-account-required';

        const text =
            document.createElement('div');

        text.textContent =
            message ||
            'Create a free account to continue chatting.';

        const link =
            document.createElement('a');

        link.href = '/register';
        link.textContent = 'Create account';

        box.appendChild(text);
        box.appendChild(link);

        thread.appendChild(box);

        scrollToBottom();
    };


    const resizeTextarea = () => {
        textarea.style.height = 'auto';

        textarea.style.height =
            Math.min(
                textarea.scrollHeight,
                180
            ) + 'px';
    };


    textarea.addEventListener(
        'input',
        resizeTextarea
    );


    const submitChat = async () => {
        if (sending) {
            return;
        }

        const message =
            textarea.value.trim();

        const pendingAttachment =
            typeof window.OpenAIBDGetAttachment === 'function'
                ? window.OpenAIBDGetAttachment()
                : null;

        if (
            !message &&
            !pendingAttachment?.file
        ) {
            textarea.focus();
            return;
        }

        sending = true;
        sendButton.disabled = true;
        sendButton.textContent = '■';

        showError('');

        /*
         * Show user message immediately.
         */
        if (message) {
            addMessage(
                'user',
                message
            );
        }

        /*
         * STEP 8.6
         * Put selected file into the conversation
         * immediately after the user's text.
         */
        if (pendingAttachment?.file) {
            addUserAttachment(
                pendingAttachment
            );
        }

        textarea.value = '';
        resizeTextarea();

        const formData =
            new FormData();

        formData.append(
            'message',
            message
        );

        /*
         * OPENAI BD STEP 7.1 ATTACHMENT SEND
         */
        /*
         * OPENAI BD STEP 8.12
         * Single attachment state owner.
         *
         * pendingAttachment was captured at the very
         * beginning of submitChat(). Do not read the
         * attachment state a second time.
         */
        if (
            pendingAttachment &&
            pendingAttachment.file instanceof File
        ) {
            formData.append(
                'attachment',
                pendingAttachment.file,
                pendingAttachment.file.name || 'attachment'
            );

            formData.append(
                'attachment_source',
                pendingAttachment.source || 'file'
            );

            console.log(
                'OABD SEND ATTACHMENT:',
                pendingAttachment.file.name,
                pendingAttachment.file.type,
                pendingAttachment.file.size
            );
        }

        const conversationId =
            conversationInput?.value?.trim() || '';

        if (conversationId) {
            formData.append(
                'conversation_id',
                conversationId
            );
        }

        /*
         * OPENAI BD STEP 7.5 REQUEST DEBUG
         */
        console.log(
            'OABD SEND DEBUG',
            {
                message: message,
                attachment: selectedAttachment
                    ? {
                        name: selectedAttachment.file?.name,
                        size: selectedAttachment.file?.size,
                        type: selectedAttachment.file?.type,
                        source: selectedAttachment.source
                    }
                    : null,
                formData: Array.from(
                    formData.entries()
                ).map(([key, value]) => [
                    key,
                    value instanceof File
                        ? {
                            name: value.name,
                            size: value.size,
                            type: value.type
                        }
                        : value
                ])
            }
        );

        try {
            const response =
                await fetch(
                    '/api/chat',
                    {
                        method: 'POST',
                        credentials: 'same-origin',
                        headers: {
                            'Accept':
                                'application/json'
                        },
                        body: formData
                    }
                );

            const contentType =
                response.headers.get(
                    'content-type'
                ) || '';

            if (
                !contentType.includes(
                    'application/json'
                )
            ) {
                throw new Error(
                    'Invalid server response.'
                );
            }

            const result =
                await response.json();

            if (
                result?.conversation_id &&
                conversationInput
            ) {
                conversationInput.value =
                    String(
                        result.conversation_id
                    );
            }

            if (result?.guest) {
                updateGuestStatus(
                    result.guest
                );
            }

            if (
                !response.ok ||
                result?.success !== true
            ) {
                if (result?.requires_account) {
                    showAccountRequired(
                        result?.error
                    );
                    return;
                }

                throw new Error(
                    result?.error ||
                    'Unable to send message.'
                );
            }

            const assistantText =
                result?.message?.content;

            if (assistantText) {
                addMessage(
                    'assistant',
                    assistantText
                );
            }

            /*
             * STEP 8.6
             * Request succeeded.
             * Remove attachment from composer.
             */
            window.dispatchEvent(
                new CustomEvent(
                    'oabd:clear-attachment-request'
                )
            );

            if (result?.requires_account) {
                showAccountRequired(
                    'Create a free account to continue chatting.'
                );
            }

        } catch (error) {

            console.error(
                'OpenAI BD chat error:',
                error
            );

            showError(
                error?.message ||
                'Something went wrong.'
            );

        } finally {

            sending = false;

            sendButton.disabled = false;
            sendButton.textContent = '↑';

            textarea.focus();
        }
    };


    /*
     * ONE submit owner.
     */
    form.addEventListener(
        'submit',
        (event) => {
            event.preventDefault();
            submitChat();
        }
    );


    /*
     * Enter = send
     * Shift + Enter = new line
     */
    textarea.addEventListener(
        'keydown',
        (event) => {
            if (
                event.key !== 'Enter' ||
                event.shiftKey ||
                event.isComposing
            ) {
                return;
            }

            event.preventDefault();

            if (!sending) {
                form.requestSubmit();
            }
        }
    );


    window.OpenAIBD = {
        version: 'user-v3',
        ready: true,
        chat: true
    };

})();


/* =========================================================
   OPENAI BD STEP 5 - ATTACHMENT MENU UI
   ========================================================= */

(() => {
    'use strict';

    const attachButton =
        document.getElementById('oabdAttachButton');

    const attachMenu =
        document.getElementById('oabdAttachMenu');

    if (!attachButton || !attachMenu) {
        return;
    }

    const closeMenu = () => {
        attachMenu.hidden = true;

        attachButton.setAttribute(
            'aria-expanded',
            'false'
        );
    };

    const openMenu = () => {
        attachMenu.hidden = false;

        attachButton.setAttribute(
            'aria-expanded',
            'true'
        );
    };

    attachButton.addEventListener(
        'click',
        (event) => {
            event.stopPropagation();

            if (attachMenu.hidden) {
                openMenu();
            } else {
                closeMenu();
            }
        }
    );

    attachMenu.addEventListener(
        'click',
        (event) => {
            event.stopPropagation();

            const action =
                event.target.closest(
                    '[data-attach-action]'
                );

            if (!action) {
                return;
            }

            /*
             * UI only in Step 5.
             * Upload backend will be connected next.
             */
            closeMenu();
        }
    );

    document.addEventListener(
        'click',
        closeMenu
    );

    document.addEventListener(
        'keydown',
        (event) => {
            if (event.key === 'Escape') {
                closeMenu();
            }
        }
    );

})();


/* =========================================================
   OPENAI BD STEP 6 - PICKER + PREVIEW
   No upload/send ownership in this step.
   ========================================================= */

(() => {
    'use strict';

    const attachMenu =
        document.getElementById('oabdAttachMenu');

    const attachButton =
        document.getElementById('oabdAttachButton');

    const photoInput =
        document.getElementById('oabdPhotoInput');

    const fileInput =
        document.getElementById('oabdFileInput');

    const cameraInput =
        document.getElementById('oabdCameraInput');

    const preview =
        document.getElementById('oabdAttachmentPreview');

    const previewThumbnail =
        document.getElementById('oabdPreviewThumbnail');

    const previewName =
        document.getElementById('oabdPreviewName');

    const previewMeta =
        document.getElementById('oabdPreviewMeta');

    const previewRemove =
        document.getElementById('oabdPreviewRemove');


    if (
        !attachMenu ||
        !photoInput ||
        !fileInput ||
        !cameraInput ||
        !preview ||
        !previewThumbnail ||
        !previewName ||
        !previewMeta ||
        !previewRemove
    ) {
        return;
    }


    let selectedFile = null;
    let selectedSource = null;
    let previewUrl = null;


    const formatBytes = (bytes) => {

        const value = Number(bytes || 0);

        if (value < 1024) {
            return value + ' B';
        }

        if (value < 1024 * 1024) {
            return (
                value / 1024
            ).toFixed(1) + ' KB';
        }

        return (
            value / (1024 * 1024)
        ).toFixed(1) + ' MB';
    };


    const extensionOf = (name) => {

        const value =
            String(name || '');

        const parts =
            value.split('.');

        if (parts.length < 2) {
            return 'FILE';
        }

        return parts
            .pop()
            .toUpperCase();
    };


    const revokePreviewUrl = () => {

        if (previewUrl) {

            URL.revokeObjectURL(
                previewUrl
            );

            previewUrl = null;
        }
    };


    const clearInputs = () => {

        photoInput.value = '';
        fileInput.value = '';
        cameraInput.value = '';
    };


    const clearAttachment = () => {

        selectedFile = null;
        selectedSource = null;

        revokePreviewUrl();
        clearInputs();

        previewThumbnail.innerHTML = '';
        previewName.textContent = '';
        previewMeta.textContent = '';

        preview.hidden = true;

        /*
         * Step 7 can use this event without
         * changing the picker code.
         */
        window.dispatchEvent(
            new CustomEvent(
                'oabd:attachment-cleared'
            )
        );
    };


    const showAttachment = (
        file,
        source
    ) => {

        if (
            !file ||
            typeof file !== 'object' ||
            typeof file.name !== 'string'
        ) {
            console.warn(
                'OpenAI BD: invalid attachment object'
            );

            return;
        }

        revokePreviewUrl();

        selectedFile = file;
        selectedSource = source;

        previewThumbnail.innerHTML = '';

        previewName.textContent =
            file.name ||
            (
                source === 'camera'
                    ? 'Camera photo'
                    : 'Attachment'
            );

        previewMeta.textContent =
            extensionOf(file.name) +
            ' · ' +
            formatBytes(file.size);


        if (
            file.type &&
            file.type.startsWith('image/')
        ) {

            previewUrl =
                URL.createObjectURL(file);

            const image =
                document.createElement('img');

            image.src = previewUrl;
            image.alt = '';

            previewThumbnail.appendChild(
                image
            );

        } else {

            previewThumbnail.textContent =
                extensionOf(file.name);
        }


        preview.hidden = false;


        /*
         * Expose selection safely for Step 7.
         * Existing text submit code is NOT modified.
         */
        window.OpenAIBDAttachment = {
            file: selectedFile,
            source: selectedSource
        };


        window.dispatchEvent(
            new CustomEvent(
                'oabd:attachment-selected',
                {
                    detail: {
                        file: selectedFile,
                        source: selectedSource
                    }
                }
            )
        );
    };


    const chooseFile = (
        input,
        source
    ) => {

        const file =
            input.files &&
            input.files[0];

        if (!file) {
            return;
        }

        /*
         * One attachment at a time for the
         * clean first implementation.
         */
        showAttachment(
            file,
            source
        );
    };


    attachMenu.addEventListener(
        'click',
        (event) => {

            const action =
                event.target.closest(
                    '[data-attach-action]'
                );

            if (!action) {
                return;
            }

            const type =
                action.dataset.attachAction;

            if (type === 'photo') {

                photoInput.value = '';
                photoInput.click();

            } else if (type === 'file') {

                fileInput.value = '';
                fileInput.click();

            } else if (type === 'camera') {

                cameraInput.value = '';
                cameraInput.click();
            }
        }
    );


    photoInput.addEventListener(
        'change',
        () => {
            chooseFile(
                photoInput,
                'photo'
            );
        }
    );


    fileInput.addEventListener(
        'change',
        (event) => {

            const input = event.currentTarget;

            if (
                !input ||
                !input.files ||
                input.files.length === 0
            ) {
                console.warn(
                    'OpenAI BD: no file returned by picker'
                );

                return;
            }

            const file = input.files.item(0);

            if (!file) {
                console.warn(
                    'OpenAI BD: selected file unavailable'
                );

                return;
            }

            console.log(
                'OpenAI BD file selected:',
                file.name,
                file.type,
                file.size
            );

            showAttachment(
                file,
                'file'
            );
        }
    );


    cameraInput.addEventListener(
        'change',
        () => {
            chooseFile(
                cameraInput,
                'camera'
            );
        }
    );


    previewRemove.addEventListener(
        'click',
        () => {

            clearAttachment();

            window.OpenAIBDAttachment = null;
        }
    );


    /*
     * Public read-only style helper for Step 7.
     */

    window.addEventListener(
        'oabd:clear-attachment-request',
        () => {
            clearAttachment();
            window.OpenAIBDAttachment = null;
        }
    );


    window.OpenAIBDGetAttachment = () => {

        if (!selectedFile) {
            return null;
        }

        return {
            file: selectedFile,
            source: selectedSource
        };
    };

})();


/* =========================================================
   OPENAI BD STEP 6.4 - NATIVE FILE RESULT DEBUG
   ========================================================= */

(() => {
    'use strict';

    const input =
        document.getElementById('oabdFileInput');

    if (!input) {
        console.error(
            'OABD FILE DEBUG: input missing'
        );
        return;
    }

    input.addEventListener(
        'change',
        (event) => {

            const files =
                event.target.files;

            const count =
                files ? files.length : 0;

            console.log(
                'OABD FILE DEBUG CHANGE',
                count
            );

            if (count > 0) {

                console.log(
                    'OABD FILE DEBUG SELECTED',
                    files[0].name,
                    files[0].type,
                    files[0].size
                );
            }
        }
    );

})();
