const athleteChangeActions = [];

// By this stage, we assume the barcode is valid
async function athleteLookup(barcode_str)
{
    return new Promise(async function(resolve, reject) {
        // Update the UI to say we're contacting the server for this athlete
        document.getElementById("welcome-message").innerHTML = `Looking up results for athlete ${barcode_str}...`;
        startToaster();

        let response = await fetch(urlRoot + `/A${barcode_str}.ath`);
        if(response.status == 206) {
            showRichMessage("<span class='material-icons'>warning</span>&nbsp;&nbsp;Athlete data might not include the most recent activities.");
        }
    
        response.json().then((myAthlete) => {
            stopToaster();
            if(myAthlete.error)
            {
                const err = myAthlete.error;
                if((err.statusCode == 405) && err.body.match(/captcha/i))
                {
                    // We're being prompted for a captcha
                    doCaptcha(err.body);
                }
                else
                {
                    alert("Sorry, athlete data is unavailable right now.\nYou can continue, but touring recommendations will not be personalised for this athlete.");
                    athLogout();
                    reject("Failed to log in");
                }
            }
            else
            {
                var name = "Stranger";  // default, when the barcode has no name
                if(String(myAthlete.name).length > 0)
                    name = myAthlete.name;

                document.getElementById("welcome-message").innerHTML = `<span class="material-icons">perm_identity</span>&nbsp;${name} (${barcode_str})`;
                resolve( myAthlete );
            }
        });
    });
}

// A quick lookup for last known data for an athlete.
// Might not be up-to date, but it's fast.
// This is used to bridge the gap while we wait a few seconds for the latest data to arrive.
async function athletePreviewLookup(barcode_str)
{
    const response = await fetch(urlRoot + `/cached/A${barcode_str}.ath`);
    const athlete_preview = {
        status: response.status,
        data: undefined
    };

    switch (response.status) {
        case 200:
        case 201:
        case 206:
            let myAthlete = await response.json(); //.then((myAthlete) => {
            var name = "Stranger";  // default, when the barcode has no name
            if(String(myAthlete.name).length > 0)
                name = myAthlete.name;

            document.getElementById("welcome-message").innerHTML = `<span class="material-icons">perm_identity</span>&nbsp;${name} (${barcode_str})`;
            athlete_preview.data = myAthlete;
            break;
        case 204:  // No data available
            break;
        case 405:  // Captcha -- shouldn't see this on athlete preview
            break;
        default:
            break;
    }
    return athlete_preview;
}

async function athLogin(barcode_str)
{
    const now = Date.now();
    // If there have been 2 login requests within half a second, reject the latter
    if(appData.loginTimestamp && ((now - appData.loginTimestamp) < 500))
        return;  // Spurious login attempt
    appData.loginTimestamp = now;

    // 1 - get id value from widget
    var barcode = parseBarcode(barcode_str);
    if (isValidBarcode(barcode))
    {
        // Show icon indicating we're waiting
        document.getElementById("loginIcon").innerHTML = "pending";
        try {
            const myAth = await athleteLookup(barcode);  // This might take a few seconds
            appData.currentAthlete = myAth;
            var athProgress = myAth.progress;

            // Detect challenges that we defined in the last week, after the cached athlete data was generated.
            const all_possible_keys = Array.from((await getAllChallenges()).keys()).sort();
            // Get the challenge keys defined in the athlete's cached data
            const ath_cached_keys = appData.currentAthlete.progress.map((x)=>{return x[0];}).sort();
            const missing_keys = all_possible_keys.filter((x)=>{return !ath_cached_keys.includes(x)});
            
            // Update the challenge states (completed/incomplete)
            updateDocumentProgress( athProgress );

            if (missing_keys.length > 0)
            {
                await refreshEventRecommendations();
                for (let ix in missing_keys) {
                    const missing_key = missing_keys[ix];
                    updateDocumentProgress( appData.currentAthlete.progress, missing_key );
                }
            }

            // Update the event recommendations
            updateEventRecommendations( myAth );

            writeCookie("barcode", barcode_str);

            var athEntry = document.getElementById("athlete-section");
            var athDisplay = document.getElementById("athlete-display");
            // On successful login, the login UI is replaced by a "Welcome" message
            athEntry.style.display = "none";
            athDisplay.style.display = "flex";

            // Athlete logged in, call all callbacks with param (myAth)
            athleteChangeActions.forEach((fn)=>{fn(myAth)});
        
            // If the athlete logs out, or logs in when the map is not on-screen,
            // schedule a refocus next time we switch to the map
            if( ! mapIsVisible() )
                appData.mapNeedsRefocus = true;
	    } catch(err) {
            console.log("Error when looking up barcode: ", err);
        }
    } else {
        alert ("Please enter a valid barcode");
    }
}

