import { GOVBRSuggest } from '../../suggest/1.2.0/GOVBRSuggest.mjs';

/**
 * Classe para o UC para exibição de ítems em árvore através da TreeView.
 */
class GOVBRTreeViewUC {
    /**
     * @type {import("./GOVBRTreeViewUserControl.mjs").GOVBRTreeViewUserControl}
     */
    userControl;
    /**
     * @type {HTMLElement}
     */
    host;
    /**
     * @type {HTMLElement}
     */
    tree;
    /**
     * @type {any}
     */
    instance;

    /**
     * @type {GOVBRSuggest}
     */
    _suggest;

    /**
     * @param {import('./GOVBRTreeViewUserControl.mjs').GOVBRTreeViewUserControl} userControl
     * @param {HTMLElement} host
     */
    constructor(userControl, host) {
        this.userControl = userControl;
        this.host = host;

        this._suggest = new GOVBRSuggest(this.host);

        this.host.classList.add('govbr-treeview-container');
        this.tree = document.createElement('div');
        this.tree.classList.add('govbr-treeview');
        this.host.style.setProperty('width', this.userControl.LARGURA_COMPONENTE || '');
        this.host.style.setProperty('height', this.userControl.ALTURA_COMPONENTE || '');

        (async () => {
            const nomeScript = GOVBRPlataformaJS.logs.isDevelop ? 'jstree' : 'jstree.min';
            await GOVBRPlataformaJS.importarModulo(this.userControl.URL_CDN, 'jstree', '3.3.17', nomeScript, 'script');
            await GOVBRPlataformaJS.importarStyleSheet(this.userControl.URL_CDN, 'treeview', this.userControl.VERSAO_JS_COMPONENTE, 'GOVBRTreeViewUC', this.host);
            GOVBR.logs.debug('TreeView - Carregado');
            if (this.userControl.UTILIZA_PESQUISA) {
                this.montaBarraPesquisa();
            }
            await this.initTree();
            this.host.append(this.tree);
            GOVBR.logs.debug('TreeView - Iniciado');
            GOVBR.logs.debug(this);
        })();
    }

    montaBarraPesquisa() {
        const container = document.createElement('div');
        container.classList.add('govbr-treeview-pesquisa');
        const lupa = document.createElement('i');
        lupa.classList.add('govbr-treeview-pesquisa-icone', 'fa-solid', 'fa-search');
        const pesquisa = document.createElement('input');
        pesquisa.classList.add('govbr-treeview-pesquisa-campo');
        pesquisa.type = 'text';
        /**
         * @type {number}
         */
        let timeout;
        pesquisa.addEventListener('input', () => {
            if (timeout) {
                clearTimeout(timeout);
            }
            timeout = setTimeout(() => {
                timeout = null;
                this.instance.search(pesquisa.value);
            }, 250);
        });
        container.append(lupa);
        container.append(pesquisa);
        this.host.append(container);
    }

