{% extends "base.html" %}

{% block content %}
<div class="px-4 py-5 my-5 text-center">
    <img class="d-block mx-auto mb-4" src="{{ url_for('static', filename='FHIRFLARE.png') }}" alt="FHIRFLARE IG Toolkit" width="192" height="192">
    <h1 class="display-5 fw-bold text-body-emphasis">FHIR API Explorer</h1>
    <div class="col-lg-6 mx-auto">
        <p class="lead mb-4">
            Interact with FHIR servers using GET, POST, PUT, or DELETE requests. Toggle between local HAPI or a custom server to explore resources or perform searches.
        </p>
    </div>
</div>

<div class="container mt-4">
    <div class="card">
        <div class="card-header"><i class="bi bi-cloud-arrow-down me-2"></i>Send FHIR Request</div>
        <div class="card-body">
            <form id="fhirRequestForm" onsubmit="return false;">
                {{ form.hidden_tag() }}
                <div class="mb-3">
                    <label class="form-label">FHIR Server</label>
                    <div class="input-group">
                        <button type="button" class="btn btn-outline-primary" id="toggleServer">
                            <span id="toggleLabel">Use Local Server</span>
                        </button>
                        <input type="text" class="form-control" id="fhirServerUrl" name="fhir_server_url" placeholder="e.g., https://hapi.fhir.org/baseR4" style="display: none;" aria-describedby="fhirServerHelp">
                    </div>
                    <small id="fhirServerHelp" class="form-text text-muted">Toggle to use local HAPI (http://localhost:8080/fhir) or enter a custom FHIR server URL.</small>
                </div>
                <div class="mb-3" id="authSection" style="display: none;">
                    <label class="form-label">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;">
                            <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>
                            <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>
                <div class="mb-3">
                    <label for="fhirPath" class="form-label">FHIR Path</label>
                    <input type="text" class="form-control" id="fhirPath" name="fhir_path" placeholder="e.g., Patient/wang-li" required aria-describedby="fhirPathHelp">
                    <small id="fhirPathHelp" class="form-text text-muted">Enter a resource path (e.g., Patient, Observation/example) or '_search' for search queries.</small>
                </div>
                <div class="mb-3">
                    <label class="form-label">Request Type</label>
                    <div class="d-flex gap-2 flex-wrap">
                        <input type="radio" class="btn-check" name="method" id="get" value="GET" checked>
                        <label class="btn btn-outline-success" for="get"><span class="badge bg-success">GET</span></label>
                        <input type="radio" class="btn-check" name="method" id="post" value="POST">
                        <label class="btn btn-outline-primary" for="post"><span class="badge bg-primary">POST</span></label>
                        <input type="radio" class="btn-check" name="method" id="put" value="PUT">
                        <label class="btn btn-outline-warning" for="put"><span class="badge bg-warning text-dark">PUT</span></label>
                        <input type="radio" class="btn-check" name="method" id="delete" value="DELETE">
                        <label class="btn btn-outline-danger" for="delete"><span class="badge bg-danger">DELETE</span></label>
                    </div>
                </div>
                <div class="mb-3" id="requestBodyGroup" style="display: none;">
                    <div class="d-flex align-items-center mb-2">
                        <label for="requestBody" class="form-label me-2 mb-0">Request Body</label>
                        <button type="button" class="btn btn-outline-secondary btn-sm btn-copy" id="copyRequestBody" title="Copy to Clipboard"><i class="bi bi-clipboard"></i></button>
                    </div>
                    <textarea class="form-control" id="requestBody" name="request_body" rows="6" placeholder="For POST: JSON resource (e.g., {'resourceType': 'Patient', ...}) or search params (e.g., name=John&birthdate=gt2000)"></textarea>
                    <div id="jsonError" class="text-danger mt-1" style="display: none;"></div>
                </div>
                <button type="button" class="btn btn-primary" id="sendRequest">Send Request</button>
            </form>
        </div>
    </div>

    <div class="card mt-4" id="responseCard" style="display: none;">
        <div class="card-header">Response</div>
        <div class="card-body">
            <h5>Status: <span id="responseStatus" class="badge"></span></h5>
            <div class="d-flex align-items-center mb-2">
                <h6 class="me-2 mb-0">Headers</h6>
                <button type="button" class="btn btn-outline-secondary btn-sm btn-copy" id="copyResponseHeaders" title="Copy to Clipboard"><i class="bi bi-clipboard"></i></button>
            </div>
            <pre id="responseHeaders" class="border p-2 bg-light mb-3" style="max-height: 200px; overflow-y: auto;"></pre>
            <div class="d-flex align-items-center mb-2">
                <h6 class="me-2 mb-0">Body</h6>
                <button type="button" class="btn btn-outline-secondary btn-sm btn-copy" id="copyResponseBody" title="Copy to Clipboard"><i class="bi bi-clipboard"></i></button>
            </div>
            <pre id="responseBody" class="border p-2 bg-light" style="max-height: 400px; overflow-y: auto;"></pre>
        </div>
    </div>
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
    console.log("DOMContentLoaded event fired.");

    // --- Get DOM Elements & Check Existence ---
    const form = document.getElementById('fhirRequestForm');
    const sendButton = document.getElementById('sendRequest');
    const fhirPathInput = document.getElementById('fhirPath');
    const requestBodyInput = document.getElementById('requestBody');
    const requestBodyGroup = document.getElementById('requestBodyGroup');
    const jsonError = document.getElementById('jsonError');
    const responseCard = document.getElementById('responseCard');
    const responseStatus = document.getElementById('responseStatus');
    const responseHeaders = document.getElementById('responseHeaders');
    const responseBody = document.getElementById('responseBody');
    const methodRadios = document.getElementsByName('method');
    const toggleServerButton = document.getElementById('toggleServer');
    const toggleLabel = document.getElementById('toggleLabel');
    const fhirServerUrlInput = document.getElementById('fhirServerUrl');
    const copyRequestBodyButton = document.getElementById('copyRequestBody');
    const copyResponseHeadersButton = document.getElementById('copyResponseHeaders');
    const copyResponseBodyButton = document.getElementById('copyResponseBody');
    const authSection = document.getElementById('authSection');
    const authTypeSelect = document.getElementById('authType');
    const authInputsGroup = document.getElementById('authInputsGroup');
    const bearerTokenInput = document.getElementById('bearerTokenInput');
    const basicAuthInputs = document.getElementById('basicAuthInputs');
    const usernameInput = document.getElementById('username');
    const passwordInput = document.getElementById('password');

    // Basic check for critical elements
    if (!form || !sendButton || !fhirPathInput || !responseCard || !toggleServerButton || !fhirServerUrlInput || !responseStatus || !responseHeaders || !responseBody || !toggleLabel) {
        console.error("One or more critical UI elements could not be found. Script execution halted.");
        alert("Error initializing UI components. Please check the console.");
        return;
    }
    console.log("All critical elements checked/found.");

    // --- State Variable ---
    let useLocalHapi = true;

    // --- Get App Mode from Flask Context ---
    const appMode = '{{ app_mode | default("standalone") | lower }}';
    console.log('App Mode Detected:', appMode);

    // --- Helper Functions ---
    function validateRequestBody(method, path) {
        if (!requestBodyInput || !jsonError) return (method === 'POST' || method === 'PUT') ? '' : undefined;
        const bodyValue = requestBodyInput.value.trim();
        requestBodyInput.classList.remove('is-invalid');
        jsonError.style.display = 'none';

        if (!bodyValue) return '';

        const isSearch = path && path.endsWith('_search');
        const isJson = bodyValue.startsWith('{') || bodyValue.startsWith('[');
        const isXml = bodyValue.startsWith('<');
        const isForm = !isJson && !isXml;

        if (method === 'POST' && isSearch && isForm) {
            return bodyValue;
        } else if (method === 'POST' || method === 'PUT') {
            if (isJson) {
                try { JSON.parse(bodyValue); return bodyValue; }
                catch (e) { jsonError.textContent = `Invalid JSON: ${e.message}`; }
            } else if (isXml) {
                return bodyValue;
            } else {
                jsonError.textContent = 'Request body must be valid JSON or XML for PUT/POST (unless using POST _search with form parameters).';
            }
            requestBodyInput.classList.add('is-invalid');
            jsonError.style.display = 'block';
            return null;
        }
        return undefined;
    }

    function cleanFhirPath(path) {
        if (!path) return '';
        return path.replace(/^(r4\/|fhir\/)*/i, '').replace(/^\/+|\/+$/g, '');
    }

    async function copyToClipboard(text, button) {
        if (text === null || text === undefined || !button || !navigator.clipboard) return;
        try {
            await navigator.clipboard.writeText(String(text));
            const originalIcon = button.innerHTML;
            button.innerHTML = '<i class="bi bi-check-lg"></i> Copied!';
            setTimeout(() => { if (button.isConnected) button.innerHTML = originalIcon; }, 1500);
        } catch (err) { console.error('Copy failed:', err); }
    }

    function updateServerToggleUI() {
        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');
            toggleServerButton.title = "Toggle between Local HAPI and Custom URL";
            toggleLabel.textContent = useLocalHapi ? 'Using Local Server' : '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(`UI Updated: useLocalHapi=${useLocalHapi}, Button Disabled=${toggleServerButton.disabled}, Input Visible=${fhirServerUrlInput.style.display !== 'none'}, Input Required=${fhirServerUrlInput.required}`);
    }

    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 toggleServer() {
        if (appMode === 'lite') {
            console.log("Toggle ignored: Lite mode active.");
            return;
        }
        useLocalHapi = !useLocalHapi;
        if (useLocalHapi && fhirServerUrlInput) {
            fhirServerUrlInput.value = '';
        }
        updateServerToggleUI();
        updateAuthInputsUI();
        console.log(`Server toggled: Now using ${useLocalHapi ? 'Local Server' : 'Custom URL'}`);
    }

    function updateRequestBodyVisibility() {
        const selectedMethod = document.querySelector('input[name="method"]:checked')?.value;
        if (!requestBodyGroup || !selectedMethod) return;
        const showBody = (selectedMethod === 'POST' || selectedMethod === 'PUT');
        requestBodyGroup.style.display = showBody ? 'block' : 'none';
        if (!showBody) {
            if (requestBodyInput) requestBodyInput.value = '';
            if (jsonError) jsonError.style.display = 'none';
            if (requestBodyInput) requestBodyInput.classList.remove('is-invalid');
        }
    }

    // --- Initial Setup ---
    updateServerToggleUI();
    updateRequestBodyVisibility();

    // --- Event Listeners ---
    toggleServerButton.addEventListener('click', toggleServer);
    if (methodRadios) { methodRadios.forEach(radio => { radio.addEventListener('change', updateRequestBodyVisibility); }); }
    if (requestBodyInput && fhirPathInput) { requestBodyInput.addEventListener('input', () => validateRequestBody(document.querySelector('input[name="method"]:checked')?.value, fhirPathInput.value)); }
    if (copyRequestBodyButton && requestBodyInput) { copyRequestBodyButton.addEventListener('click', () => copyToClipboard(requestBodyInput.value, copyRequestBodyButton)); }
    if (copyResponseHeadersButton && responseHeaders) { copyResponseHeadersButton.addEventListener('click', () => copyToClipboard(responseHeaders.textContent, copyResponseHeadersButton)); }
    if (copyResponseBodyButton && responseBody) { copyResponseBodyButton.addEventListener('click', () => copyToClipboard(responseBody.textContent, copyResponseBodyButton)); }
    if (authTypeSelect) { authTypeSelect.addEventListener('change', updateAuthInputsUI); }

    // --- Send Request Button Listener ---
    sendButton.addEventListener('click', async function() {
        console.log("Send Request button clicked.");
        sendButton.disabled = true;
        sendButton.textContent = 'Sending...';
        responseCard.style.display = 'none';
        responseStatus.textContent = '';
        responseHeaders.textContent = '';
        responseBody.textContent = '';
        responseStatus.className = 'badge';
        fhirServerUrlInput.classList.remove('is-invalid');
        if (requestBodyInput) requestBodyInput.classList.remove('is-invalid');
        if (jsonError) jsonError.style.display = 'none';
        if (bearerTokenInput) bearerTokenInput.classList.remove('is-invalid');
        if (usernameInput) usernameInput.classList.remove('is-invalid');
        if (passwordInput) passwordInput.classList.remove('is-invalid');

        // --- Get Values ---
        const path = fhirPathInput.value.trim();
        const method = document.querySelector('input[name="method"]:checked')?.value;
        const customUrl = fhirServerUrlInput.value.trim();
        let body = undefined;
        const authType = authTypeSelect ? authTypeSelect.value : 'none';
        const bearerToken = document.getElementById('bearerToken').value.trim();
        const username = usernameInput ? usernameInput.value.trim() : '';
        const password = passwordInput ? passwordInput.value : '';

        // --- Basic Input Validation ---
        if (!path) {
            alert('Please enter a FHIR Path.');
            sendButton.disabled = false;
            sendButton.textContent = 'Send Request';
            return;
        }
        if (!method) {
            alert('Please select a Request Type.');
            sendButton.disabled = false;
            sendButton.textContent = 'Send Request';
            return;
        }
        if (!useLocalHapi && !customUrl) {
            alert('Please enter a custom FHIR Server URL.');
            fhirServerUrlInput.classList.add('is-invalid');
            sendButton.disabled = false;
            sendButton.textContent = 'Send Request';
            return;
        }
        if (!useLocalHapi && customUrl) {
            try { new URL(customUrl); }
            catch (_) {
                alert('Invalid custom FHIR Server URL format.');
                fhirServerUrlInput.classList.add('is-invalid');
                sendButton.disabled = false;
                sendButton.textContent = 'Send Request';
                return;
            }
        }

        // --- Validate Authentication ---
        if (!useLocalHapi) {
            if (authType === 'bearer' && !bearerToken) {
                alert('Please enter a Bearer Token.');
                document.getElementById('bearerToken').classList.add('is-invalid');
                sendButton.disabled = false;
                sendButton.textContent = 'Send Request';
                return;
            }
            if (authType === 'basic' && (!username || !password)) {
                alert('Please enter both Username and Password for Basic Authentication.');
                if (!username) usernameInput.classList.add('is-invalid');
                if (!password) passwordInput.classList.add('is-invalid');
                sendButton.disabled = false;
                sendButton.textContent = 'Send Request';
                return;
            }
        }

        // --- Validate & Get Body ---
        if (method === 'POST' || method === 'PUT') {
            body = validateRequestBody(method, path);
            if (body === null) {
                alert('Request body contains invalid JSON/Format.');
                sendButton.disabled = false;
                sendButton.textContent = 'Send Request';
                return;
            }
            if (body === '') body = '';
        }

        // --- Determine Fetch URL and Headers ---
        const cleanedPath = cleanFhirPath(path);
        const finalFetchUrl = '/fhir/' + cleanedPath;
        const headers = { 'Accept': 'application/fhir+json, application/fhir+xml;q=0.9, */*;q=0.8' };

        if (body !== undefined) {
            if (body.trim().startsWith('{')) { headers['Content-Type'] = 'application/fhir+json'; }
            else if (body.trim().startsWith('<')) { headers['Content-Type'] = 'application/fhir+xml'; }
            else if (method === 'POST' && path.endsWith('_search') && body && !body.trim().startsWith('{') && !body.trim().startsWith('<')) { headers['Content-Type'] = 'application/x-www-form-urlencoded'; }
            else if (body) { headers['Content-Type'] = 'application/fhir+json'; }
        }

        if (!useLocalHapi && customUrl) {
            headers['X-Target-FHIR-Server'] = customUrl.replace(/\/+$/, '');
            console.log("Adding header X-Target-FHIR-Server:", headers['X-Target-FHIR-Server']);
            if (authType === 'bearer') {
                headers['Authorization'] = `Bearer ${bearerToken}`;
                console.log("Adding header Authorization: Bearer <truncated>");
            } else if (authType === 'basic') {
                const credentials = btoa(`${username}:${password}`);
                headers['Authorization'] = `Basic ${credentials}`;
                console.log("Adding header Authorization: Basic <redacted>");
            }
        }

        const csrfTokenInput = form.querySelector('input[name="csrf_token"]');
        const csrfToken = csrfTokenInput ? csrfTokenInput.value : null;
        if (useLocalHapi && ['POST', 'PUT', 'DELETE', 'PATCH'].includes(method) && csrfToken) {
            headers['X-CSRFToken'] = csrfToken;
            console.log("CSRF Token added for local request.");
        } else if (useLocalHapi && ['POST', 'PUT', 'DELETE', 'PATCH'].includes(method) && !csrfToken) {
            console.warn("CSRF token input not found for local modifying request.");
        }

        console.log(`Executing Fetch: Method=${method}, URL=${finalFetchUrl}, LocalHAPI=${useLocalHapi}`);
        console.log("Request Headers:", { ...headers, Authorization: headers.Authorization ? '<redacted>' : undefined });
        if (body !== undefined) console.log("Request Body (first 300 chars):", (body || '').substring(0, 300) + ((body?.length ?? 0) > 300 ? "..." : ""));

        // --- Make the Fetch Request ---
        try {
            const response = await fetch(finalFetchUrl, {
                method: method,
                headers: headers,
                body: body
            });

            responseCard.style.display = 'block';
            responseStatus.textContent = `${response.status} ${response.statusText}`;
            responseStatus.className = `badge ${response.ok ? 'bg-success' : 'bg-danger'}`;

            let headerText = '';
            response.headers.forEach((value, key) => { headerText += `${key}: ${value}\n`; });
            responseHeaders.textContent = headerText.trim();

            const responseContentType = response.headers.get('content-type') || '';
            let responseBodyText = await response.text();
            let displayBody = responseBodyText;

            if (responseContentType.includes('json') && responseBodyText.trim()) {
                try { displayBody = JSON.stringify(JSON.parse(responseBodyText), null, 2); }
                catch (e) { console.warn("Failed to pretty-print JSON response:", e); }
            } else if (responseContentType.includes('xml') && responseBodyText.trim()) {
                try {
                    let formattedXml = '';
                    let indent = 0;
                    const xmlLines = responseBodyText.replace(/>\s*</g, '><').split(/(<[^>]+>)/);
                    for (let i = 0; i < xmlLines.length; i++) {
                        const node = xmlLines[i];
                        if (!node || node.trim().length === 0) continue;
                        if (node.match(/^<\/\w/)) indent--;
                        formattedXml += '  '.repeat(Math.max(0, indent)) + node.trim() + '\n';
                        if (node.match(/^<\w/) && !node.match(/\/>$/) && !node.match(/^<\?/)) indent++;
                    }
                    displayBody = formattedXml.trim();
                } catch (e) { console.warn("Basic XML formatting failed:", e); }
            }

            responseBody.textContent = displayBody;

            if (typeof Prism !== 'undefined') {
                responseBody.className = 'border p-2 bg-light';
                if (responseContentType.includes('json')) {
                    responseBody.classList.add('language-json');
                } else if (responseContentType.includes('xml')) {
                    responseBody.classList.add('language-xml');
                }
                Prism.highlightElement(responseBody);
            }

        } catch (error) {
            console.error('Fetch error:', error);
            responseCard.style.display = 'block';
            responseStatus.textContent = 'Network Error';
            responseStatus.className = 'badge bg-danger';
            responseHeaders.textContent = 'N/A';
            let errorDetail = `Error: ${error.message}\n\n`;
            if (useLocalHapi) {
                errorDetail += `Could not connect to the FHIRFLARE proxy at ${finalFetchUrl}. Ensure the toolkit server and the local HAPI FHIR server (at http://localhost:8080/fhir) are running.`;
            } else {
                errorDetail += `Could not connect to the FHIRFLARE proxy at ${finalFetchUrl} or the proxy could not connect to the target server (${customUrl}). Ensure the toolkit server is running and the target server is accessible.`;
            }
            responseBody.textContent = errorDetail;
        } finally {
            sendButton.disabled = false;
            sendButton.textContent = 'Send Request';
        }
    });
});
</script>
{% endblock %}