<template>
  <select class="select2 form-select" ref="select2" required name="filter_type" :multiple="multiple" :disabled="disabled">
    <option class="no-wrap  p-0" v-for="(item, i) in options_2" :selected="is_selected(item)" :value="item.value" :disabled="item.disabled">
      {{item.label}}
    </option>
    <optgroup v-for="(item, i) in groups_options_2" :label="item.group">
      <option v-for="(opt, j) in item.options" :selected="is_selected(opt)" :value="opt.value" :disabled="opt.disabled">
        {{opt.label}}
      </option>
    </optgroup>
  </select>
</template>

<script setup>
import { ref, onMounted, computed, watch, onBeforeUnmount } from "vue";

const select2 = ref(null);

// const selected2_option = ref({});

const emit = defineEmits(['update:selected_option', 'update:selected_options', 'select_option', 'unselect_option', 'change_selected_options']);

const options_2 = ref([]);
const groups_options_2 = ref([]);
const selected_option_2 = ref({});
const selected_values = ref([]); // used only if multiple == true
const refresh_options = ref(0);

const props = defineProps({
    id: String,
    options: Array,
    selected_option: Object,
    selected_options: Array,
    multiple: Boolean,
    add_tag: Boolean,
    disable_change: Boolean,
    theme: String,
    dropdown_size: String,
    disabled: Boolean
});

let first_time_render = true;

onMounted(() => {
    if (!props.options) { return; }
    if (!props.disable_change || !first_time_render) {
    	set_input();
    }
});

watch(() => props.selected_option, (cur_value, old_value) => {
    set_selected_option(cur_value);
    change_select_2_selected_value();
}, { flush: 'pre'});

watch(() => props.selected_options, (cur_value, old_value) => {
    set_selected_values(cur_value);
    change_select_2_selected_value();
}, { flush: 'pre'});


watch([refresh_options], (cur_value, old_value) => {
    render();
}, { flush: 'post'});


watch(() => props.options, (current_value, old_value) => {
    if (props.disable_change == true || current_value == null) { return; }
    set_input();
}, { flush: 'pre'});


function set_input() {
    set_options();
    set_selected_option();
    set_selected_values();
}

function set_options() {
    options_2.value = [];
    groups_options_2.value = [];
    
    if (props.options == null) { return; }
    let groups_dict = {};
    props.options.forEach((option) => {
	let opt_2 = { ...option };
	if (opt_2.value == null) {
	    opt_2.value = opt_2.label;
	}
	if (option.group == null) {
	    options_2.value.push(opt_2);
	} else {
	    if (groups_dict[option.group] == null) {
		groups_dict[option.group] = { group: opt_2.group, options: [] };
	    }
	    groups_dict[option.group].options.push(opt_2);
	}
    });
    groups_options_2.value = ntopng_utility.object_to_array(groups_dict);
    refresh_options.value += 1;
}


const render = () => {
    let select2Div = select2.value;
    if (first_time_render == false) {
	destroy();
    }
    if (!$(select2Div).hasClass("select2-hidden-accessible")) {
	$(select2Div).select2({
	    width: '100%',
	    theme: props.theme ? props.theme : 'bootstrap-5',
	    dropdownParent: $(select2Div).parent(),
	    dropdownAutoWidth : true,
        tags: props.add_tag && !props.multiple,
        selectionCssClass: props.dropdown_size == "small" ? 'select2--small' : '',
        dropdownCssClass: props.dropdown_size == "small" ? 'select2--small' : ''
	});
	$(select2Div).on('select2:select', function (e) {
        let data = e.params.data;
            if (data.element === null) {
                //TODO: implement for multiselect
                let option = { label: data.text, value: data.id };
		emit('update:selected_option', option);
		emit('select_option', option);
                return;
            } 
	    let value = data.element._value;
	    let option = find_option_from_value_or_label(value);
	    if (value !== props.selected_option) {
		emit('update:selected_option', option);
		emit('select_option', option);
            }
	    if (!props.multiple) {
		return;
	    }
	    selected_values.value = selected_values.value.filter((v) => v != value);
	    selected_values.value.push(value);
	    let options = find_options_from_values(selected_values.value);
	    emit('update:selected_options', options);
	    emit('change_selected_options', options);		 
	});
	$(select2Div).on('select2:unselect', function (e) {
	    let data = e.params.data;
	    let value = data.element._value;
	    if (!props.multiple) {
		return;
	    }
	    selected_values.value = selected_values.value.filter((v) => v != value);
	    let option = find_option_from_value_or_label(value);
	    let options = find_options_from_values(selected_values.value);
	    emit('unselect_option', option);
	    emit('update:selected_options', options);
	    emit('change_selected_options', options);		 
	});
    }
    first_time_render = false;
    // this.$forceUpdate();
    change_select_2_selected_value();
};

function change_select_2_selected_value() {
    let select2Div = select2.value;
    if (!props.multiple) {
	let value = get_value_from_selected_option(props.selected_option);
	$(select2Div).val(value);
	$(select2Div).trigger("change");
    } else {
	$(select2Div).val(selected_values.value);
	$(select2Div).trigger("change");
    }
}

function is_selected(item) {
    if (!props.multiple) {
	const is_zero_value = selected_option_2.value.value == 0 ||selected_option_2.value.value == "0";
	return item.value == selected_option_2.value.value || (is_zero_value && item.label == selected_option_2.value.label);
}
   return selected_values.value.find((v) => v == item.value) != null || item.selected; 
}

function set_selected_values() {
    if (props.selected_options == null || !props.multiple) {
        return;
    }
    selected_values.value = [];
    props.selected_options.forEach((opt) => {
        let value = opt.value || opt.label;
        selected_values.value.push(value);
    });
}

function set_selected_option(selected_option) {
    if (selected_option == null && !props.multiple) {
	selected_option = get_props_selected_option();
    }
    selected_option_2.value = selected_option;
}

function get_props_selected_option() {
    if (props.selected_option == null) {
	return props.options[0];
    }
    return props.selected_option;
}

function get_value_from_selected_option(selected_option) {
    if (selected_option == null) {
	selected_option = get_props_selected_option();
    }
    let value;
    if (selected_option.value != null) {
	value = selected_option.value;
    } else {
	value = selected_option.label;
    }
    return value;
}

function find_options_from_values(values) {
    let options = values.map((v) => find_option_from_value_or_label(v));
    return options;
}

function find_option_from_value_or_label(value) {
    let option_2 = find_option_2_from_value(value);
    let option = props.options.find((o) => (o.value === option_2.value) || (o.label == option_2.label));
    return option;
}

function find_option_2_from_value(value) {
    if (value == null) {
	value = get_value_from_selected_option();
    }
    // let option = options_2.value.find((o) => o.value == value);
    let option = options_2.value.find((o) => o.value === value);
    if (option != null) { return option; }
    for (let i = 0; i < groups_options_2.value.length; i += 1) {
	let g = groups_options_2.value[i];
	option = g.options.find((o) => o.value === value);
	if (option != null) {
	    return option;
	}
    }
    return null;
}
    
defineExpose({ render });

function destroy() {
    try {
	$(select2.value).select2('destroy');
	$(select2.value).off('select2:select');    
    } catch(err) {
	console.error("Destroy select-search catch error:");
	console.error(err);
    }
}

onBeforeUnmount(() => {
    destroy();
});

</script>
