import { i18n } from "../localization";
import djv from "djv";
import { generateFilename } from "../utils/generate_filename";
import Clipboard from "../Clipboard";
import GUI, { TABS } from "../gui";
import { tracking } from "../Analytics";
import { mspHelper } from "../msp/MSPHelper";
import FC from "../fc";
import { VtxDeviceTypes } from "../utils/VtxDeviceStatus/VtxDeviceStatus";
import MSP from "../msp";
import MSPCodes from "../msp/MSPCodes";
import { gui_log } from "../gui_log";
import $ from "jquery";
import FileSystem from "../FileSystem";

const vtx = {
    vtxTableSavePending: false,
    vtxTableFactoryBandsSupported: false,
    MAX_POWERLEVEL_VALUES: 8,
    MAX_BAND_VALUES: 8,
    MAX_BAND_CHANNELS_VALUES: 8,
    VTXTABLE_BAND_LIST: [],
    VTXTABLE_POWERLEVEL_LIST: [],
    analyticsChanges: {},
    updating: true,
    env: new djv(),
};

vtx.isVtxDeviceStatusReady = function () {
    const isReady = null !== FC.VTX_DEVICE_STATUS && FC.VTX_DEVICE_STATUS.deviceIsReady;

    return !!isReady;
};

vtx.updateVtxDeviceStatus = function () {
    function vtxDeviceStatusReceived() {
        $("#vtx_type_description").text(TABS.vtx.getVtxTypeString());

        const vtxReady_e = $(".VTX_info span.colorToggle");
        const isReady = vtx.isVtxDeviceStatusReady();

        // update device ready state
        vtxReady_e.text(isReady ? i18n.getMessage("vtxReadyTrue") : i18n.getMessage("vtxReadyFalse"));
        vtxReady_e.toggleClass("ready", isReady);
    }

    MSP.send_message(MSPCodes.MSP2_GET_VTX_DEVICE_STATUS, false, false, vtxDeviceStatusReceived);
};

vtx.getVtxTypeString = function () {
    let result = i18n.getMessage(`vtxType_${FC.VTX_CONFIG.vtx_type}`);

    const isSmartAudio = VtxDeviceTypes.VTXDEV_SMARTAUDIO === FC.VTX_CONFIG.vtx_type;
    const isVtxDeviceStatusReceived = null !== FC.VTX_DEVICE_STATUS;

    if (isSmartAudio && isVtxDeviceStatusReceived) {
        result += ` ${FC.VTX_DEVICE_STATUS.smartAudioVersion}`;
    }

    return result;
};

