import {
    main_api,
    saveSettingsDebounced,
    callPopup,
} from '../script.js';
import { power_user } from './power-user.js';
//import { BIAS_CACHE, displayLogitBias, getLogitBiasListResult } from './logit-bias.js';
//import { getEventSourceStream } from './sse-stream.js';
//import { getSortableDelay, onlyUnique } from './utils.js';
//import { getCfgPrompt } from './cfg-scale.js';
import { setting_names } from './textgen-settings.js';


const TGsamplerNames = setting_names;

const forcedOnColoring = 'color: #89db35;';
const forcedOffColoring = 'color: #e84f62;';

let userDisabledSamplers, userShownSamplers;

// Goal 1: show popup with all samplers for active API
async function showSamplerSelectPopup() {
    const popup = $('#dialogue_popup');
    popup.addClass('large_dialogue_popup');
    const html = $(document.createElement('div'));
    html.attr('id', 'sampler_view_list')
        .addClass('flex-container flexFlowColumn');
    html.append(`
    <div class="title_restorable flexFlowColumn alignItemsBaseline">
        <div class="flex-container justifyCenter">
            <h3>Sampler Select</h3>
            <div class="flex-container alignItemsBaseline">
            <div id="resetSelectedSamplers" class="menu_button menu_button_icon" title="Reset custom sampler selection">
                <i class="fa-solid fa-recycle"></i>
            </div>
        </div>
            <!--<div class="flex-container alignItemsBaseline">
                <div class="menu_button menu_button_icon" title="Create a new sampler">
                    <i class="fa-solid fa-plus"></i>
                    <span data-i18n="Create">Create</span>
                </div>
            </div>-->
        </div>
        <small>Here you can toggle the display of individual samplers. (WIP)</small>
    </div>
    <hr>`);

    const listContainer = $('<div id="apiSamplersList" class="flex-container flexNoGap"></div>');
    const APISamplers = await listSamplers(main_api);
    listContainer.append(APISamplers);
    html.append(listContainer);

    callPopup(html, 'text', null, { allowVerticalScrolling: true });

    setSamplerListListeners();

    $('#resetSelectedSamplers').off('click').on('click', async function () {
        console.log('saw sampler select reset click');
        userDisabledSamplers = [];
        userShownSamplers = [];
        power_user.selectSamplers.forceShown = [];
        power_user.selectSamplers.forceHidden = [];
        await validateDisabledSamplers(true);
    });

    $('#textgen_type').on('change', async function () {
        console.log('changed TG Type, resetting custom samplers'); //unfortunate, but necessary unless we save custom samplers for each TGTytpe
        userDisabledSamplers = [];
        userShownSamplers = [];
        power_user.selectSamplers.forceShown = [];
        power_user.selectSamplers.forceHidden = [];
        await validateDisabledSamplers();
    });
}

