/**
 * Track queue progress component.
 *
 * @package EaLab\WP_Deployer
 */

const handle = () => {
    // Retrieve all tracking queue progress elements.
    const trackingQueueProgressElements = document.querySelectorAll('tracking-queue-progress');

    trackingQueueProgressElements.forEach((trackingQueueProgressElement) => {
        // Check if the element is already initialized.
        if (trackingQueueProgressElement.getAttribute('data-initialized') === 'true') {
            return;
        }

        // Mark the element as initialized.
        trackingQueueProgressElement.setAttribute('data-initialized', 'true');

        // Build the tracking queue progress component.
        trackingQueueProgressElement.innerHTML = `
            <div class="status-text in-progress">${deploy_sync_content__trackingQueueProgress_settings?.text?.loadingQueueStatus ?? 'Loading the queue status…'}</div>
            <div class="output-section"><div>${deploy_sync_content__trackingQueueProgress_settings?.text?.lastHourOutput ?? 'Last hour output:'}</div><div class="output"></div></div>
        `;

        // The value contains the remaining items in the queue.
        const statusText = trackingQueueProgressElement.querySelector('.status-text');

        // The value contains the output of the queue.
        const output = trackingQueueProgressElement.querySelector('.output');

        // Perform a periodic AJAX request to retrieve the queue progress data.
        const intervalId = setInterval(() => {
            // Prevent multiple requests from being sent at the same time.
            if (trackingQueueProgressElement.getAttribute('data-requesting') === 'true') {
                return;
            }

            trackingQueueProgressElement.setAttribute('data-requesting', 'true');

            // This endpoint returns the following data:
            // - progress: Array containing the global progress data.
            //   - pending: The number of steps that are pending.
            // - steps_data: Array of objects containing the data for each step.
            //   - id: The step database ID.
            //   - data_id: The step group ID. Usually "tracking-queue".
            //   - data: The step data. This is a JSON-encoded string, which can be decoded using JSON.parse().
            //     Once decoded, the data is an array of text to output.
            const url = trackingQueueProgressElement.getAttribute('data-url');

            // Add the nonce header to the request.
            const headers = new Headers();
            headers.append('X-WP-Nonce', deploy_sync_content__trackingQueueProgress_settings?.rest?.nonce ?? '');

            // Fetch the data from the endpoint.
            fetch(url, {
                method: 'GET', headers: headers,
            })
                .then((response) => {
                    if (!response.ok) {
                        throw new Error(deploy_sync_content__trackingQueueProgress_settings?.text?.networkError ?? 'A network error occurred.');
                    }

                    return response.json();
                })
                .then((data) => {
                    // Append the output of the queue to the output element.
                    const stepsData = data?.steps_data ?? [];
                    const outputData = stepsData.map((stepData) => {
                        const parsed = JSON.parse(stepData.data ?? '[]');

                        // parsed is a simple key value pair object.
                        // Take each value to build the output.
                        return Object.values(parsed).join('\n');
                    });

                    const joined = outputData.join('\n');

                    if (joined) {
                        // Check if the output is overflown.
                        const wasOverflown = output.scrollHeight > output.clientHeight;
                        const wasScrolledToBottom = output.scrollHeight - output.scrollTop - output.clientHeight <= 1;

                        // Append if the output is not empty.
                        output.textContent = output.textContent + '\n' + joined;

                        // Scroll to the bottom of the output if the element is already scrolled to the bottom,
                        // or scroll to the bottom if the element was not overflown.
                        if (!wasOverflown || wasScrolledToBottom) {
                            output.scrollTop = output.scrollHeight - output.clientHeight;
                        }
                    }

                    const remainingSteps = data.progress.pending;

                    if (remainingSteps) {
                        // Update the remaining items in the queue.
                        statusText.textContent = (deploy_sync_content__trackingQueueProgress_settings?.text?.remainingSteps ?? 'Remaining steps: ') + remainingSteps;
                    } else {
                        statusText.textContent = deploy_sync_content__trackingQueueProgress_settings?.text?.queueProcessed ?? 'The queue has been processed.';

                        // Stop the periodic request.
                        clearInterval(intervalId);

                        // Post a message to tell the (maybe) containing page that we finished.
                        window.parent.postMessage(
                            {
                                type: "queue-processed"
                            }
                        );

                        // Change the class from in-progress to ok.
                        statusText.classList.remove('in-progress');
                        statusText.classList.add('ok');
                    }

                    // Find the last ID returned by the endpoint.
                    const stepsDataLength = stepsData?.length || false;

                    if (stepsDataLength > 0) {
                        // Logically, the last ID is the ID of the last step in the queue
                        // because the steps are ordered by ID.
                        const lastId = stepsData[stepsDataLength - 1].id;

                        // Update the URL to include the last ID for the next request.
                        const urlWithLastId = new URL(url);
                        urlWithLastId.searchParams.set('after_id', lastId);
                        trackingQueueProgressElement.setAttribute('data-url', urlWithLastId.toString());
                    }

                    // Allow the next request to be sent.
                    trackingQueueProgressElement.setAttribute('data-requesting', 'false');
                })
                .catch((error) => {
                    // Stop the periodic request.
                    clearInterval(intervalId);

                    statusText.textContent = error.message;

                    // Change the class from in-progress to error.
                    statusText.classList.remove('in-progress');
                    statusText.classList.add('not-ok');
                });
        }, 1000);
    });
};

handle();