    /**
     * Inicia a tree ou recria esta do UC caso já exista.
     */
    async initTree() {
        if (this.instance) {
            this.instance.destroy();
        }
        if (this.userControl.PERMITE_SELECAO && !this.userControl.UTILIZA_CHECKBOX) {
            this.tree.classList.add('jstree-selection');
        } else {
            this.tree.classList.remove('jstree-selection');
        }
        this.tree.innerHTML = '';
        this.tree.setAttribute('id', this.userControl.IDENTIFICADOR_COMPONENTE);
        // @ts-ignore
        const $ = window['$'] || window['jQuery'];
        $(this.tree).data('DND_ALVO_ID_TREES', this.userControl.DND_ALVO_ID_TREES || []);
        const self = this;
        /**
         * @type {Record<string, any>}
         */
        const opt = {
            core: {
                data: await this.getDados(),
                animation: 150,
                multiple: !!(this.userControl.PERMITE_SELECAO && this.userControl.UTILIZA_CHECKBOX),
                check_callback:
                    /**
                     * @this {any}
                     * @param {any} operation
                     * @param {any} node
                     * @param {any} target
                     * @param {any} node_position
                     * @param {any} more
                     */
                    function (operation, node, target, node_position, more) {
                        if (self.userControl.UTILIZA_DND) {
                            if (operation === 'move_node') {
                                const alvosValidos = more.origin.element.data('DND_ALVO_ID_TREES');
                                if (more?.dnd && alvosValidos?.length) {
                                    return !target.state?.disabled && alvosValidos.includes(this.element.attr('id'));
                                }
                            }
                            return true;
                        }
                        return false;
                    },
            },
            plugins: this.getPlugins(),
            types: (this.userControl.TIPOS || []).reduce(
                /**
                 * @param {Record<string, any>} tipos
                 * @param {any} tipo
                 */
                (tipos, tipo) => {
                    tipos[tipo.id] = {
                        icon: tipo.icone,
                        valid_children: tipo.filhosValidos || [],
                        max_children: tipo.filhosValidos?.length ? -1 : 0,
                        max_depth: tipo.filhosValidos?.length || tipo.id === '#' ? -1 : 0,
                    };
                    return tipos;
                },
                {}
            ),
        };
        if (this.userControl.PERMITE_SELECAO && this.userControl.UTILIZA_CHECKBOX) {
            opt.checkbox = {
                visible: true,
                three_state: this.userControl.CHECKBOX_UTILIZA_CASCATA,
                whole_node: true,
                keep_selected_style: false,
                cascade: this.userControl.CHECKBOX_UTILIZA_CASCATA ? 'up+down+undetermined' : '',
                tie_selection: true,
                cascade_to_disabled: false,
                cascade_to_hidden: false,
            };
        }
        if (this.userControl.UTILIZA_DND) {
            opt.dnd = {
                copy: false,
                is_draggable:
                    /**
                     * @param {any} nodes
                     * @param {any} event
                     */
                    (nodes, event) => {
                        const ret = (nodes || []).every(
                            /**
                             * @param {any} node
                             */
                            (node) =>
                                !node.state?.disabled && (!this.userControl.DND_ORIGEM_TIPO_ITENS || this.userControl.DND_ORIGEM_TIPO_ITENS.some((type) => type.id === node.type))
                        );
                        GOVBR.logs.debug('Drag: ', nodes, ' - ', ret);
                        return ret;
                    },
                check_while_dragging: true,
                always_copy: false,
                inside_pos: 0,
                drag_selection: false,
                touch: false,
                large_drop_target: true,
                large_drag_target: true,
                use_html: true,
                blank_space_drop: true,
            };
        }
        if (this.userControl.UTILIZA_PESQUISA) {
            opt.search = {
                ajax: false,
                fuzzy: false,
                case_sensitive: false,
                show_only_matches: true,
                show_only_matches_children: true,
                close_opened_onclear: true,
                search_leaves_only: false,
                /**
                 * @param {any} texto
                 * @param {any} node
                 */
                search_callback: (texto, node) => {
                    GOVBRPlataformaJS.logs.debug('Search: ', texto, node);
                    const textoNode = (node.li_attr['data-texto'] || node.text || '')
                        .toString()
                        .toLowerCase()
                        .normalize('NFD')
                        .replace(/[\u0300-\u036f]/g, '');
                    texto = (texto || '')
                        .toString()
                        .toLowerCase()
                        .normalize('NFD')
                        .replace(/[\u0300-\u036f]/g, '');
                    return textoNode.includes(texto);
                },
            };
        }
        GOVBRPlataformaJS.logs.debug('Opt: ', opt);
        this.instance = $(this.tree).jstree(opt).jstree(true);
        $(this.tree).on('ready.jstree', () => {
            this.tree.querySelectorAll('.govbr-tree-view-conteudo-hint').forEach((node) => {
                this._suggest.aplicaHint(node, node.getAttribute('data-hint'));
            });
            $(this.tree).on(
                'changed.jstree',
                /**
                 * @param  {...any} args
                 */
                (...args) => {
                    GOVBR.logs.debug('Changed: ', args);
                    this.salvaTree();
                }
            );
            $(this.tree).on(
                'after_close.jstree after_open.jstree create_node.jstree rename_node.jstree delete_node.jstree copy_node.jstree move_node.jstree',
                /**
                 * @param {any} e
                 * @param {any} data
                 */
                (e, data) => {
                    GOVBR.logs.debug('Change Node: ', e.type, this, e, data);
                    this.salvaTree();
                }
            );
            this.salvaTree();
        });
    }