async function athLoginPreview(barcode_str)
{
    /*const now = Date.now();
    // If there have been 2 login requests within half a second, reject the latter
    if(appData.loginTimestamp && ((now - appData.loginTimestamp) < 500))
        return 0;  // Spurious login attempt

    appData.loginTimestamp = now;*/

    // 1 - get id value from widget
    const barcode = parseBarcode(barcode_str);
    if (isValidBarcode(barcode))
    {
        try {
            const ath_preview = await athletePreviewLookup(barcode);  // This should be VERY quick
            if(ath_preview.data) {

                const myAth = ath_preview.data;
                appData.currentAthlete = myAth;
                const athProgress = myAth.progress;
                
                // Detect challenges that we defined in the last week, after the cached athlete data was generated.
                const all_possible_keys = Array.from((await getAllChallenges()).keys()).sort();
                // Get the challenge keys defined in the athlete's cached data
                const ath_cached_keys = athProgress.map((x)=>{return x[0];}).sort();
                const missing_keys = all_possible_keys.filter((x)=>{return !ath_cached_keys.includes(x)});
                
                // Update the challenge states (completed/incomplete)
                updateDocumentProgress( athProgress );
                
                if (missing_keys.length > 0)
                {
                    await refreshEventRecommendations();
                    for (let ix in missing_keys) {
                        const missing_key = missing_keys[ix];
                        updateDocumentProgress( appData.currentAthlete.progress, missing_key );
                    }
                }
                
                // Update the event recommendations
                updateEventRecommendations( myAth );
                
                var athEntry = document.getElementById("athlete-section");
                var athDisplay = document.getElementById("athlete-display");
                // On successful login, the login UI is replaced by a "Welcome" message
                athEntry.style.display = "none";
                athDisplay.style.display = "flex";
                
                // Athlete found, notify affected callbacks
                athleteChangeActions.forEach((fn)=>{fn(myAth)});
                
                // If the athlete logs out, or logs in when the map is not on-screen,
                // schedule a refocus next time we switch to the map
                if( ! mapIsVisible() ) {
                    appData.mapNeedsRefocus = true;
                }
            }
            return ath_preview.status;  // if status is 206, the caller should follow up with a request for fresh athData
	    } catch(err) {
            console.log("Error when previewing barcode: ", err);
            return 0;
        }
    }
}

function athLogout()
{
    var athEntry = document.getElementById("athlete-section");
    var athDisplay = document.getElementById("athlete-display");
    stopToaster();
    
    // Operation completed, change "waiting" icon back to original search
    document.getElementById("loginIcon").innerHTML = "search";

    // On logout - the login UI becomes visible again
    athEntry.style.display = "flex";
    athDisplay.style.display = "none";
    appData.currentAthlete = null;

    // clear progress (consider each element may has been disabled individually)
    const nameley_progress = document.getElementById("max-progress-namely");
    if(nameley_progress) {
        nameley_progress.innerHTML = 0;
    }

    const vol_pct = document.getElementById("vol-pct");
    if(vol_pct) {
        vol_pct.innerHTML = "0.0%";
    }

    const w_index = document.getElementById("w-index");
    if(w_index) {
        w_index.innerHTML = "0 <i>(0)</i>";
    }

    var challenges = document.getElementsByClassName("challenge");
    for (var i = 0; i < challenges.length; i++) {
        var challengeWidget = challenges[i];
        challengeWidget.classList.remove("complete");

        // TODO - this "if" is because of the add/remove auxiliary button
        if(challengeWidget.value) {
            // Set progress back to zero
            const challengeKey = challengeWidget.value.key;
            var progress_stat = document.getElementById(`progress-${challengeKey}`);
            if(progress_stat)
            {
                progress_stat.innerHTML = 0;
            }
            var progress_bar = document.getElementById(`progress-bar-${challengeKey}`);
            if( progress_bar )
            {
                progress_bar.style.width = 0;
                progress_bar.style.backgroundColor = "red";
            }
        }
    }

    // Remove the complete status from any challenge importers (Most Wanted Numbers)
    const challenge_importers = document.getElementsByClassName("challenge-import");
    Array.from(challenge_importers).forEach((x)=>{x.classList.remove("complete")});

    // Update event list based on no athlete
    updateGenericEventRecommendations();

    // Athlete logged out, call all callbacks with param (undefined)
    athleteChangeActions.forEach((fn)=>{fn()});

    // If any bingo highlighting was active, disable it now
    toggleBingoHighlighting(false);

    // If the athlete logs out, or logs in when the map is not on-screen,
    // schedule a refocus next time we switch to the map
    if( ! mapIsVisible() )
        appData.mapNeedsRefocus = true;
}


// is an athlete logged in?
function athleteLoggedIn()
{
    return (appData.currentAthlete != null);
}

function athleteShortName()
{
    if(athleteLoggedIn())
    {
        // return the first word in the Athlete's name
        return appData.currentAthlete.name.split(" ")[0];
    }
}

// Other modules can add a callback to be called when the current athlete changes (either successful login, or logout).
function addAthleteChangeAction(fn)
{
    athleteChangeActions.push(fn);
}