// Credentials schema per provider name. Defines the fields to collect and how to label them.
const PROVIDER_CREDENTIAL_SCHEMAS = {
    // todo Figure out SOTA authentication
    // see e.g. https://github.com/ham2k/app-polo/blob/main/src/extensions/activities/sota/SOTAAccount.jsx
    //          https://github.com/ham2k/app-polo/blob/main/src/store/apis/apiSOTA/apiSOTA.js
    // Refresh token? Way to show user that they need to log in again because cached credentials aren't valid?
    // todo type: text/password distinction on text boxes so API keys can be obscured
    "SOTA": [
        {key: "access_token", label: "SOTA Access Token", help: ""},
        {key: "id_token", label: "SOTA ID Token", help: "TODO SOTA authentication to provide this..."}
    ],
    "ParksNPeaks": [
        {key: "user_id", label: "Parks N Peaks User ID", help: ""},
        {key: "api_key", label: "Parks N Peaks API Key", help: "Get your API key from your Parks N Peaks account."}
    ],
    "ZLOTA": [
        {key: "user_id", label: "ZLOTA User ID", help: ""},
        {key: "api_key", label: "ZLOTA User PIN", help: "Get your PIN from your ZLOTA account."}
    ],
    "Tiles": [
        {
            key: "offline_spot_gateway_pin",
            label: "Offline Spot Gateway PIN",
            help: "Get your PIN from your Tiles on the Air account profile."
        }
    ]
};

// Load server options. Once a successful callback is made from this, we can populate the choice boxes in the form and load
// any saved values from local storage.
function loadOptions() {
    $.getJSON('/api/v2/options', function (jsonData) {
        // Store options
        options = jsonData;

        // Populate modes drop-down
        $.each(options["modes"], function (i, m) {
            $('#mode').append($('<option>', {
                value: m,
                text: m
            }));
        });

        // Populate SIG drop-down
        $.each(options["sigs"], function (i, sig) {
            $('#sig').append($('<option>', {
                value: sig.name,
                text: sig.name
            }));
        });

        // Load reCAPTCHA if a site key is configured (key is inlined into page by server)
        if (window._recaptchaSiteKey) {
            loadRecaptcha(window._recaptchaSiteKey);
        }

        // Load settings from settings storage now all the controls are available
        loadSettings();

        // Update the upstream area for any pre-selected SIG
        updateUpstreamArea();
    });
}

// Load and inject the reCAPTCHA script
function loadRecaptcha(siteKey) {
    window._recaptchaSiteKey = siteKey;
    if (!document.getElementById('recaptcha-script')) {
        const script = document.createElement('script');
        script.id = 'recaptcha-script';
        script.src = 'https://www.google.com/recaptcha/api.js?render=explicit&onload=renderRecaptcha';
        script.async = true;
        script.defer = true;
        document.head.appendChild(script);
    }
    $("#recaptcha-area").show();
}

// Called by reCAPTCHA after its script loads
function renderRecaptcha() {
    window._recaptchaWidgetId = grecaptcha.render('recaptcha-widget', {
        sitekey: window._recaptchaSiteKey,
        size: 'normal'
    });
}

// Update the "Send spot to..." area based on the currently selected SIG
function updateUpstreamArea() {
    if (!window._allowUpstreamSpotting || !options || !options["spot_submit_providers"]) {
        $("#upstream-area").hide();
        return;
    }

    const sig = $("#sig").val();
    const providers = (sig && options["spot_submit_providers"][sig]) ? options["spot_submit_providers"][sig] : [];

    if (providers.length === 0) {
        $("#upstream-area").hide();
        return;
    }

    $("#upstream-area").show();

    // Update the provider selector
    $("#upstream-provider-select").empty();
    $.each(providers, function (i, name) {
        $("#upstream-provider-select").append($('<option>', {value: name, text: name}));
    });

    if (providers.length > 1) {
        $("#upstream-provider-label").text("upstream spot sources:");
        $("#upstream-provider-select-col").show();
    } else {
        $("#upstream-provider-label").text(providers[0]);
        $("#upstream-provider-select-col").hide();
    }

    // Show the credentials button if this provider has an authentication mechanism and we need input from the user
    updateCredentialsButton();
}

// Update the credentials button visibility based on selected provider
function updateCredentialsButton() {
    const providerName = getSelectedUpstreamProvider();
    if (providerName && PROVIDER_CREDENTIAL_SCHEMAS[providerName]) {
        $("#upstream-credentials-btn").show();
    } else {
        $("#upstream-credentials-btn").hide();
    }
}

// Get the currently selected upstream provider name
function getSelectedUpstreamProvider() {
    const providers = (options && options["spot_submit_providers"] && $("#sig").val())
        ? (options["spot_submit_providers"][$("#sig").val()] || [])
        : [];
    if (providers.length === 0) return null;
    if (providers.length === 1) return providers[0];
    return $("#upstream-provider-select").val();
}

// Show the credentials modal for the currently selected upstream provider
function showCredentialsModal() {
    const providerName = getSelectedUpstreamProvider();
    if (!providerName || !PROVIDER_CREDENTIAL_SCHEMAS[providerName]) return;

    const schema = PROVIDER_CREDENTIAL_SCHEMAS[providerName];
    const stored = loadCredentials(providerName);

    $("#credentials-provider-name").text(providerName);
    $("#credentials-fields").empty();

    $.each(schema, function (i, field) {
        const val = stored[field.key] || "";
        let html = '<div class="mb-3">';
        html += '<label for="cred-' + field.key + '" class="form-label">' + field.label + '</label>';
        html += '<input type="text" class="form-control" id="cred-' + field.key + '" value="' + $('<div>').text(val).html() + '">';
        if (field.help) {
            html += '<div class="form-text">' + field.help + '</div>';
        }
        html += '</div>';
        $("#credentials-fields").append(html);
    });

    // Store provider name for saveCredentials()
    $("#credentials-modal").data("provider", providerName);
    new bootstrap.Modal(document.getElementById('credentials-modal')).show();
}