function setSamplerListListeners() {
    // Goal 2: hide unchecked samplers from DOM
    let listContainer = $('#apiSamplersList');
    listContainer.find('input').off('change').on('change', async function () {

        const samplerName = this.name.replace('_checkbox', '');
        let relatedDOMElement = $(`#${samplerName}_${main_api}`).parent();
        let targetDisplayType = 'flex';

        if (samplerName === 'json_schema') {
            relatedDOMElement = $('#json_schema_block');
            targetDisplayType = 'block';
        }

        if (samplerName === 'grammar_string') {
            relatedDOMElement = $('#grammar_block_ooba');
            targetDisplayType = 'block';
        }

        if (samplerName === 'guidance_scale') {
            relatedDOMElement = $('#cfg_block_ooba');
            targetDisplayType = 'block';
        }

        if (samplerName === 'mirostat_mode') {
            relatedDOMElement = $('#mirostat_block_ooba');
            targetDisplayType = 'block';
        }

        if (samplerName === 'dry_multiplier') {
            relatedDOMElement = $('#dryBlock');
            targetDisplayType = 'block';
        }

        if (samplerName === 'dynatemp') {
            relatedDOMElement = $('#dynatemp_block_ooba');
            targetDisplayType = 'block';
        }

        if (samplerName === 'banned_tokens') {
            relatedDOMElement = $('#banned_tokens_block_ooba');
            targetDisplayType = 'block';
        }

        if (samplerName === 'sampler_order') { //this is for kcpp sampler order
            relatedDOMElement = $('#sampler_order_block_kcpp');
        }

        if (samplerName === 'samplers') { //this is for lcpp sampler order
            relatedDOMElement = $('#sampler_order_block_lcpp');
        }

        if (samplerName === 'sampler_priority') { //this is for ooba's sampler priority
            relatedDOMElement = $('#sampler_priority_block_ooba');
        }

        if (samplerName === 'penalty_alpha') { //contrastive search only has one sampler, does it need its own block?
            relatedDOMElement = $('#contrastiveSearchBlock');
        }

        if (samplerName === 'num_beams') { // num_beams is the killswitch for Beam Search
            relatedDOMElement = $('#beamSearchBlock');
            targetDisplayType = 'block';
        }

        if (samplerName === 'smoothing_factor') { // num_beams is the killswitch for Beam Search
            relatedDOMElement = $('#smoothingBlock');
            targetDisplayType = 'block';
        }

        // Get the current state of the custom data attribute
        const previousState = relatedDOMElement.data('selectsampler');

        if ($(this).prop('checked') === false) {
            //console.log('saw clicking checkbox from on to off...');
            if (previousState === 'shown') {
                console.log('saw previously custom shown sampler');
                //console.log('removing from custom force show list');
                relatedDOMElement.removeData('selectsampler');
                $(this).parent().find('.sampler_name').removeAttr('style');
                power_user?.selectSamplers?.forceShown.splice(power_user?.selectSamplers?.forceShown.indexOf(samplerName), 1);
                console.log(power_user?.selectSamplers?.forceShown);
            } else {
                console.log('saw previous untouched sampler');
                //console.log(`adding ${samplerName} to force hide list`);
                relatedDOMElement.data('selectsampler', 'hidden');
                console.log(relatedDOMElement.data('selectsampler'));
                power_user.selectSamplers.forceHidden.push(samplerName);
                $(this).parent().find('.sampler_name').attr('style', forcedOffColoring);
                console.log(power_user.selectSamplers.forceHidden);
            }
        } else { // going from unchecked to checked
            //console.log('saw clicking checkbox from off to on...');
            if (previousState === 'hidden') {
                console.log('saw previously custom hidden sampler');
                //console.log('removing from custom force hide list');
                relatedDOMElement.removeData('selectsampler');
                $(this).parent().find('.sampler_name').removeAttr('style');
                power_user?.selectSamplers?.forceHidden.splice(power_user?.selectSamplers?.forceHidden.indexOf(samplerName), 1);
                console.log(power_user?.selectSamplers?.forceHidden);
            } else {
                console.log('saw previous untouched sampler');
                //console.log(`adding ${samplerName} to force shown list`);
                relatedDOMElement.data('selectsampler', 'shown');
                console.log(relatedDOMElement.data('selectsampler'));
                power_user.selectSamplers.forceShown.push(samplerName);
                $(this).parent().find('.sampler_name').attr('style', forcedOnColoring);
                console.log(power_user.selectSamplers.forceShown);
            }
        }
        await saveSettingsDebounced();

        const shouldDisplay = $(this).prop('checked') ? targetDisplayType : 'none';
        relatedDOMElement.css('display', shouldDisplay);

        console.log(samplerName, relatedDOMElement.data('selectsampler'), shouldDisplay);
    });

}

function isElementVisibleInDOM(element) {
    while (element && element !== document.body) {
        if (window.getComputedStyle(element).display === 'none') {
            return false;
        }
        element = element.parentElement;
    }
    return true;
}


