/**
 * Niwa AI — MCP Admin Settings page JavaScript.
 *
 * Handles token generation, listing, revocation, and clipboard copy
 * for the MCP server configuration admin page.
 *
 * @since 0.10.69
 */
( function () {
    'use strict';

    /* ────────────────────────────────────
     * Duration label map
     * ──────────────────────────────────── */
    var DURATION_LABELS = {
        '1_day':   '1 Day',
        '1_month': '1 Month',
        '1_year':  '1 Year',
        'never':   'No Expiration',
    };

    /* ────────────────────────────────────
     * Helpers
     * ──────────────────────────────────── */

    /**
     * Format a Unix timestamp (seconds) into a locale string.
     *
     * @param {number|null} ts Unix timestamp in seconds.
     * @return {string} Formatted date or dash.
     */
    function formatDate( ts ) {
        if ( ! ts || ts <= 0 ) {
            return '—';
        }
        return new Date( ts * 1000 ).toLocaleString();
    }

    /**
     * Truncate a JTI string to first 8 characters + ellipsis.
     *
     * @param {string} jti Full JTI value.
     * @return {string} Truncated display value.
     */
    function truncateJti( jti ) {
        if ( ! jti ) {
            return '—';
        }
        if ( jti.length <= 8 ) {
            return jti;
        }
        return jti.substring( 0, 8 ) + '...';
    }

    /**
     * Get a human-readable duration label.
     *
     * @param {string} key Duration key.
     * @return {string} Label.
     */
    function durationLabel( key ) {
        return DURATION_LABELS[ key ] || key || '—';
    }

    /**
     * Set button loading state.
     *
     * @param {HTMLElement} btn    Button element.
     * @param {boolean}     state  True = loading, false = restore.
     * @param {string}      [text] Optional original text to restore.
     */
    function setLoading( btn, state, text ) {
        if ( state ) {
            btn.dataset.originalText = btn.textContent;
            btn.textContent = '...';
            btn.disabled = true;
        } else {
            btn.textContent = text || btn.dataset.originalText || 'Done';
            btn.disabled = false;
        }
    }

    /**
     * Escape HTML entities for safe insertion.
     *
     * @param {string} str Raw string.
     * @return {string} Escaped string.
     */
    function escHtml( str ) {
        var div = document.createElement( 'div' );
        div.appendChild( document.createTextNode( str ) );
        return div.innerHTML;
    }

    /* ────────────────────────────────────
     * API helpers
     * ──────────────────────────────────── */

    /**
     * Perform a REST API request.
     *
     * @param {string} endpoint Relative endpoint under niwa-ai/v1.
     * @param {string} method   HTTP method.
     * @param {Object} [data]   Request body (for POST).
     * @return {Promise<Object>} Parsed JSON response.
     */
    function apiRequest( endpoint, method, data ) {
        var url = niwaMcpAdmin.restUrl.replace( /\/+$/, '' ) + '/' + endpoint;
        var options = {
            method:  method,
            headers: {
                'Content-Type': 'application/json',
                'X-WP-Nonce':   niwaMcpAdmin.nonce,
            },
        };

        if ( data && method !== 'GET' ) {
            options.body = JSON.stringify( data );
        }

        return fetch( url, options ).then( function ( response ) {
            return response.json().then( function ( json ) {
                if ( ! response.ok ) {
                    var msg = ( json && json.message ) ? json.message : 'Request failed.';
                    throw new Error( msg );
                }
                return json;
            } );
        } );
    }

    /* ────────────────────────────────────
     * Load active tokens
     * ──────────────────────────────────── */

    function loadTokens() {
        var loading = document.getElementById( 'niwa-mcp-tokens-loading' );
        var table   = document.getElementById( 'niwa-mcp-tokens-table' );
        var tbody   = document.getElementById( 'niwa-mcp-tokens-body' );
        var empty   = document.getElementById( 'niwa-mcp-tokens-empty' );

        if ( loading ) {
            loading.style.display = 'block';
        }
        if ( table ) {
            table.style.display = 'none';
        }
        if ( empty ) {
            empty.style.display = 'none';
        }

        apiRequest( 'mcp/tokens', 'GET' )
            .then( function ( response ) {
                var tokens = ( response && Array.isArray( response.data ) ) ? response.data : ( Array.isArray( response ) ? response : [] );

                if ( loading ) {
                    loading.style.display = 'none';
                }

                if ( tokens.length === 0 ) {
                    if ( empty ) {
                        empty.style.display = 'block';
                    }
                    return;
                }

                if ( tbody ) {
                    tbody.innerHTML = '';
                }

                tokens.forEach( function ( token ) {
                    var tr = document.createElement( 'tr' );
                    tr.innerHTML =
                        '<td><code>' + escHtml( truncateJti( token.jti ) ) + '</code></td>' +
                        '<td>' + escHtml( token.user_login || token.user_id || '—' ) + '</td>' +
                        '<td>' + escHtml( formatDate( token.created_at ) ) + '</td>' +
                        '<td>' + escHtml( formatDate( token.expires_at ) ) + '</td>' +
                        '<td>' + escHtml( durationLabel( token.duration ) ) + '</td>' +
						'<td>' + escHtml( Array.isArray( token.scopes ) && token.scopes.length ? token.scopes.join( ', ' ) : '—' ) + '</td>' +
                        '<td><button type="button" class="button niwa-btn niwa-btn--secondary niwa-mcp-revoke-btn" data-jti="' + escHtml( token.jti || '' ) + '">' + 'Revoke' + '</button></td>';
                    if ( tbody ) {
                        tbody.appendChild( tr );
                    }
                } );

                // Attach revoke handlers.
                var revokeButtons = document.querySelectorAll( '.niwa-mcp-revoke-btn' );
                revokeButtons.forEach( function ( btn ) {
                    btn.addEventListener( 'click', function () {
                        revokeToken( btn.dataset.jti, btn );
                    } );
                } );

                if ( table ) {
                    table.style.display = '';
                }
            } )
            .catch( function ( err ) {
                if ( loading ) {
                    loading.textContent = 'Error loading tokens: ' + err.message;
                }
            } );
    }

    /* ────────────────────────────────────
     * Generate token
     * ──────────────────────────────────── */

    function generateToken() {
        var btn       = document.getElementById( 'niwa-mcp-generate-btn' );
        var select    = document.getElementById( 'niwa-mcp-duration' );
        var resultDiv = document.getElementById( 'niwa-mcp-token-result' );
        var valueEl   = document.getElementById( 'niwa-mcp-token-value' );
		var readOptions = document.getElementById( 'niwa-mcp-read-options' );
        var duration  = select ? select.value : '1_year';
		var scopes    = readOptions && readOptions.checked ? [ 'read_options' ] : [];

        if ( ! btn ) {
            console.error( '[Niwa MCP] Generate button not found in DOM.' );
            return;
        }

        setLoading( btn, true );

        var url = niwaMcpAdmin.restUrl.replace( /\/+$/, '' ) + '/mcp/token';

        fetch( url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-WP-Nonce': niwaMcpAdmin.nonce,
            },
			body: JSON.stringify( { duration: duration, scopes: scopes } ),
        } )
            .then( function ( response ) {
                return response.text().then( function ( rawText ) {
                    var json;
                    try {
                        json = JSON.parse( rawText );
                    } catch ( e ) {
                        console.error( '[Niwa MCP] Response is NOT valid JSON:', e.message );
                        throw new Error( 'Server returned a non-JSON response.' );
                    }

                    if ( ! response.ok ) {
                        var msg = ( json && json.message ) ? json.message : ( json && json.error ) ? json.error : 'HTTP ' + response.status;
                        console.error( '[Niwa MCP] Server error:', msg, json );
                        throw new Error( msg );
                    }

                    return json;
                } );
            } )
            .then( function ( response ) {
                setLoading( btn, false );

                var tokenData = ( response && response.data ) ? response.data : response;
                var token = ( tokenData && tokenData.token ) ? tokenData.token : '';

                if ( valueEl ) {
                    valueEl.textContent = token;
                } else {
                    console.error( '[Niwa MCP] #niwa-mcp-token-value element NOT found in DOM!' );
                }

                if ( resultDiv ) {
                    resultDiv.classList.add( 'visible' );
                } else {
                    console.error( '[Niwa MCP] #niwa-mcp-token-result element NOT found in DOM!' );
                }

                // Refresh the tokens table.
                loadTokens();
            } )
            .catch( function ( err ) {
                setLoading( btn, false );
                console.error( '[Niwa MCP] GENERATE FAILED:', err.message, err );
                alert( 'Niwa MCP Error: ' + err.message );
            } );
    }

    /* ────────────────────────────────────
     * Revoke token
     * ──────────────────────────────────── */

    function revokeToken( jti, btn ) {
        if ( ! jti ) {
            return;
        }

        var confirmed = confirm( 'Revoke token ' + truncateJti( jti ) + '? This action cannot be undone.' );
        if ( ! confirmed ) {
            return;
        }

        if ( btn ) {
            setLoading( btn, true );
        }

        apiRequest( 'mcp/revoke', 'POST', { jti: jti } )
            .then( function () {
                loadTokens();
            } )
            .catch( function ( err ) {
                if ( btn ) {
                    setLoading( btn, false );
                }
                alert( 'Error: ' + err.message );
            } );
    }

    /* ────────────────────────────────────
     * Copy to clipboard
     * ──────────────────────────────────── */

    function copyToClipboard( text, button ) {
        if ( ! text || ! button ) {
            return;
        }

        var originalText = button.innerHTML;

        function onSuccess() {
            button.classList.add( 'copied' );
            var svgIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>';
            button.innerHTML = svgIcon + ' Copied!';
            setTimeout( function () {
                button.classList.remove( 'copied' );
                button.innerHTML = originalText;
            }, 2000 );
        }

        function onFail() {
            // Fallback: select text in a temporary textarea.
            var textarea = document.createElement( 'textarea' );
            textarea.value = text;
            textarea.style.position = 'fixed';
            textarea.style.left = '-9999px';
            document.body.appendChild( textarea );
            textarea.select();
            try {
                document.execCommand( 'copy' );
                onSuccess();
            } catch ( e ) {
                alert( 'Copy failed. Please select and copy manually.' );
            }
            document.body.removeChild( textarea );
        }

        if ( navigator.clipboard && navigator.clipboard.writeText ) {
            navigator.clipboard.writeText( text ).then( onSuccess ).catch( onFail );
        } else {
            onFail();
        }
    }

    /* ────────────────────────────────────
     * Event listeners
     * ──────────────────────────────────── */

    document.addEventListener( 'DOMContentLoaded', function () {

        // Load tokens on page load.
        loadTokens();

        // Generate token button.
        var generateBtn = document.getElementById( 'niwa-mcp-generate-btn' );
        if ( generateBtn ) {
            generateBtn.addEventListener( 'click', generateToken );
        }

        // Copy buttons (delegate).
        document.addEventListener( 'click', function ( e ) {
            var btn = e.target.closest( '.niwa-mcp-copy-btn' );
            if ( ! btn ) {
                return;
            }

            var targetId = btn.dataset.copyTarget;
            if ( ! targetId ) {
                return;
            }

            var targetEl = document.getElementById( targetId );
            if ( ! targetEl ) {
                return;
            }

            copyToClipboard( targetEl.textContent, btn );
        } );
    } );
} )();
