{% extends "base.html" %}
{% from "_form_helpers.html" import render_field %}

{% block content %}
<div class="px-4 py-5 my-5 text-center">
    <h1 class="display-5 fw-bold text-body-emphasis">Retrieve & Split Data</h1>
    <div class="col-lg-8 mx-auto">
        <p class="lead mb-4">
            Retrieve FHIR bundles from a server, then download as a ZIP file. Split uploaded or retrieved bundle ZIPs into individual resources, downloaded as a ZIP file.
        </p>
    </div>
</div>
<div class="container mt-4">
    <div class="card shadow-sm mb-4">
        <div class="card-header">
            <h4 class="my-0 fw-normal"><i class="bi bi-cloud-download me-2"></i>Retrieve Bundles</h4>
        </div>
        <div class="card-body">
            {% if form.errors %}
                <div class="alert alert-danger">
                    <p><strong>Please correct the following errors:</strong></p>
                    <ul>
                        {% for field, errors in form.errors.items() %}
                            <li>{{ form[field].label.text }}: {{ errors|join(', ') }}</li>
                        {% endfor %}
                    </ul>
                </div>
            {% endif %}
            <form id="retrieveForm" method="POST">
                {{ form.csrf_token(id='retrieve_csrf_token') }}
                <div class="mb-3">
                    <label class="form-label fw-bold">FHIR Server</label>
                    <div class="input-group">
                        <button type="button" class="btn btn-outline-primary" id="toggleServer">
                            <span id="toggleLabel">Use Local </span>
                        </button>
                        {{ form.fhir_server_url(class="form-control", id="fhirServerUrl", style="display: none;", placeholder="e.g., https://fhir.hl7.org.au/aucore/fhir/DEFAULT", **{'aria-describedby': 'fhirServerHelp'}) }}
                    </div>
                    <small id="fhirServerHelp" class="form-text text-muted">Toggle to use local Fhir Server(/fhir proxy) or enter a custom FHIR server URL.</small>
                </div>
                {# Authentication Section (Shown for Custom URL) #}
                <div class="mb-3" id="authSection" style="display: none;">
                    <label class="form-label fw-bold">Authentication</label>
                    <div class="row g-3 align-items-end">
                        <div class="col-md-5">
                            <select class="form-select" id="authType" name="auth_type">
                                <option value="none" selected>None</option>
                                <option value="bearer">Bearer Token</option>
                                <option value="basic">Basic Authentication</option>
                            </select>
                        </div>
                        <div class="col-md-7" id="authInputsGroup" style="display: none;">
                            {# Bearer Token Input #}
                            <div id="bearerTokenInput" style="display: none;">
                                <label for="bearerToken" class="form-label">Bearer Token</label>
                                <input type="password" class="form-control" id="bearerToken" name="bearer_token" placeholder="Enter Bearer Token">
                            </div>
                            {# Basic Auth Inputs #}
                            <div id="basicAuthInputs" style="display: none;">
                                <label for="username" class="form-label">Username</label>
                                <input type="text" class="form-control mb-2" id="username" name="username" placeholder="Enter Username">
                                <label for="password" class="form-label">Password</label>
                                <input type="password" class="form-control" id="password" name="password" placeholder="Enter Password">
                            </div>
                        </div>
                    </div>
                    <small class="form-text text-muted">Select authentication method for the custom FHIR server.</small>
                </div>
                {# Checkbox Row #}
                <div class="row g-3 mb-3 align-items-center">
                    <div class="col-md-6">
                        {{ render_field(form.validate_references, id='validate_references_checkbox') }}
                    </div>
                    <div class="col-md-6" id="fetchReferenceBundlesGroup" style="display: none;">
                        {{ render_field(form.fetch_reference_bundles, id='fetch_reference_bundles_checkbox') }}
                    </div>
                </div>
                <button type="button" class="btn btn-primary mb-3" id="fetchMetadata">Fetch Metadata</button>
                <div class="banner3 mt-3" id="resourceTypes" style="display: none;">
                    <h5>Resource Types</h5>
                    <div class="d-flex flex-wrap gap-2" id="resourceButtons"></div>
                </div>
                <button type="submit" class="btn btn-primary btn-lg w-100" id="retrieveButton" name="submit_retrieve">
                    <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" style="display: none;"></span>
                    <i class="bi bi-arrow-down-circle me-2"></i>{{ form.submit_retrieve.label.text }}
                </button>
                <button type="button" class="btn btn-success btn-lg w-100 mt-2" id="downloadRetrieveButton" style="display: none;">
                    <i class="bi bi-download me-2"></i>Download Retrieved Bundles
                </button>
            </form>
            <div class="card mt-4">
                <div class="card-header">Retrieval Log</div>
                <div class="card-body">
                    <div id="retrieveConsole" class="border p-3 rounded bg-dark text-light" style="height: 200px; overflow-y: auto; font-family: monospace; font-size: 0.85rem;">
                        <span class="text-muted">Retrieval output will appear here...</span>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="card shadow-sm">
        <div class="card-header">
            <h4 class="my-0 fw-normal"><i class="bi bi-scissors me-2"></i>Split Bundles</h4>
        </div>
        <div class="card-body">
            <form id="splitForm" method="POST" enctype="multipart/form-data">
                {{ form.csrf_token(id='split_csrf_token') }}
                <div class="mb-3">
                    <label class="form-label fw-bold">Bundle Source</label>
                    <div class="form-check">
                        <input class="form-check-input" type="radio" name="bundle_source" id="uploadBundles" value="upload" checked>
                        <label class="form-check-label" for="uploadBundles">Upload Bundle ZIP</label>
                    </div>
                    <div class="form-check">
                        <input class="form-check-input" type="radio" name="bundle_source" id="useRetrievedBundles" value="retrieved" {% if not session.get('retrieve_params', {}).get('bundle_zip_path', None) %} disabled {% endif %}>
                        <label class="form-check-label" for="useRetrievedBundles">Use Retrieved Bundles{% if not session.get('retrieve_params', {}).get('bundle_zip_path', None) %} (No bundles retrieved in this session){% endif %}</label>
                    </div>
                </div>
                {{ render_field(form.split_bundle_zip, class="form-control") }}
                <button type="submit" class="btn btn-primary btn-lg w-100" id="splitButton" name="submit_split">
                    <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" style="display: none;"></span>
                    <i class="bi bi-arrow-right-circle me-2"></i>{{ form.submit_split.label.text }}
                </button>
                <button type="button" class="btn btn-success btn-lg w-100 mt-2" id="downloadSplitButton" style="display: none;">
                    <i class="bi bi-download me-2"></i>Download Split Resources
                </button>
            </form>
            <div class="card mt-4">
                <div class="card-header">Splitting Log</div>
                <div class="card-body">
                    <div id="splitConsole" class="border p-3 rounded bg-dark text-light" style="height: 200px; overflow-y: auto; font-family: monospace; font-size: 0.85rem;">
                        <span class="text-muted">Splitting output will appear here...</span>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
    // --- DOM Element References ---
    const retrieveForm = document.getElementById('retrieveForm');
    const splitForm = document.getElementById('splitForm');
    const retrieveButton = document.getElementById('retrieveButton');
    const splitButton = document.getElementById('splitButton');
    const downloadRetrieveButton = document.getElementById('downloadRetrieveButton');
    const downloadSplitButton = document.getElementById('downloadSplitButton');
    const fetchMetadataButton = document.getElementById('fetchMetadata');
    const toggleServerButton = document.getElementById('toggleServer');
    const toggleLabel = document.getElementById('toggleLabel');
    const fhirServerUrlInput = document.getElementById('fhirServerUrl');
    const resourceTypesDiv = document.getElementById('resourceTypes');
    const resourceButtonsContainer = document.getElementById('resourceButtons');
    const retrieveConsole = document.getElementById('retrieveConsole');
    const splitConsole = document.getElementById('splitConsole');
    const bundleSourceRadios = document.getElementsByName('bundle_source');
    const splitBundleZipInput = document.getElementById('split_bundle_zip');
    const splitBundleZipGroup = splitBundleZipInput ? splitBundleZipInput.closest('.form-group') : null;
    const validateReferencesCheckbox = document.getElementById('validate_references_checkbox');
    const fetchReferenceBundlesGroup = document.getElementById('fetchReferenceBundlesGroup');
    const fetchReferenceBundlesCheckbox = document.getElementById('fetch_reference_bundles_checkbox');
    const authSection = document.getElementById('authSection');
    const authTypeSelect = document.getElementById('authType');
    const authInputsGroup = document.getElementById('authInputsGroup');
    const bearerTokenInput = document.getElementById('bearerToken');
    const basicAuthInputs = document.getElementById('basicAuthInputs');
    const usernameInput = document.getElementById('username');
    const passwordInput = document.getElementById('password');
    // --- State & Config Variables ---
    const appMode = '{{ app_mode | default("standalone") | lower }}';
    const apiKey = '{{ api_key }}';
    const sessionZipPath = '{{ session.get("retrieve_params", {}).get("bundle_zip_path", "") }}';
    let useLocalHapi = (appMode !== 'lite');
    let retrieveZipPath = null;
    let splitZipPath = null;
    let fetchedMetadataCache = null;
    let localHapiBaseUrl = ''; // To store the fetched URL
    // --- Helper Functions ---
    const sanitizeText = (str) => str ? String(str).replace(/</g, "&lt;").replace(/>/g, "&gt;") : "";
    // --- UI Update Functions ---
    function updateBundleSourceUI() {
        const selectedSource = Array.from(bundleSourceRadios).find(radio => radio.checked)?.value;
        if (splitBundleZipGroup) {
            splitBundleZipGroup.style.display = selectedSource === 'upload' ? 'block' : 'none';
        }
        if (splitBundleZipInput) {
            splitBundleZipInput.required = selectedSource === 'upload';
        }
    }
    async function fetchLocalUrlAndSetUI() {
        try {
            const response = await fetch('/api/get-local-server-url');
            if (!response.ok) throw new Error('Failed to fetch local server URL.');
            const data = await response.json();
            localHapiBaseUrl = data.url.replace(/\/+$/, ''); // Normalize by removing trailing slashes
            console.log(`Local HAPI URL fetched: ${localHapiBaseUrl}`);
        } catch (error) {
            console.error(error);
            localHapiBaseUrl = '/fhir'; // Fallback to proxy
            alert('Could not fetch local HAPI server URL. Falling back to proxy.');
        } finally {
            updateServerToggleUI();
        }
    }
    function updateServerToggleUI() {
        if (!toggleLabel || !fhirServerUrlInput || !toggleServerButton || !authSection) return;
        if (appMode === 'lite') {
            useLocalHapi = false;
            toggleServerButton.disabled = true;
            toggleServerButton.classList.add('disabled');
            toggleServerButton.style.pointerEvents = 'none';
            toggleServerButton.setAttribute('aria-disabled', 'true');
            toggleServerButton.title = "Local HAPI server is unavailable in Lite mode";
            toggleLabel.textContent = 'Use Custom URL';
            fhirServerUrlInput.style.display = 'block';
            fhirServerUrlInput.placeholder = "Enter FHIR Base URL (Local HAPI unavailable)";
            fhirServerUrlInput.required = true;
            authSection.style.display = 'block';
        } else {
            toggleServerButton.disabled = false;
            toggleServerButton.classList.remove('disabled');
            toggleServerButton.style.pointerEvents = 'auto';
            toggleServerButton.removeAttribute('aria-disabled');
            toggleLabel.textContent = useLocalHapi ? 'Using Local HAPI' : 'Using Custom URL';
            fhirServerUrlInput.style.display = useLocalHapi ? 'none' : 'block';
            fhirServerUrlInput.placeholder = "e.g., https://hapi.fhir.org/baseR4";
            fhirServerUrlInput.required = !useLocalHapi;
            authSection.style.display = useLocalHapi ? 'none' : 'block';
        }
        fhirServerUrlInput.classList.remove('is-invalid');
        updateAuthInputsUI();
        console.log(`Server toggle UI updated: useLocalHapi=${useLocalHapi}, customUrl=${fhirServerUrlInput.value}`);
    }
    function updateAuthInputsUI() {
        if (!authTypeSelect || !authInputsGroup || !bearerTokenInput || !basicAuthInputs) return;
        const authType = authTypeSelect.value;
        authInputsGroup.style.display = (authType === 'bearer' || authType === 'basic') ? 'block' : 'none';
        bearerTokenInput.style.display = authType === 'bearer' ? 'block' : 'none';
        basicAuthInputs.style.display = authType === 'basic' ? 'block' : 'none';
        if (authType !== 'bearer' && bearerTokenInput) bearerTokenInput.value = '';
        if (authType !== 'basic' && usernameInput) usernameInput.value = '';
        if (authType !== 'basic' && passwordInput) passwordInput.value = '';
    }
    function toggleFetchReferenceBundles() {
        if (validateReferencesCheckbox && fetchReferenceBundlesGroup) {
            fetchReferenceBundlesGroup.style.display = validateReferencesCheckbox.checked ? 'block' : 'none';
            if (!validateReferencesCheckbox.checked && fetchReferenceBundlesCheckbox) {
                fetchReferenceBundlesCheckbox.checked = false;
            }
        } else {
            console.warn("Could not find checkbox elements needed for toggling.");
        }
    }
    // --- Event Listeners ---
    bundleSourceRadios.forEach(radio => {
        radio.addEventListener('change', updateBundleSourceUI);
    });
    toggleServerButton.addEventListener('click', () => {
        if (appMode === 'lite') return;
        useLocalHapi = !useLocalHapi;
        if (useLocalHapi) fhirServerUrlInput.value = '';
        updateServerToggleUI();
        resourceTypesDiv.style.display = 'none';
        fetchedMetadataCache = null;
        console.log(`Server toggled: useLocalHapi=${useLocalHapi}`);
    });
    if (authTypeSelect) {
        authTypeSelect.addEventListener('change', updateAuthInputsUI);
    }
    if (validateReferencesCheckbox) {
        validateReferencesCheckbox.addEventListener('change', toggleFetchReferenceBundles);
    } else {
        console.warn("Validate references checkbox not found.");
    }
    fetchMetadataButton.addEventListener('click', async () => {
        resourceButtonsContainer.innerHTML = '<span class="text-muted">Fetching...</span>';
        resourceTypesDiv.style.display = 'block';
        let customUrl = null;
        if (!useLocalHapi) {
            customUrl = fhirServerUrlInput.value.trim().replace(/\/+$/, ''); // Normalize custom URL
            if (!customUrl) {
                fhirServerUrlInput.classList.add('is-invalid');
                alert('Please enter a valid FHIR server URL.');
                resourceButtonsContainer.innerHTML = '<span class="text-danger">Error: Custom URL required.</span>';
                return;
            }
            try { new URL(customUrl); } catch (_) {
                fhirServerUrlInput.classList.add('is-invalid');
                alert('Invalid custom URL format.');
                resourceButtonsContainer.innerHTML = '<span class="text-danger">Error: Invalid URL format.</span>';
                return;
            }
        }
        fhirServerUrlInput.classList.remove('is-invalid');
        fetchMetadataButton.disabled = true;
        fetchMetadataButton.textContent = 'Fetching...';
        try {
            // Build URL and headers based on the toggle state
            let fetchUrl;
            const headers = { 'Accept': 'application/fhir+json' };
            if (useLocalHapi) {
                if (!localHapiBaseUrl) {
                    throw new Error("Local HAPI URL not available. Please refresh.");
                }
                fetchUrl = `${localHapiBaseUrl}/metadata`; // localHapiBaseUrl is already normalized
                console.log(`Fetching metadata directly from local URL: ${fetchUrl}`);
            } else {
                fetchUrl = `${customUrl}/metadata`;
                // Add authentication headers for the direct request to the custom server
                const authType = authTypeSelect.value;
                if (authType === 'bearer' && bearerTokenInput && bearerTokenInput.value) {
                    headers['Authorization'] = `Bearer ${bearerTokenInput.value}`;
                } else if (authType === 'basic' && usernameInput && passwordInput && usernameInput.value && passwordInput.value) {
                    const credentials = btoa(`${usernameInput.value}:${passwordInput.value}`);
                    headers['Authorization'] = `Basic ${credentials}`;
                }
                console.log(`Fetching metadata directly from custom URL: ${fetchUrl}`);
            }
            console.log(`Request Headers sent: ${JSON.stringify(headers)}`);
            const response = await fetch(fetchUrl, { method: 'GET', headers: headers });
            if (!response.ok) {
                let errorText = `Request failed with status ${response.status} ${response.statusText}`;
                try { const errorBody = await response.text(); errorText += ` - Body: ${errorBody.substring(0, 200)}...`; } catch (e) {}
                console.error(`Metadata fetch failed: ${errorText}`);
                throw new Error(errorText);
            }
            const data = await response.json();
            console.log("Metadata received:", JSON.stringify(data, null, 2).substring(0, 500));
            fetchedMetadataCache = data;
            const resourceTypes = data.rest?.[0]?.resource?.map(r => r.type)?.filter(Boolean) || [];
            resourceButtonsContainer.innerHTML = '';
            if (!resourceTypes.length) {
                resourceButtonsContainer.innerHTML = '<span class="text-warning">No resource types found in metadata.</span>';
            } else {
                resourceTypes.sort().forEach(type => {
                    const button = document.createElement('button');
                    button.type = 'button';
                    button.className = 'btn btn-outline-primary btn-sm me-2 mb-2';
                    button.textContent = type;
                    button.dataset.resource = type;
                    button.addEventListener('click', () => {
                        button.classList.toggle('active');
                        button.classList.toggle('btn-primary');
                        button.classList.toggle('btn-outline-primary');
                    });
                    resourceButtonsContainer.appendChild(button);
                });
            }
        } catch (e) {
            console.error('Metadata fetch error:', e);
            resourceButtonsContainer.innerHTML = `<span class="text-danger">Error: ${e.message}</span>`;
            resourceTypesDiv.style.display = 'block';
            alert(`Error fetching metadata: ${e.message}`);
            fetchedMetadataCache = null;
        } finally {
            fetchMetadataButton.disabled = false;
            fetchMetadataButton.textContent = 'Fetch Metadata';
        }
    });
    retrieveForm.addEventListener('submit', async (e) => {
        e.preventDefault();
        const spinner = retrieveButton.querySelector('.spinner-border');
        const icon = retrieveButton.querySelector('i');
        retrieveButton.disabled = true;
        if (spinner) spinner.style.display = 'inline-block';
        if (icon) icon.style.display = 'none';
        downloadRetrieveButton.style.display = 'none';
        retrieveZipPath = null;
        retrieveConsole.innerHTML = `<div>${new Date().toLocaleTimeString()} [INFO] Starting bundle retrieval...</div>`;
        const selectedResources = Array.from(resourceButtonsContainer.querySelectorAll('.btn.active')).map(btn => btn.dataset.resource);
        if (!selectedResources.length) {
            alert('Please select at least one resource type.');
            retrieveButton.disabled = false;
            if (spinner) spinner.style.display = 'none';
            if (icon) icon.style.display = 'inline-block';
            return;
        }
        const currentFhirServerUrl = useLocalHapi ? localHapiBaseUrl : fhirServerUrlInput.value.trim().replace(/\/+$/, '');
        if (!currentFhirServerUrl) {
            alert('FHIR Server URL is required.');
            fhirServerUrlInput.classList.add('is-invalid');
            retrieveButton.disabled = false;
            if (spinner) spinner.style.display = 'none';
            if (icon) icon.style.display = 'inline-block';
            return;
        }
        const formData = new FormData();
        const csrfTokenInput = retrieveForm.querySelector('input[name="csrf_token"]');
        if (csrfTokenInput) formData.append('csrf_token', csrfTokenInput.value);
        selectedResources.forEach(res => formData.append('resources', res));
        formData.append('fhir_server_url', currentFhirServerUrl);
        if (validateReferencesCheckbox) {
            formData.append('validate_references', validateReferencesCheckbox.checked ? 'true' : 'false');
        }
        if (fetchReferenceBundlesCheckbox) {
            if (validateReferencesCheckbox && validateReferencesCheckbox.checked) {
                formData.append('fetch_reference_bundles', fetchReferenceBundlesCheckbox.checked ? 'true' : 'false');
            } else {
                formData.append('fetch_reference_bundles', 'false');
            }
        } else {
            formData.append('fetch_reference_bundles', 'false');
        }
        if (!useLocalHapi && authTypeSelect) {
            const authType = authTypeSelect.value;
            formData.append('auth_type', authType);
            if (authType === 'bearer' && bearerTokenInput) {
                if (!bearerTokenInput.value) {
                    alert('Please enter a Bearer Token.');
                    retrieveButton.disabled = false;
                    if (spinner) spinner.style.display = 'none';
                    if (icon) icon.style.display = 'inline-block';
                    return;
                }
                formData.append('bearer_token', bearerTokenInput.value);
            } else if (authType === 'basic' && usernameInput && passwordInput) {
                if (!usernameInput.value || !passwordInput.value) {
                    alert('Please enter both Username and Password for Basic Authentication.');
                    retrieveButton.disabled = false;
                    if (spinner) spinner.style.display = 'none';
                    if (icon) icon.style.display = 'inline-block';
                    return;
                }
                formData.append('username', usernameInput.value);
                formData.append('password', passwordInput.value);
            }
        }
        const headers = {
            'Accept': 'application/x-ndjson',
            'X-CSRFToken': csrfTokenInput ? csrfTokenInput.value : '',
            'X-API-Key': apiKey
        };
        console.log(`Submitting retrieve request. Server: ${currentFhirServerUrl}, ValidateRefs: ${formData.get('validate_references')}, FetchRefBundles: ${formData.get('fetch_reference_bundles')}, AuthType: ${formData.get('auth_type')}`);
        try {
            const response = await fetch('/api/retrieve-bundles', { method: 'POST', headers: headers, body: formData });
            if (!response.ok) {
                const errorData = await response.json().catch(() => ({ message: 'Failed to parse error response.' }));
                throw new Error(`HTTP ${response.status}: ${errorData.message || 'Unknown error during retrieval'}`);
            }
            retrieveZipPath = response.headers.get('X-Zip-Path');
            console.log(`Received X-Zip-Path: ${retrieveZipPath}`);
            const reader = response.body.getReader();
            const decoder = new TextDecoder();
            let buffer = '';
            while (true) {
                const { done, value } = await reader.read();
                if (done) break;
                buffer += decoder.decode(value, { stream: true });
                const lines = buffer.split('\n');
                buffer = lines.pop() || '';
                for (const line of lines) {
                    if (!line.trim()) continue;
                    try {
                        const data = JSON.parse(line);
                        const timestamp = new Date().toLocaleTimeString();
                        let messageClass = 'text-info';
                        let prefix = '[INFO]';
                        if (data.type === 'error') { prefix = '[ERROR]'; messageClass = 'text-danger'; }
                        else if (data.type === 'warning') { prefix = '[WARNING]'; messageClass = 'text-warning'; }
                        else if (data.type === 'success') { prefix = '[SUCCESS]'; messageClass = 'text-success'; }
                        else if (data.type === 'progress') { prefix = '[PROGRESS]'; messageClass = 'text-light'; }
                        else if (data.type === 'complete') { prefix = '[COMPLETE]'; messageClass = 'text-primary'; }
                        const messageDiv = document.createElement('div');
                        messageDiv.className = messageClass;
                        messageDiv.innerHTML = `${timestamp} ${prefix} ${sanitizeText(data.message)}`;
                        retrieveConsole.appendChild(messageDiv);
                        retrieveConsole.scrollTop = retrieveConsole.scrollHeight;
                        if (data.type === 'complete' && retrieveZipPath) {
                            const completeData = data.data || {};
                            const bundlesFound = (completeData.total_initial_bundles > 0) || (completeData.fetched_individual_references > 0) || (completeData.fetched_type_bundles > 0);
                            if (!bundlesFound) {
                                retrieveConsole.innerHTML += `<div class="text-warning">${timestamp} [WARNING] No bundles were retrieved. Check server data or resource selection.</div>`;
                            } else {
                                downloadRetrieveButton.style.display = 'block';
                                const useRetrievedRadio = document.getElementById('useRetrievedBundles');
                                const useRetrievedLabel = useRetrievedRadio?.nextElementSibling;
                                if (useRetrievedRadio) useRetrievedRadio.disabled = false;
                                if (useRetrievedLabel) useRetrievedLabel.textContent = 'Use Retrieved Bundles';
                            }
                        }
                    } catch (e) { console.error('Stream parse error:', e, 'Line:', line); }
                }
            }
            if (buffer.trim()) { /* Handle final buffer */ }
        } catch (e) {
            console.error('Retrieval error:', e);
            const ts = new Date().toLocaleTimeString();
            retrieveConsole.innerHTML += `<div class="text-danger">${ts} [ERROR] ${sanitizeText(e.message)}</div>`;
            retrieveConsole.scrollTop = retrieveConsole.scrollHeight;
        } finally {
            retrieveButton.disabled = false;
            if (spinner) spinner.style.display = 'none';
            if (icon) icon.style.display = 'inline-block';
        }
    });
    downloadRetrieveButton.addEventListener('click', () => {
        if (retrieveZipPath) {
            const filename = retrieveZipPath.split('/').pop() || 'retrieved_bundles.zip';
            const downloadUrl = `/tmp/${filename}`;
            console.log(`Attempting to download ZIP from Flask endpoint: ${downloadUrl}`);
            const link = document.createElement('a');
            link.href = downloadUrl;
            link.download = 'retrieved_bundles.zip';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            setTimeout(() => {
                const csrfToken = retrieveForm.querySelector('input[name="csrf_token"]')?.value || '';
                fetch('/clear-session', { method: 'POST', headers: { 'X-CSRFToken': csrfToken }})
                    .then(() => console.log("Session clear requested."))
                    .catch(err => console.error("Session clear failed:", err));
                downloadRetrieveButton.style.display = 'none';
                retrieveZipPath = null;
                const useRetrievedRadio = document.getElementById('useRetrievedBundles');
                const useRetrievedLabel = useRetrievedRadio?.nextElementSibling;
                if (useRetrievedRadio) useRetrievedRadio.disabled = true;
                if (useRetrievedLabel) useRetrievedLabel.textContent = 'Use Retrieved Bundles (No bundles retrieved in this session)';
            }, 500);
        } else {
            console.error("No retrieve ZIP path available for download");
            alert("Download error: No file path available.");
        }
    });
    splitForm.addEventListener('submit', async (e) => {
        e.preventDefault();
        const spinner = splitButton.querySelector('.spinner-border');
        const icon = splitButton.querySelector('i');
        splitButton.disabled = true;
        if (spinner) spinner.style.display = 'inline-block';
        if (icon) icon.style.display = 'none';
        downloadSplitButton.style.display = 'none';
        splitZipPath = null;
        splitConsole.innerHTML = `<div>${new Date().toLocaleTimeString()} [INFO] Starting bundle splitting...</div>`;
        const formData = new FormData();
        const csrfTokenInput = splitForm.querySelector('input[name="csrf_token"]');
        if (csrfTokenInput) formData.append('csrf_token', csrfTokenInput.value);
        const bundleSource = Array.from(bundleSourceRadios).find(radio => radio.checked)?.value;
        if (bundleSource === 'upload') {
            if (!splitBundleZipInput || splitBundleZipInput.files.length === 0) {
                alert('Please select a ZIP file to upload for splitting.');
                splitButton.disabled = false;
                if (spinner) spinner.style.display = 'none';
                if (icon) icon.style.display = 'inline-block';
                return;
            }
            formData.append('split_bundle_zip', splitBundleZipInput.files[0]);
            console.log("Splitting uploaded file:", splitBundleZipInput.files[0].name);
        } else if (bundleSource === 'retrieved' && sessionZipPath) {
            formData.append('split_bundle_zip_path', sessionZipPath);
            console.log("Splitting retrieved bundle path:", sessionZipPath);
        } else if (bundleSource === 'retrieved' && !sessionZipPath) {
            if (retrieveZipPath) {
                formData.append('split_bundle_zip_path', retrieveZipPath);
                console.log("Splitting retrieve bundle path from current run:", retrieveZipPath);
            } else {
                alert('No bundle source available. Please retrieve bundles first or upload a ZIP.');
                splitButton.disabled = false;
                if (spinner) spinner.style.display = 'none';
                if (icon) icon.style.display = 'inline-block';
                return;
            }
        } else {
            alert('No bundle source selected.');
            splitButton.disabled = false;
            if (spinner) spinner.style.display = 'none';
            if (icon) icon.style.display = 'inline-block';
            return;
        }
        const headers = {
            'Accept': 'application/x-ndjson',
            'X-CSRFToken': csrfTokenInput ? csrfTokenInput.value : '',
            'X-API-Key': apiKey
        };
        try {
            const response = await fetch('/api/split-bundles', { method: 'POST', headers: headers, body: formData });
            if (!response.ok) {
                const errorMsg = await response.text();
                let detail = errorMsg;
                try { const errorJson = JSON.parse(errorMsg); detail = errorJson.message || errorJson.error || JSON.stringify(errorJson); } catch (e) {}
                throw new Error(`HTTP ${response.status}: ${detail}`);
            }
            splitZipPath = response.headers.get('X-Zip-Path');
            console.log(`Received X-Zip-Path for split: ${splitZipPath}`);
            const reader = response.body.getReader();
            const decoder = new TextDecoder();
            let buffer = '';
            while (true) {
                const { done, value } = await reader.read();
                if (done) break;
                buffer += decoder.decode(value, { stream: true });
                const lines = buffer.split('\n');
                buffer = lines.pop() || '';
                for (const line of lines) {
                    if (!line.trim()) continue;
                    try {
                        const data = JSON.parse(line);
                        const timestamp = new Date().toLocaleTimeString();
                        let messageClass = 'text-info';
                        let prefix = '[INFO]';
                        if (data.type === 'error') { prefix = '[ERROR]'; messageClass = 'text-danger'; }
                        else if (data.type === 'success') { prefix = '[SUCCESS]'; messageClass = 'text-success'; }
                        else if (data.type === 'progress') { prefix = '[PROGRESS]'; messageClass = 'text-light'; }
                        else if (data.type === 'complete') { prefix = '[COMPLETE]'; messageClass = 'text-primary'; }
                        const messageDiv = document.createElement('div');
                        messageDiv.className = messageClass;
                        messageDiv.innerHTML = `${timestamp} ${prefix} ${sanitizeText(data.message)}`;
                        splitConsole.appendChild(messageDiv);
                        splitConsole.scrollTop = splitConsole.scrollHeight;
                        if (data.type === 'complete' && splitZipPath) {
                            downloadSplitButton.style.display = 'block';
                        }
                    } catch (e) { console.error('Stream parse error:', e, 'Line:', line); }
                }
            }
            if (buffer.trim()) { /* Handle final buffer */ }
        } catch (e) {
            console.error('Splitting error:', e);
            const ts = new Date().toLocaleTimeString();
            splitConsole.innerHTML += `<div class="text-danger">${ts} [ERROR] ${sanitizeText(e.message)}</div>`;
            splitConsole.scrollTop = splitConsole.scrollHeight;
        } finally {
            splitButton.disabled = false;
            if (spinner) spinner.style.display = 'none';
            if (icon) icon.style.display = 'inline-block';
        }
    });
    downloadSplitButton.addEventListener('click', () => {
        if (splitZipPath) {
            const filename = splitZipPath.split('/').pop() || 'split_resources.zip';
            const downloadUrl = `/tmp/${filename}`;
            console.log(`Attempting to download split ZIP from Flask endpoint: ${downloadUrl}`);
            const link = document.createElement('a');
            link.href = downloadUrl;
            link.download = 'split_resources.zip';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            setTimeout(() => {
                const csrfToken = splitForm.querySelector('input[name="csrf_token"]')?.value || '';
                fetch('/clear-session', { method: 'POST', headers: { 'X-CSRFToken': csrfToken }})
                    .then(() => console.log("Session clear requested after split download."))
                    .catch(err => console.error("Session clear failed:", err));
                downloadSplitButton.style.display = 'none';
                splitZipPath = null;
            }, 500);
        } else {
            console.error("No split ZIP path available for download");
            alert("Download error: No file path available.");
        }
    });
    // --- Initial Setup Calls ---
    updateBundleSourceUI();
    fetchLocalUrlAndSetUI();
    toggleFetchReferenceBundles();
});
</script>
{% endblock %}