async function listSamplers(main_api, arrayOnly = false) {
    let availableSamplers;
    if (main_api === 'textgenerationwebui') {
        availableSamplers = TGsamplerNames;
        const valuesToRemove = new Set(['streaming', 'bypass_status_check', 'custom_model', 'legacy_api']);
        availableSamplers = availableSamplers.filter(sampler => !valuesToRemove.has(sampler));
        availableSamplers.sort();
    }

    if (arrayOnly) {
        console.debug('returning full samplers array');
        return availableSamplers;
    }

    const samplersListHTML = availableSamplers.reduce((html, sampler) => {
        let customColor, displayname;
        let targetDOMelement = $(`#${sampler}_${main_api}`);

        if (sampler === 'sampler_order') { //this is for kcpp sampler order
            targetDOMelement = $('#sampler_order_block_kcpp');
            displayname = 'KCPP Sampler Order Block';
        }

        if (sampler === 'samplers') { //this is for lcpp sampler order
            targetDOMelement = $('#sampler_order_block_lcpp');
            displayname = 'LCPP Sampler Order Block';
        }

        if (sampler === 'sampler_priority') { //this is for ooba's sampler priority
            targetDOMelement = $('#sampler_priority_block_ooba');
            displayname = 'Ooba Sampler Priority Block';
        }

        if (sampler === 'penalty_alpha') { //contrastive search only has one sampler, does it need its own block?
            targetDOMelement = $('#contrastiveSearchBlock');
            displayname = 'Contrast Search Block';
        }

        if (sampler === 'num_beams') { // num_beams is the killswitch for Beam Search
            targetDOMelement = $('#beamSearchBlock');
            displayname = 'Beam Search Block';
        }

        if (sampler === 'smoothing_factor') { // num_beams is the killswitch for Beam Search
            targetDOMelement = $('#smoothingBlock');
            displayname = 'Smoothing Block';
        }

        if (sampler === 'dry_multiplier') {
            targetDOMelement = $('#dryBlock');
            displayname = 'DRY Rep Pen Block';
        }

        if (sampler === 'dynatemp') {
            targetDOMelement = $('#dynatemp_block_ooba');
            displayname = 'DynaTemp Block';
        }

        if (sampler === 'json_schema') {
            targetDOMelement = $('#json_schema_block');
            displayname = 'JSON Schema Block';
        }

        if (sampler === 'grammar_string') {
            targetDOMelement = $('#grammar_block_ooba');
            displayname = 'Grammar Block';
        }

        if (sampler === 'guidance_scale') {
            targetDOMelement = $('#cfg_block_ooba');
            displayname = 'CFG Block';
        }

        if (sampler === 'mirostat_mode') {
            targetDOMelement = $('#mirostat_block_ooba');
            displayname = 'Mirostat Block';
        }



        const isInForceHiddenArray = userDisabledSamplers.includes(sampler);
        const isInForceShownArray = userShownSamplers.includes(sampler);
        let isVisibleInDOM = isElementVisibleInDOM(targetDOMelement[0]);
        const isInDefaultState = () => {
            if (isVisibleInDOM && isInForceShownArray) { return false; }
            else if (!isVisibleInDOM && isInForceHiddenArray) { return false; }
            else { return true; }
        };

        const shouldBeChecked = () => {
            if (isInForceHiddenArray) {
                customColor = forcedOffColoring;
                return false;
            }
            else if (isInForceShownArray) {
                customColor = forcedOnColoring;
                return true;
            }
            else { return isVisibleInDOM; }
        };
        console.log(sampler, targetDOMelement.prop('id'), isInDefaultState(), isInForceShownArray, isInForceHiddenArray, shouldBeChecked());
        if (displayname === undefined) { displayname = sampler; }
        return html + `
        <div class="sampler_view_list_item wide50p flex-container">
            <input type="checkbox" name="${sampler}_checkbox" ${shouldBeChecked() ? 'checked' : ''}>
            <small class="sampler_name" style="${customColor}">${displayname}</small>
        </div>
        `;
    }, '');

    return samplersListHTML;
}

// Goal 3: make "sampler is hidden/disabled" status persistent (save settings)
// this runs on initial getSettings as well as after API changes