vtx.initialize = function (callback) {
    const self = this;

    if (GUI.active_tab !== "vtx") {
        GUI.active_tab = "vtx";
    }

    self.analyticsChanges = {};

    read_vtx_config(load_html);

    function load_html() {
        $("#content").load("./tabs/vtx.html", process_html);
    }

    function process_html() {
        initDisplay();

        // translate to user-selected language
        i18n.localizePage();

        self.updating = false;
        GUI.content_ready(callback);
    }

    // Read all the MSP data needed by the tab
    function read_vtx_config(callback_after_msp) {
        vtx_config();

        function vtx_config() {
            MSP.send_message(MSPCodes.MSP_VTX_CONFIG, false, false, vtxConfigReceived);
        }

        function vtxConfigReceived() {
            vtx.intervalId = setInterval(vtx.updateVtxDeviceStatus, 1000);
            vtxtable_bands();
        }

        function vtxtable_bands() {
            // Simulation of static variable
            if (typeof vtxtable_bands.counter === "undefined") {
                TABS.vtx.VTXTABLE_BAND_LIST = [];
                vtxtable_bands.counter = 1;
            } else {
                TABS.vtx.VTXTABLE_BAND_LIST.push(Object.assign({}, FC.VTXTABLE_BAND));
                vtxtable_bands.counter++;
            }

            const buffer = [];
            buffer.push8(vtxtable_bands.counter);

            if (vtxtable_bands.counter <= FC.VTX_CONFIG.vtx_table_bands) {
                MSP.send_message(MSPCodes.MSP_VTXTABLE_BAND, buffer, false, vtxtable_bands);
            } else {
                vtxtable_bands.counter = undefined;
                vtxtable_powerlevels();
            }
        }

        function vtxtable_powerlevels() {
            // Simulation of static variable
            if (typeof vtxtable_powerlevels.counter === "undefined") {
                TABS.vtx.VTXTABLE_POWERLEVEL_LIST = [];
                vtxtable_powerlevels.counter = 1;
            } else {
                TABS.vtx.VTXTABLE_POWERLEVEL_LIST.push(Object.assign({}, FC.VTXTABLE_POWERLEVEL));
                vtxtable_powerlevels.counter++;
            }

            const buffer = [];
            buffer.push8(vtxtable_powerlevels.counter);

            if (vtxtable_powerlevels.counter <= FC.VTX_CONFIG.vtx_table_powerlevels) {
                MSP.send_message(MSPCodes.MSP_VTXTABLE_POWERLEVEL, buffer, false, vtxtable_powerlevels);
            } else {
                vtxtable_powerlevels.counter = undefined;
                callback_after_msp();
            }
        }
    }

    // Validates the vtxConfig object against a JSON Schema
    function validateVtxJson(vtxConfig, callback_valid, callback_error) {
        // At minimum the version must be defined
        if (!vtxConfig.version) {
            console.error("Validation against schema failed, version missing");
            callback_error();
        }

        function validateAgainstSchema(schemaJson, vtxConfig) {
            let valid = false;
            if (schemaJson !== undefined) {
                // Validate
                valid = TABS.vtx.env.validate(schemaJson, vtxConfig) === undefined;
            }

            console.log("Validation against schema result:", valid);
            valid ? callback_valid() : callback_error();
        }

        const vtxJsonSchemaUrl = `../../resources/jsonschema/vtxconfig_schema-${vtxConfig.version}.json`;

        fetch(vtxJsonSchemaUrl)
            .then((response) => response.json())
            .catch((error) => console.error("Error fetching VTX Schema:", error))
            .then((schemaJson) => validateAgainstSchema(schemaJson, vtxConfig));
    }

    // Emulates the MSP read from a vtxConfig object (JSON)
    function read_vtx_config_json(vtxConfig, vtxcallback_after_read) {
        // Bands and channels
        FC.VTX_CONFIG.vtx_table_bands = vtxConfig.vtx_table.bands_list.length;

        let maxChannels = 0;
        TABS.vtx.VTXTABLE_BAND_LIST = [];
        for (let i = 1; i <= FC.VTX_CONFIG.vtx_table_bands; i++) {
            TABS.vtx.VTXTABLE_BAND_LIST[i - 1] = {};
            TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_number = i;
            TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_name = vtxConfig.vtx_table.bands_list[i - 1].name;
            TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_letter = vtxConfig.vtx_table.bands_list[i - 1].letter;
            TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_is_factory_band =
                vtxConfig.vtx_table.bands_list[i - 1].is_factory_band;
            TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies =
                vtxConfig.vtx_table.bands_list[i - 1].frequencies;

            maxChannels = Math.max(maxChannels, TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies.length);
        }

        FC.VTX_CONFIG.vtx_table_channels = maxChannels;

        // Power levels
        FC.VTX_CONFIG.vtx_table_powerlevels = vtxConfig.vtx_table.powerlevels_list.length;

        TABS.vtx.VTXTABLE_POWERLEVEL_LIST = [];
        for (let i = 1; i <= FC.VTX_CONFIG.vtx_table_powerlevels; i++) {
            TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1] = {};
            TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_number = i;
            TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_value =
                vtxConfig.vtx_table.powerlevels_list[i - 1].value;
            TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_label =
                vtxConfig.vtx_table.powerlevels_list[i - 1].label;
        }

        // Setting the latest vtx power to prevent out of bounds error
        if (FC.VTX_CONFIG.vtx_power > TABS.vtx.VTXTABLE_POWERLEVEL_LIST.length) {
            FC.VTX_CONFIG.vtx_power = TABS.vtx.VTXTABLE_POWERLEVEL_LIST.length;
        }

        vtxcallback_after_read();
    }

    // Prepares all the UI elements, the MSP command has been executed before
    function initDisplay() {
        $(".tab-vtx").addClass("supported");

        // Load all the dynamic elements
        loadPowerLevelsTemplate();
        loadBandsChannelsTemplate();
        populateBandSelect();
        populatePowerSelect();

        $(".uppercase").keyup(function () {
            this.value = this.value.toUpperCase().trim();
        });

        // Supported?
        const vtxSupported =
            FC.VTX_CONFIG.vtx_type !== VtxDeviceTypes.VTXDEV_UNSUPPORTED &&
            FC.VTX_CONFIG.vtx_type !== VtxDeviceTypes.VTXDEV_UNKNOWN;
        const vtxTableNotConfigured =
            vtxSupported &&
            FC.VTX_CONFIG.vtx_table_available &&
            (FC.VTX_CONFIG.vtx_table_bands === 0 ||
                FC.VTX_CONFIG.vtx_table_channels === 0 ||
                FC.VTX_CONFIG.vtx_table_powerlevels === 0);

        TABS.vtx.vtxTableFactoryBandsSupported = FC.VTX_CONFIG.vtx_type === VtxDeviceTypes.VTXDEV_SMARTAUDIO;

        $(".vtx_supported").toggle(vtxSupported);
        $(".vtx_not_supported").toggle(!vtxSupported);
        $(".vtx_table_available").toggle(vtxSupported && FC.VTX_CONFIG.vtx_table_available);
        $(".vtx_table_not_configured").toggle(vtxTableNotConfigured);
        $(".vtx_table_save_pending").toggle(TABS.vtx.vtxTableSavePending);
        $(".factory_band").toggle(TABS.vtx.vtxTableFactoryBandsSupported);

        // Insert actual values in the fields
        // Values of the selected mode
        $("#vtx_frequency").val(FC.VTX_CONFIG.vtx_frequency);
        $("#vtx_band").val(FC.VTX_CONFIG.vtx_band);

        $("#vtx_band").change(populateChannelSelect).change();

        $("#vtx_channel").val(FC.VTX_CONFIG.vtx_channel);
        if (FC.VTX_CONFIG.vtx_table_available) {
            $("#vtx_channel").attr("max", FC.VTX_CONFIG.vtx_table_channels);
        }

        $("#vtx_power").val(FC.VTX_CONFIG.vtx_power);
        $("#vtx_pit_mode").prop("checked", FC.VTX_CONFIG.vtx_pit_mode);
        $("#vtx_pit_mode_frequency").val(FC.VTX_CONFIG.vtx_pit_mode_frequency);
        $("#vtx_low_power_disarm").val(FC.VTX_CONFIG.vtx_low_power_disarm);

        // Values of the current values
        const vtxReady_e = $(".VTX_info span.colorToggle");
        vtxReady_e.text(
            FC.VTX_CONFIG.vtx_device_ready ? i18n.getMessage("vtxReadyTrue") : i18n.getMessage("vtxReadyFalse"),
        );
        vtxReady_e.toggleClass("ready", FC.VTX_CONFIG.vtx_device_ready);

        $("#vtx_type_description").text(self.getVtxTypeString());
        $("#vtx_channel_description").text(FC.VTX_CONFIG.vtx_channel);
        $("#vtx_frequency_description").text(FC.VTX_CONFIG.vtx_frequency);
        $("#vtx_pit_mode_description").text(
            FC.VTX_CONFIG.vtx_pit_mode ? i18n.getMessage("yes") : i18n.getMessage("no"),
        );
        $("#vtx_pit_mode_frequency_description").text(FC.VTX_CONFIG.vtx_pit_mode_frequency);
        $("#vtx_low_power_disarm_description").text(
            i18n.getMessage(`vtxLowPowerDisarmOption_${FC.VTX_CONFIG.vtx_low_power_disarm}`),
        );

        if (FC.VTX_CONFIG.vtx_band === 0) {
            $("#vtx_band_description").text(i18n.getMessage("vtxBand_0"));
        } else {
            if (FC.VTX_CONFIG.vtx_table_available && TABS.vtx.VTXTABLE_BAND_LIST[FC.VTX_CONFIG.vtx_band - 1]) {
                let bandName = TABS.vtx.VTXTABLE_BAND_LIST[FC.VTX_CONFIG.vtx_band - 1].vtxtable_band_name;
                if (bandName.trim() === "") {
                    bandName = FC.VTX_CONFIG.vtx_band;
                }
                $("#vtx_band_description").text(bandName);
            } else {
                $("#vtx_band_description").text(FC.VTX_CONFIG.vtx_band);
            }
        }

        if (FC.VTX_CONFIG.vtx_power === 0) {
            $("#vtx_power_description").text(i18n.getMessage("vtxPower_0"));
        } else {
            if (FC.VTX_CONFIG.vtx_table_available) {
                let powerLevel =
                    TABS.vtx.VTXTABLE_POWERLEVEL_LIST[FC.VTX_CONFIG.vtx_power - 1].vtxtable_powerlevel_label;
                if (powerLevel.trim() === "") {
                    powerLevel = FC.VTX_CONFIG.vtx_power;
                }
                $("#vtx_power_description").text(powerLevel);
            } else {
                const levelText = i18n.getMessage("vtxPower_X", { powerLevel: FC.VTX_CONFIG.vtx_power });
                $("#vtx_power_description").text(levelText);
            }
        }

        $("#vtx_table_powerlevels").val(FC.VTX_CONFIG.vtx_table_powerlevels);

        // Populate power levels
        for (let i = 1; i <= TABS.vtx.VTXTABLE_POWERLEVEL_LIST.length; i++) {
            $(`#vtx_table_powerlevels_${i}`).val(TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_value);
            $(`#vtx_table_powerlabels_${i}`).val(TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_label);
        }

        $("#vtx_table_bands").val(FC.VTX_CONFIG.vtx_table_bands);
        $("#vtx_table_channels").val(FC.VTX_CONFIG.vtx_table_channels);

        // Populate VTX Table
        let hasFactoryBands = false;
        for (let i = 1; i <= TABS.vtx.VTXTABLE_BAND_LIST.length; i++) {
            $(`#vtx_table_band_name_${i}`).val(TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_name);
            $(`#vtx_table_band_letter_${i}`).val(TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_letter);
            $(`#vtx_table_band_factory_${i}`).prop(
                "checked",
                TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_is_factory_band,
            );
            hasFactoryBands = hasFactoryBands || TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_is_factory_band;
            for (let j = 1; j <= TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies.length; j++) {
                $(`#vtx_table_band_channel_${i}_${j}`).val(
                    TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies[j - 1],
                );
            }
        }

        $(".vtx_table_factory_bands_not_supported").toggle(!TABS.vtx.vtxTableFactoryBandsSupported && hasFactoryBands);

        // Actions and other
        function frequencyOrBandChannel() {
            const frequencyEnabled = $(this).prop("checked");

            if (frequencyEnabled) {
                $(".field.vtx_channel").slideUp(100, function () {
                    $(".field.vtx_band").slideUp(100, function () {
                        $(".field.vtx_frequency").slideDown(100);
                    });
                });
            } else {
                $(".field.vtx_frequency").slideUp(100, function () {
                    $(".field.vtx_band").slideDown(100, function () {
                        $(".field.vtx_channel").slideDown(100);
                    });
                });
            }
        }

        $("#vtx_frequency_channel")
            .prop("checked", FC.VTX_CONFIG.vtx_band === 0 && FC.VTX_CONFIG.vtx_frequency > 0)
            .change(frequencyOrBandChannel);

        if ($("#vtx_frequency_channel").prop("checked")) {
            $(".field.vtx_channel").hide();
            $(".field.vtx_band").hide();
            $(".field.vtx_frequency").show();
        } else {
            $(".field.vtx_channel").show();
            $(".field.vtx_band").show();
            $(".field.vtx_frequency").hide();
        }

        function showHidePowerlevels() {
            const powerlevelsValue = $(this).val();

            for (let i = 1; i <= TABS.vtx.MAX_POWERLEVEL_VALUES; i++) {
                $(`.vtx_table_powerlevels_table td:nth-child(${i})`).toggle(i <= powerlevelsValue);
            }
        }

        $("#vtx_table_powerlevels").on("input", showHidePowerlevels).trigger("input");

        function showHideBands() {
            const bandsValue = $(this).val();

            for (let i = 1; i <= TABS.vtx.MAX_BAND_VALUES; i++) {
                $(`.vtx_table_bands_table tr:nth-child(${i + 1})`).toggle(i <= bandsValue);
            }
        }

        $("#vtx_table_bands").on("input", showHideBands).trigger("input");

        function showHideBandChannels() {
            const channelsValue = $(this).val();

            for (let i = 1; i <= TABS.vtx.MAX_BAND_CHANNELS_VALUES; i++) {
                $(`.vtx_table_bands_table td:nth-child(${i + 3})`).toggle(i <= channelsValue);
            }
        }

        $("#vtx_table_channels").on("input", showHideBandChannels).trigger("input");
        $("#vtx_table").change(function () {
            let fromScratch = true;
            if (
                self.analyticsChanges["VtxTableLoadFromClipboard"] !== undefined ||
                self.analyticsChanges["VtxTableLoadFromFile"] !== undefined
            ) {
                fromScratch = false;
            }
            self.analyticsChanges["VtxTableEdit"] = fromScratch ? "modificationOnly" : "fromTemplate";
        });

        /*** Helper functions */

        function loadPowerLevelsTemplate() {
            // Power levels title
            const powerLevelsTitleEle = $(".vtx_table_powerlevels_table .vtx_table_powerlevels_title");

            for (let i = 1; i <= TABS.vtx.MAX_POWERLEVEL_VALUES; i++) {
                powerLevelsTitleEle.append(`<td><span>${i}</span></td>`);
            }

            // Power levels
            const powerLevelsRowEle = $(".vtx_table_powerlevels_table .vtx_table_powerlevels_values");

            const powerValuesEle = $("#tab-vtx-templates #tab-vtx-powerlevel-values td");
            for (let i = 1; i <= TABS.vtx.MAX_POWERLEVEL_VALUES; i++) {
                const newPowerValuesEle = powerValuesEle.clone();
                $(newPowerValuesEle).find("input").attr("id", `vtx_table_powerlevels_${i}`);
                powerLevelsRowEle.append(newPowerValuesEle);
            }
            powerLevelsRowEle.append(`<td><span>${i18n.getMessage("vtxTablePowerLevelsValue")}</span></td>`);

            // Power labels
            const powerLabelsRowEle = $(".vtx_table_powerlevels_table .vtx_table_powerlevels_labels");

            const powerLabelsEle = $("#tab-vtx-templates #tab-vtx-powerlevel-labels td");
            for (let i = 1; i <= TABS.vtx.MAX_POWERLEVEL_VALUES; i++) {
                const newPowerLabelsEle = powerLabelsEle.clone();
                $(newPowerLabelsEle).find("input").attr("id", `vtx_table_powerlabels_${i}`);
                powerLabelsRowEle.append(newPowerLabelsEle);
            }
            powerLabelsRowEle.append(`<td><span>${i18n.getMessage("vtxTablePowerLevelsLabel")}</span></td>`);
        }

        function loadBandsChannelsTemplate() {
            const bandsTableEle = $(".vtx_table_bands_table tbody");

            // Title
            const titleEle = $("#tab-vtx-templates #tab-vtx-bands-title tr");

            for (let i = 1; i <= TABS.vtx.MAX_BAND_VALUES; i++) {
                titleEle.append(`<td><span>${i}</span></td>`);
            }
            bandsTableEle.append(titleEle);

            // Bands
            const bandEle = $("#tab-vtx-templates #tab-vtx-bands tr");
            const channelEle = $("#tab-vtx-templates #tab-vtx-channels td");
            for (let i = 1; i <= TABS.vtx.MAX_BAND_VALUES; i++) {
                const newBandEle = bandEle.clone();
                $(newBandEle).find("#vtx_table_band_name").attr("id", `vtx_table_band_name_${i}`);
                $(newBandEle).find("#vtx_table_band_letter").attr("id", `vtx_table_band_letter_${i}`);
                $(newBandEle).find("#vtx_table_band_factory").attr("id", `vtx_table_band_factory_${i}`);

                // Channels
                for (let j = 1; j <= TABS.vtx.MAX_BAND_CHANNELS_VALUES; j++) {
                    const newChannelEle = channelEle.clone();
                    $(newChannelEle).find("input").attr("id", `vtx_table_band_channel_${i}_${j}`);

                    newBandEle.append(newChannelEle);
                }

                // Append to the end an index of the band
                newBandEle.append(`<td><span>${i18n.getMessage("vtxBand_X", { bandName: i })}</span></td>`);

                bandsTableEle.append(newBandEle);
            }
        }

        function populateBandSelect() {
            const selectBand = $(".field #vtx_band");

            selectBand.append(new Option(i18n.getMessage("vtxBand_0"), 0));
            if (FC.VTX_CONFIG.vtx_table_available) {
                for (let i = 1; i <= FC.VTX_CONFIG.vtx_table_bands; i++) {
                    let bandName = TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_name;
                    if (bandName.trim() === "") {
                        bandName = i18n.getMessage("vtxBand_X", { bandName: i });
                    }
                    selectBand.append(new Option(bandName, i));
                }
            } else {
                for (let i = 1; i <= TABS.vtx.MAX_BAND_VALUES; i++) {
                    selectBand.append(new Option(i18n.getMessage("vtxBand_X", { bandName: i }), i));
                }
            }
            // Sort the element, if need to group, do it by lexical sort, ie. by naming of (the translated) selection text
            selectBand.sortSelect(i18n.getMessage("vtxBand_0"));
        }

        function populateChannelSelect() {
            const selectChannel = $(".field #vtx_channel");
            const selectedBand = $("#vtx_band").val();

            selectChannel.empty();

            selectChannel.append(new Option(i18n.getMessage("vtxChannel_0"), 0));
            if (FC.VTX_CONFIG.vtx_table_available) {
                if (TABS.vtx.VTXTABLE_BAND_LIST[selectedBand - 1]) {
                    for (
                        let i = 1;
                        i <= TABS.vtx.VTXTABLE_BAND_LIST[selectedBand - 1].vtxtable_band_frequencies.length;
                        i++
                    ) {
                        const channelName =
                            TABS.vtx.VTXTABLE_BAND_LIST[selectedBand - 1].vtxtable_band_frequencies[i - 1];
                        if (channelName > 0) {
                            selectChannel.append(new Option(i18n.getMessage("vtxChannel_X", { channelName: i }), i));
                        }
                    }
                }
            } else {
                for (let i = 1; i <= TABS.vtx.MAX_BAND_CHANNELS_VALUES; i++) {
                    selectChannel.append(new Option(i18n.getMessage("vtxChannel_X", { channelName: i }), i));
                }
            }
        }

        function populatePowerSelect() {
            const selectPower = $(".field #vtx_power");

            if (FC.VTX_CONFIG.vtx_table_available) {
                selectPower.append(new Option(i18n.getMessage("vtxPower_0"), 0));
                for (let i = 1; i <= FC.VTX_CONFIG.vtx_table_powerlevels; i++) {
                    let powerLevel = TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_label;
                    if (powerLevel.trim() === "") {
                        powerLevel = i18n.getMessage("vtxPower_X", { powerLevel: i });
                    }
                    selectPower.append(new Option(powerLevel, i));
                }
            } else {
                const powerMaxMinValues = getPowerValues(FC.VTX_CONFIG.vtx_type);
                for (let i = powerMaxMinValues.min; i <= powerMaxMinValues.max; i++) {
                    if (i === 0) {
                        selectPower.append(new Option(i18n.getMessage("vtxPower_0"), 0));
                    } else {
                        selectPower.append(new Option(i18n.getMessage("vtxPower_X", { powerLevel: i }), i));
                    }
                }
            }
        }

        // Returns the power values min and max depending on the VTX Type
        function getPowerValues(vtxType) {
            let powerMinMax = {};

            if (FC.VTX_CONFIG.vtx_table_available) {
                powerMinMax = { min: 1, max: FC.VTX_CONFIG.vtx_table_powerlevels };
            } else {
                switch (vtxType) {
                    case VtxDeviceTypes.VTXDEV_UNSUPPORTED:
                        powerMinMax = {};
                        break;

                    case VtxDeviceTypes.VTXDEV_RTC6705:
                        powerMinMax = { min: 1, max: 3 };
                        break;

                    case VtxDeviceTypes.VTXDEV_SMARTAUDIO:
                        powerMinMax = { min: 1, max: 4 };
                        break;

                    case VtxDeviceTypes.VTXDEV_TRAMP:
                        powerMinMax = { min: 1, max: 5 };
                        break;

                    case VtxDeviceTypes.VTXDEV_MSP:
                        powerMinMax = { min: 1, max: 5 };
                        break;

                    case VtxDeviceTypes.VTXDEV_UNKNOWN:
                    default:
                        powerMinMax = { min: 0, max: 7 };
                }
            }
            return powerMinMax;
        }

        // Save and other button functions
        $("a.save_file").click(function () {
            save_json();
        });

        $("a.save_lua").click(function () {
            save_lua();
        });

        $("a.load_file").click(function () {
            load_json();
        });

        $("a.load_clipboard").click(function () {
            load_clipboard_json();
        });

        $("a.save").click(function () {
            if (!self.updating) {
                save_vtx();
            }
        });
    }

    function save_lua() {
        const suffix = "lua";

        const uid0 = FC.CONFIG.uid[0].toString(16).padStart(8, "0");
        const uid1 = FC.CONFIG.uid[1].toString(16).padStart(8, "0");
        const uid2 = FC.CONFIG.uid[2].toString(16).padStart(8, "0");

        const filename = `${uid0}${uid1}${uid2}.${suffix}`;

        FileSystem.pickSaveFile(
            filename,
            i18n.getMessage("fileSystemPickerFiles", { typeof: suffix.toUpperCase() }),
            `.${suffix}`,
        )
            .then((file) => {
                dump_html_to_msp();
                const vtxConfig = createVtxConfigInfo();
                const text = createLuaTables(vtxConfig);

                console.log("Saving lua to:", file.name);
                FileSystem.writeFile(file, text);
            })
            .catch((error) => {
                console.error("Failed to write lua file:", error);
                gui_log(i18n.getMessage("vtxSavedLuaFileKo"));
            });
    }
    function save_json() {
        const suggestedName = "vtxtable";
        const suffix = "json";

        const filename = generateFilename(suggestedName, suffix);

        FileSystem.pickSaveFile(
            filename,
            i18n.getMessage("fileSystemPickerFiles", { typeof: suffix.toUpperCase() }),
            `.${suffix}`,
        )
            .then((file) => {
                dump_html_to_msp();
                const vtxConfig = createVtxConfigInfo();
                const text = JSON.stringify(vtxConfig, null, 4);

                console.log("Saving VTX to:", file.name);
                FileSystem.writeFile(file, text);
            })
            .catch((error) => {
                console.error("Failed to write VTX file:", error);
                gui_log(i18n.getMessage("vtxSavedFileKo"));
            });
    }

    function load_json() {
        const suffix = "json";

        FileSystem.pickOpenFile(
            i18n.getMessage("fileSystemPickerFiles", { typeof: suffix.toUpperCase() }),
            `.${suffix}`,
        )
            .then((file) => {
                console.log("Reading VTX config from:", file.name);
                FileSystem.readFile(file).then((text) => {
                    const vtxConfig = JSON.parse(text);

                    validateVtxJson(
                        vtxConfig,
                        function () {
                            // JSON is valid
                            read_vtx_config_json(vtxConfig, load_html);

                            TABS.vtx.vtxTableSavePending = true;

                            self.analyticsChanges["VtxTableLoadFromClipboard"] = undefined;
                            self.analyticsChanges["VtxTableLoadFromFile"] = file.name;

                            console.log("Load VTX file end");
                            gui_log(i18n.getMessage("vtxLoadFileOk"));
                        },
                        function () {
                            // JSON is NOT valid
                            console.error("VTX Config from file failed validation against schema");
                            gui_log(i18n.getMessage("vtxLoadFileKo"));
                        },
                    );
                });
            })
            .catch((error) => {
                console.error("Failed loading VTX file config", error);
                gui_log(i18n.getMessage("vtxLoadFileKo"));
            });
    }

    function load_clipboard_json() {
        try {
            Clipboard.readText(
                function (text) {
                    console.log("Pasted content: ", text);

                    const vtxConfig = JSON.parse(text);

                    validateVtxJson(
                        vtxConfig,
                        function () {
                            // JSON is valid
                            read_vtx_config_json(vtxConfig, load_html);

                            TABS.vtx.vtxTableSavePending = true;

                            self.analyticsChanges["VtxTableLoadFromFile"] = undefined;
                            self.analyticsChanges["VtxTableLoadFromClipboard"] = text.length;

                            console.log("Load VTX clipboard end");
                            gui_log(i18n.getMessage("vtxLoadClipboardOk"));
                        },
                        function () {
                            // JSON is NOT valid
                            gui_log(i18n.getMessage("vtxLoadClipboardKo"));
                            console.error("VTX Config from clipboard failed validation against schema");
                        },
                    );
                },
                function (err) {
                    gui_log(i18n.getMessage("vtxLoadClipboardKo"));
                    console.error("Failed to read clipboard contents: ", err);
                },
            );
        } catch (err) {
            console.error(`Failed loading VTX file config: ${err}`);
            gui_log(i18n.getMessage("vtxLoadClipboardKo"));
        }
    }

    // Save all the values from the tab to MSP
    function save_vtx() {
        self.updating = true;

        dump_html_to_msp();

        // Start MSP saving
        save_vtx_config();

        tracking.sendSaveAndChangeEvents(tracking.EVENT_CATEGORIES.FLIGHT_CONTROLLER, self.analyticsChanges, "vtx");

        function save_vtx_config() {
            MSP.send_message(
                MSPCodes.MSP_SET_VTX_CONFIG,
                mspHelper.crunch(MSPCodes.MSP_SET_VTX_CONFIG),
                false,
                save_vtx_powerlevels,
            );
        }

        function save_vtx_powerlevels() {
            // Simulation of static variable
            if (typeof save_vtx_powerlevels.counter === "undefined") {
                save_vtx_powerlevels.counter = 0;
            } else {
                save_vtx_powerlevels.counter++;
            }

            if (save_vtx_powerlevels.counter < FC.VTX_CONFIG.vtx_table_powerlevels) {
                FC.VTXTABLE_POWERLEVEL = { ...TABS.vtx.VTXTABLE_POWERLEVEL_LIST[save_vtx_powerlevels.counter] };
                MSP.send_message(
                    MSPCodes.MSP_SET_VTXTABLE_POWERLEVEL,
                    mspHelper.crunch(MSPCodes.MSP_SET_VTXTABLE_POWERLEVEL),
                    false,
                    save_vtx_powerlevels,
                );
            } else {
                save_vtx_powerlevels.counter = undefined;
                save_vtx_bands();
            }
        }

        function save_vtx_bands() {
            // Simulation of static variable
            if (typeof save_vtx_bands.counter === "undefined") {
                save_vtx_bands.counter = 0;
            } else {
                save_vtx_bands.counter++;
            }

            if (save_vtx_bands.counter < FC.VTX_CONFIG.vtx_table_bands) {
                FC.VTXTABLE_BAND = Object.assign({}, TABS.vtx.VTXTABLE_BAND_LIST[save_vtx_bands.counter]);
                MSP.send_message(
                    MSPCodes.MSP_SET_VTXTABLE_BAND,
                    mspHelper.crunch(MSPCodes.MSP_SET_VTXTABLE_BAND),
                    false,
                    save_vtx_bands,
                );
            } else {
                save_vtx_bands.counter = undefined;
                save_to_eeprom();
            }
        }

        function save_to_eeprom() {
            mspHelper.writeConfiguration(false, save_completed);
        }

        function save_completed() {
            TABS.vtx.vtxTableSavePending = false;

            const saveButton = $("#save_button");
            const oldText = saveButton.text();
            const buttonDelay = 1500;

            saveButton.html(i18n.getMessage("buttonSaving")).addClass("disabled");

            clearInterval(TABS.vtx.intervalId);

            // Allow firmware to make relevant changes before initialization
            setTimeout(() => {
                saveButton.html(i18n.getMessage("buttonSaved"));

                setTimeout(() => {
                    TABS.vtx.initialize();
                    saveButton.html(oldText).removeClass("disabled");
                }, buttonDelay);
            }, buttonDelay);
        }
    }

    function dump_html_to_msp() {
        // General config
        const frequencyEnabled = $("#vtx_frequency_channel").prop("checked");
        if (frequencyEnabled) {
            FC.VTX_CONFIG.vtx_frequency = parseInt($("#vtx_frequency").val());
            FC.VTX_CONFIG.vtx_band = 0;
            FC.VTX_CONFIG.vtx_channel = 0;
        } else {
            FC.VTX_CONFIG.vtx_band = parseInt($("#vtx_band").val());
            FC.VTX_CONFIG.vtx_channel = parseInt($("#vtx_channel").val());
            FC.VTX_CONFIG.vtx_frequency = 0;
        }
        FC.VTX_CONFIG.vtx_power = parseInt($("#vtx_power").val());
        FC.VTX_CONFIG.vtx_pit_mode = $("#vtx_pit_mode").prop("checked");
        FC.VTX_CONFIG.vtx_pit_mode_frequency = parseInt($("#vtx_pit_mode_frequency").val());
        FC.VTX_CONFIG.vtx_low_power_disarm = parseInt($("#vtx_low_power_disarm").val());
        FC.VTX_CONFIG.vtx_table_clear = true;

        // Power levels
        FC.VTX_CONFIG.vtx_table_powerlevels = parseInt($("#vtx_table_powerlevels").val());

        TABS.vtx.VTXTABLE_POWERLEVEL_LIST = [];
        for (let i = 1; i <= FC.VTX_CONFIG.vtx_table_powerlevels; i++) {
            TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1] = {};
            TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_number = i;
            TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_value = parseInt(
                $(`#vtx_table_powerlevels_${i}`).val(),
            );
            TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_label = $(`#vtx_table_powerlabels_${i}`).val();
        }

        // Bands and channels
        FC.VTX_CONFIG.vtx_table_bands = parseInt($("#vtx_table_bands").val());
        FC.VTX_CONFIG.vtx_table_channels = parseInt($("#vtx_table_channels").val());
        TABS.vtx.VTXTABLE_BAND_LIST = [];
        for (let i = 1; i <= FC.VTX_CONFIG.vtx_table_bands; i++) {
            TABS.vtx.VTXTABLE_BAND_LIST[i - 1] = {};
            TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_number = i;
            TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_name = $(`#vtx_table_band_name_${i}`).val();
            TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_letter = $(`#vtx_table_band_letter_${i}`).val();
            TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_is_factory_band = TABS.vtx.vtxTableFactoryBandsSupported
                ? $(`#vtx_table_band_factory_${i}`).prop("checked")
                : false;

            TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies = [];
            for (let j = 1; j <= FC.VTX_CONFIG.vtx_table_channels; j++) {
                TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies.push(
                    parseInt($(`#vtx_table_band_channel_${i}_${j}`).val()),
                );
            }
        }
    }

    // Copies from the MSP data to the vtxInfo object (JSON)
    function createVtxConfigInfo() {
        const vtxConfig = {
            description: "Betaflight VTX Config file",
            version: "1.0",
        };

        vtxConfig.vtx_table = {};

        vtxConfig.vtx_table.bands_list = [];
        for (let i = 1; i <= FC.VTX_CONFIG.vtx_table_bands; i++) {
            vtxConfig.vtx_table.bands_list[i - 1] = {};
            vtxConfig.vtx_table.bands_list[i - 1].name = TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_name;
            vtxConfig.vtx_table.bands_list[i - 1].letter = TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_letter;
            vtxConfig.vtx_table.bands_list[i - 1].is_factory_band =
                TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_is_factory_band;
            vtxConfig.vtx_table.bands_list[i - 1].frequencies =
                TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies;
        }

        vtxConfig.vtx_table.powerlevels_list = [];
        for (let i = 1; i <= FC.VTX_CONFIG.vtx_table_powerlevels; i++) {
            vtxConfig.vtx_table.powerlevels_list[i - 1] = {};
            vtxConfig.vtx_table.powerlevels_list[i - 1].value =
                TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_value;
            vtxConfig.vtx_table.powerlevels_list[i - 1].label =
                TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_label;
        }

        return vtxConfig;
    }

    function createLuaTables(vtxConfig) {
        let bandsString = 'bandTable = { [0]="U"';
        let frequenciesString = "frequencyTable = {\n";

        const bandsList = vtxConfig.vtx_table.bands_list;
        for (let index = 0, len = bandsList.length; index < len; ++index) {
            bandsString += `, "${bandsList[index].letter}"`;
            frequenciesString += "        { ";
            for (let i = 0, l = bandsList[index].frequencies.length; i < l; ++i) {
                frequenciesString += `${bandsList[index].frequencies[i]}, `;
            }
            frequenciesString += "},\n";
        }
        bandsString += " },\n";
        frequenciesString += "    },\n";

        const freqBandsString = `frequenciesPerBand = ${bandsList[1].frequencies.length},\n`;

        const powerList = vtxConfig.vtx_table.powerlevels_list;
        let powersString = "powerTable = { ";
        for (let index = 0, len = powerList.length; index < len; ++index) {
            powersString += `[${index + 1}]="${powerList[index].label}", `;
        }
        powersString += "},\n";

        return `return {\n    ${frequenciesString}    ${freqBandsString}    ${bandsString}    ${powersString}}`;
    }
};

vtx.cleanup = function (callback) {
    // Add here things that need to be cleaned or closed before leaving the tab
    this.vtxTableSavePending = false;
    this.VTXTABLE_BAND_LIST = [];
    this.VTXTABLE_POWERLEVEL_LIST = [];

    clearInterval(this.intervalId);

    if (callback) {
        callback();
    }
};

TABS.vtx = vtx;
export { vtx };
