window.$ = window.$ || function(selector) {
    const elements = document.querySelectorAll(selector);

    return {
        elements: elements,
        get: function() {
            return elements[0]
        },

        html: function(content) {
            if (content === undefined) {
                return elements[0]?.innerHTML;
            } else {
                elements.forEach(el => el.innerHTML = content);
                return this;
            }
        },

        append: function(content) {
            if (content === undefined) {
                return elements[0]?.innerHTML;
            } else {
                elements.forEach(el => el.insertAdjacentHTML('beforeend',`${content}`));
                return this;
            }
        },

        text: function(content) {
            if (content === undefined) {
                return elements[0]?.textContent;
            } else {
                elements.forEach(el => el.textContent = content);
                return this;
            }
        },

        on: function(event, callback) {
            elements.forEach(el => el.addEventListener(event, callback));
            return this;
        },

        css: function(prop, value) {
            elements.forEach(el => el.style[prop] = value);
            return this;
        },

        val: function(value) {
            if (value === undefined) {
                return elements[0]?.value;
            } else {
                elements.forEach(el => el.value = value);
                return this;
            }
        },

        attr: function(name, value) {
            if (value === undefined) {
                return elements[0]?.getAttribute(name);
            } else {
                elements.forEach(el => el.setAttribute(name, value));
                return this;
            }
        },



        data: function(name, value) {
            if (name === undefined) {
                return elements[0]?.dataset; // retorna todos os data-*
            }
            if (value === undefined) {
                return elements[0]?.dataset[name]; // retorna um específico
            }
            elements.forEach(el => el.dataset[name] = value); // define valor
            return this;
        }
    };
};

const toBoolean = (stringValue) => {
    switch(stringValue?.toLowerCase()?.trim()){
        case "true": 
            return true;
        case "yes": 
            return true
        case "1": 
          return true;

        case "false": 
            return false
        case "no": 
            return false
        case "0": 
            return false
        case null: 
            return false
        case undefined:
          return false;

        default: 
          return JSON.parse(stringValue);
    }
}

$.await = function(selector) {
    return new Promise((resolve) => {
        // Verifica imediatamente se o elemento já existe
        const elements = document.querySelectorAll(selector);
        if (elements.length > 0) {
            resolve(buildWrapper(elements));
            return;
        }

        // Configura o MutationObserver
        const observer = new MutationObserver((mutations, obs) => {
            const elems = document.querySelectorAll(selector);
            if (elems.length > 0) {
                obs.disconnect(); // Para de observar
                resolve(buildWrapper(elems));
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    });

    function buildWrapper(elements) {
        return {
            get: () => elements,
            val: function(value) {
                if (value === undefined) return elements[0]?.value;
                elements.forEach(el => el.value = value);
                return this;
            },
            append: function(content) {
                if (content === undefined) return elements[0]?.innerHTML;
                elements.forEach(el => el.insertAdjacentHTML('beforeend', `${content}`));
                return this;
            },
            data: function(key, value) {
                if (key === undefined) return elements[0]?.dataset;
                if (value === undefined) return elements[0]?.dataset[key];
                elements.forEach(el => el.dataset[key] = value);
                return this;
            },
            on: function(event, handler) {
                elements.forEach(el => el.addEventListener(event, handler));
                return this;
            },
            off: function(event, handler) {
                elements.forEach(el => el.removeEventListener(event, handler));
                return this;
            }
        };
    }
};

$.storage = function(selector) {
    return {
        get: function() {
            let value = localStorage.getItem(selector.toString());
            if (value === null) return null;

            try {
                return JSON.parse(value); // tenta transformar em objeto/array/número/etc
            } catch {
                return value; // se não for JSON válido, retorna string pura
            }
        },

        set: function(value) {
            if (typeof value === "object") {
                localStorage.setItem(selector.toString(), JSON.stringify(value));
            } else {
                localStorage.setItem(selector.toString(), value);
            }
            return this;
        },

        remove: function() {
            localStorage.removeItem(selector.toString());
            return this;
        },

        clear: function() {
            localStorage.clear();
            return this;
        }
    };
};

$.AjaxRequest = function(options) {
    const method = (options.method || "POST").toUpperCase();
    let url = options.url;
    let fetchOptions = { method };

    // Monta os dados
    if (options.data) {
        if (method === "GET") {
            const params = new URLSearchParams(options.data).toString();
            url += "?" + params;
        } else {
            // Para POST/PUT/etc
            fetchOptions.body = new FormData();
            for (const key in options.data) {
                fetchOptions.body.append(key, options.data[key]);
            }
        }
    }

    // Executa a requisição
    fetch(url, fetchOptions)
        .then(res => {
            if (!res.ok) throw new Error(res.statusText);
            // Tenta interpretar como JSON, se falhar retorna texto
            return res.text().then(text => {
                try {
                    return JSON.parse(text);
                } catch {
                    return text;
                }
            });
        })
        .then(data => {
            if (options.success) options.success(data);
        })
        .catch(err => {
            if (options.error) options.error(err);
        });
};