export async function validateDisabledSamplers(redraw = false) {
    const APISamplers = await listSamplers(main_api, true);

    if (!Array.isArray(APISamplers)) {
        return;
    }

    for (const sampler of APISamplers) {
        let relatedDOMElement = $(`#${sampler}_${main_api}`).parent();
        let targetDisplayType = 'flex';

        if (sampler === 'json_schema') {
            relatedDOMElement = $('#json_schema_block');
            targetDisplayType = 'block';
        }

        if (sampler === 'grammar_string') {
            relatedDOMElement = $('#grammar_block_ooba');
            targetDisplayType = 'block';
        }

        if (sampler === 'guidance_scale') {
            relatedDOMElement = $('#cfg_block_ooba');
            targetDisplayType = 'block';
        }

        if (sampler === 'mirostat_mode') {
            relatedDOMElement = $('#mirostat_block_ooba');
            targetDisplayType = 'block';
        }

        if (sampler === 'dynatemp') {
            relatedDOMElement = $('#dynatemp_block_ooba');
            targetDisplayType = 'block';
        }

        if (sampler === 'banned_tokens') {
            relatedDOMElement = $('#banned_tokens_block_ooba');
            targetDisplayType = 'block';
        }

        if (sampler === 'sampler_order') { //this is for kcpp sampler order
            relatedDOMElement = $('#sampler_order_block_kcpp');
        }

        if (sampler === 'samplers') { //this is for lcpp sampler order
            relatedDOMElement = $('#sampler_order_block_lcpp');
        }

        if (sampler === 'sampler_priority') { //this is for ooba's sampler priority
            relatedDOMElement = $('#sampler_priority_block_ooba');
        }

        if (sampler === 'dry_multiplier') {
            relatedDOMElement = $('#dryBlock');
            targetDisplayType = 'block';
        }

        if (sampler === 'penalty_alpha') { //contrastive search only has one sampler, does it need its own block?
            relatedDOMElement = $('#contrastiveSearchBlock');
        }

        if (sampler === 'num_beams') { // num_beams is the killswitch for Beam Search
            relatedDOMElement = $('#beamSearchBlock');
        }

        if (sampler === 'smoothing_factor') { // num_beams is the killswitch for Beam Search
            relatedDOMElement = $('#smoothingBlock');
        }

        if (power_user?.selectSamplers?.forceHidden.includes(sampler)) {
            //default handling for standard sliders
            relatedDOMElement.data('selectsampler', 'hidden');
            relatedDOMElement.css('display', 'none');
        } else if (power_user?.selectSamplers?.forceShown.includes(sampler)) {
            relatedDOMElement.data('selectsampler', 'shown');
            relatedDOMElement.css('display', targetDisplayType);
        } else {
            if (relatedDOMElement.data('selectsampler') === 'hidden') {
                relatedDOMElement.removeAttr('selectsampler');
                relatedDOMElement.css('display', targetDisplayType);
            }
            if (relatedDOMElement.data('selectsampler') === 'shown') {
                relatedDOMElement.removeAttr('selectsampler');
                relatedDOMElement.css('display', 'none');
            }
        }
        if (redraw) {
            let samplersHTML = await listSamplers(main_api);
            $('#apiSamplersList').empty().append(samplersHTML);
            setSamplerListListeners();
        }

        await saveSettingsDebounced();

    }
}


export async function initCustomSelectedSamplers() {

    userDisabledSamplers = power_user?.selectSamplers?.forceHidden || [];
    userShownSamplers = power_user?.selectSamplers?.forceShown || [];
    power_user.selectSamplers = {};
    power_user.selectSamplers.forceHidden = userDisabledSamplers;
    power_user.selectSamplers.forceShown = userShownSamplers;
    await saveSettingsDebounced();
    $('#samplerSelectButton').off('click').on('click', showSamplerSelectPopup);

}

// Goal 4: filter hidden samplers from API output

// Goal 5: allow addition of custom samplers to be displayed
// Goal 6: send custom sampler values into prompt