    salvaTree() {
        this.userControl.SELECIONADOS = [];
        const fnTrataItem =
            /**
             * @param {import('./GOVBRTreeViewUserControl.mjs').GOVBRTreeViewUserControlItens[]} accum
             * @param {any} item
             * @returns {import('./GOVBRTreeViewUserControl.mjs').GOVBRTreeViewUserControlItens[]}
             */
            (accum, item) => {
                /**
                 * @type {import('./GOVBRTreeViewUserControl.mjs').GOVBRTreeViewUserControlItens}
                 */
                const ret = {
                    id: item.id,
                    icone: item.li_attr['data-icone'] || '',
                    texto: item.li_attr['data-texto'] || '',
                    hint: item.li_attr['data-hint'] || '',
                    aberto: item.state.opened,
                    desativado: item.state.disabled,
                    selecionado: item.state.selected,
                    tipo: item.type,
                };
                if (ret.selecionado) {
                    this.userControl.SELECIONADOS.push(JSON.parse(JSON.stringify(ret)));
                }
                if (item.children) {
                    ret.filhos = item.children.reduce(fnTrataItem, []);
                }
                accum.push(ret);
                return accum;
            };
        this.userControl.ITENS = (this.instance.get_json() || []).reduce(fnTrataItem, []);
        GOVBR.logs.debug('Salvou: ', this.userControl.ITENS, this.userControl.SELECIONADOS);
    }

    async getDados() {
        /**
         * @param {any[]} accum
         * @param {import('./GOVBRTreeViewUserControl.mjs').GOVBRTreeViewUserControlItens} item
         */
        const fnTrataItem = (accum, item) => {
            const tipo = (this.userControl.TIPOS || []).find((tipo) => tipo.id === item.tipo);
            if (tipo) {
                /**
                 * @type {any}
                 */
                const ret = {
                    id: item.id,
                    text: `<span class="govbr-tree-view-icone-item ${item.icone || tipo.icone || 'icone-default'}"></span><span class="govbr-tree-view-conteudo-item">${item.texto}</span>${item.hint ? `<span class="govbr-tree-view-conteudo-hint" data-hint="${GOVBR.ComponentUtils.escapaValorAtributoHTML(item.hint)}"><i aria-hidden class="govbr-tree-view-conteudo-hint-icone fa-solid fa-info-circle"></i></span>` : ''}`,
                    icon: '',
                    type: item.tipo,
                    state: {
                        opened: !!item.aberto,
                        disabled: !!item.desativado,
                        selected: !!item.selecionado,
                    },
                    li_attr: {
                        'data-icone': item.icone,
                        'data-texto': item.texto,
                        'data-hint': item.hint,
                    },
                    children: null,
                };
                if (item.filhos) {
                    ret.children = item.filhos.reduce(fnTrataItem, []);
                }
                accum.push(ret);
            }
            return accum;
        };
        return (this.userControl.ITENS || []).reduce(fnTrataItem, []);
    }

    getPlugins() {
        const plugins = ['types', 'wholerow'];
        if (this.userControl.PERMITE_SELECAO && this.userControl.UTILIZA_CHECKBOX) {
            plugins.push('checkbox');
        }
        if (this.userControl.UTILIZA_DND) {
            plugins.push('dnd');
        }
        if (this.userControl.UTILIZA_PESQUISA) {
            plugins.push('search');
        }
        return plugins;
    }
}

// Caso esteja no browser, disponibiliza o widget no objeto de window.
if (typeof window !== 'undefined') {
    // @ts-ignore
    window['GOVBRTreeViewUC'] = GOVBRTreeViewUC;
}
export { GOVBRTreeViewUC };