// Save credentials from the modal to local storage
function saveCredentials() {
    const providerName = $("#credentials-modal").data("provider");
    if (!providerName || !PROVIDER_CREDENTIAL_SCHEMAS[providerName]) return;

    const schema = PROVIDER_CREDENTIAL_SCHEMAS[providerName];
    const creds = {};
    $.each(schema, function (i, field) {
        creds[field.key] = $("#cred-" + field.key).val();
    });
    localStorage.setItem("upstream-credentials-" + providerName, JSON.stringify(creds));
    bootstrap.Modal.getInstance(document.getElementById('credentials-modal')).hide();
}

// Load credentials for a provider from local storage
function loadCredentials(providerName) {
    const stored = localStorage.getItem("upstream-credentials-" + providerName);
    return stored ? JSON.parse(stored) : {};
}

// Method called to add a spot to the server
function addSpot() {
    try {
        // Save settings (this will save "your call" for future use)
        saveSettings();

        // Unpack the user's entered values
        const dx = $("#dx-call").val().toUpperCase();
        const freqStr = $("#freq").val();
        const mode = $("#mode")[0].value;
        const sig = $("#sig")[0].value;
        const sigRef = $("#sig-ref").val();
        const dxGrid = $("#dx-grid").val();
        const comment = $("#comment").val();
        const de = $("#de-call").val().toUpperCase();

        // Prepare the spot object for the server
        const spot = {};
        spot["dx_call"] = dx;
        spot["freq"] = parseFloat(freqStr) * 1000;
        if (mode !== "") spot["mode"] = mode;
        if (sig !== "") spot["sig"] = sig;
        if (sigRef !== "") spot["sig_refs"] = [{sig: sig, id: sigRef}];
        if (dxGrid !== "") spot["dx_grid"] = dxGrid;
        if (comment !== "") spot["comment"] = comment;
        spot["de_call"] = de;
        spot["time"] = moment.utc().valueOf() / 1000.0;

        // Prepare "handling" structure to tell the server what to do with this spot
        const handling = {};

        // Add CAPTCHA token if reCAPTCHA is loaded
        if (window._recaptchaWidgetId !== undefined) {
            handling["captcha_token"] = grecaptcha.getResponse(window._recaptchaWidgetId);
        }

        // Upstream submission
        const submitUpstream = $("#submit-upstream").is(":checked");
        const upstreamProviderName = getSelectedUpstreamProvider();
        if (submitUpstream && upstreamProviderName) {
            handling["submit_upstream"] = true;
            handling["upstream_provider"] = upstreamProviderName;
            handling["upstream_credentials"] = loadCredentials(upstreamProviderName);
        }

        $.ajax("/api/v2/spot", {
            data: JSON.stringify({spot, handling}),
            contentType: 'application/json',
            type: 'POST',
            timeout: 10000,
            success: async function (result) {
                // Reset CAPTCHA for next use
                if (window._recaptchaWidgetId !== undefined) {
                    grecaptcha.reset(window._recaptchaWidgetId);
                }
                if (result && result.startsWith && result.startsWith("Warning")) {
                    $("#result-good").html("<div class='alert alert-warning fade show mb-0 mt-4' role='alert'><i class='fa-solid fa-triangle-exclamation'></i> " + result + " Returning you to the spots list...</div>");
                } else {
                    $("#result-good").html("<div class='alert alert-success fade show mb-0 mt-4' role='alert'><i class='fa-solid fa-check'></i> Spot submitted. Returning you to the spots list...</div>");
                }
                $("#result-bad").html("");
                setTimeout(() => {
                    $("#result-good").hide();
                    window.location.replace("/");
                }, 2000);
            },
            error: function (result) {
                if (window._recaptchaWidgetId !== undefined) {
                    grecaptcha.reset(window._recaptchaWidgetId);
                }
                if (result.responseText) {
                    showAddSpotError(result.responseText.slice(1, -1));
                } else {
                    showAddSpotError("The server did not return a response.");
                }
            }
        });
    } catch (error) {
        showAddSpotError(error);
    }
    return false;
}

// Show an "add spot" error.
function showAddSpotError(text) {
    const div = $("<div class='alert alert-danger alert-dismissible fade show mb-0 mt-4' role='alert'></div>");
    div.append("<i class='fa-solid fa-triangle-exclamation'></i> ");
    div.append(document.createTextNode(text));
    div.append("<button type='button' class='btn-close' data-bs-dismiss='alert' aria-label='Close'></button>");
    $("#result-bad").empty().append(div);
}

// Force callsign and mode capitalisation
$("#dx-call").change(function () {
    $(this).val($(this).val().trim().toUpperCase());
});
$("#de-call").change(function () {
    $(this).val($(this).val().trim().toUpperCase());
});
$("#mode").change(function () {
    $(this).val($(this).val().trim().toUpperCase());
});

// Update upstream area and credentials button when SIG changes
$("#sig").change(function () {
    updateUpstreamArea();
});

// Update credentials button when provider selector changes
$("#upstream-provider-select").change(function () {
    updateCredentialsButton();
});

// Startup
$(document).ready(function () {
    // Load options
    loadOptions();
});
