// Sort button
class BrickGridSortButton {
    constructor(button, grid) {
        this.button = button;
        this.grid = grid;
        this.data = this.button.dataset;

        // Setup
        button.addEventListener("click", ((grid, button) => (e) => {
            grid.sort(button);
        })(grid, this));
    }

    // Active
    active() {
        this.button.classList.remove("btn-outline-primary");
        this.button.classList.add("btn-primary");
    }

    // Inactive
    inactive() {
        delete this.button.dataset.sortOrder;
        this.button.classList.remove("btn-primary");
        this.button.classList.add("btn-outline-primary");
    }

    // Toggle sorting
    toggle(order) {
        // Cleanup
        delete this.button.dataset.sortOrder;

        let icon = this.button.querySelector("i.ri");
        if (icon) {
            this.button.removeChild(icon);
        }

        // Set order
        if (order) {
            this.active();

            this.button.dataset.sortOrder = order;

            icon = document.createElement("i");
            icon.classList.add("ri", "ms-1", `ri-sort-${order}`);

            this.button.append(icon);
        }
    }
}

// Grid class
class BrickGrid {
    constructor(grid) {
        this.id = grid.id;

        // Grid elements (built based on the initial id)
        this.html_grid = document.getElementById(this.id);
        this.html_sort = document.getElementById(`${this.id}-sort`);
        this.html_search = document.getElementById(`${this.id}-search`);
        this.html_filter = document.getElementById(`${this.id}-filter`);
        this.html_theme = document.getElementById(`${this.id}-theme`);

        // Sort buttons
        this.html_sort_buttons = {};
        if (this.html_sort) {
            this.html_sort.querySelectorAll("button[data-sort-attribute]").forEach(button => {
                this.html_sort_buttons[button.id] = new BrickGridSortButton(button, this);
            });
        }

        // Clear button
        this.html_clear = document.querySelector("button[data-sort-clear]")
        if (this.html_clear) {
            this.html_clear.addEventListener("click", ((grid) => (e) => {
                grid.clear(e.currentTarget)
            })(this))
        }

        // Filter setup
        if (this.html_search) {
            this.html_search.addEventListener("keyup", ((grid) => () => {
                grid.filter();
            })(this));
        }

        if (this.html_filter) {
            this.html_filter.addEventListener("change", ((grid) => () => {
                grid.filter();
            })(this));
        }

        if (this.html_theme) {
            this.html_theme.addEventListener("change", ((grid) => () => {
                grid.filter();
            })(this));
        }

        // Cookie setup
        const cookies = document.cookie.split(";").reduce((acc, cookieString) => {
            const [key, value] = cookieString.split("=").map(s => s.trim().replace(/^"|"$/g, ""));
            if (key && value) {
                acc[key] = decodeURIComponent(value);
            }
            return acc;
        }, {});

        // Initial sort
        if ("sort-id" in cookies && cookies["sort-id"] in this.html_sort_buttons) {
            const current = this.html_sort_buttons[cookies["sort-id"]];

            if("sort-order" in cookies) {
                current.button.setAttribute("data-sort-order", cookies["sort-order"]);
            }

            this.sort(current, true);
        }
    }

    // Clear
    clear(current) {
        // Cleanup all
        for (const [id, button] of Object.entries(this.html_sort_buttons)) {
            button.toggle();
            button.inactive();
        }

        // Clear cookies
        document.cookie = `sort-id=""; Path=/; SameSite=strict`;
        document.cookie = `sort-order=""; Path=/; SameSite=strict`;

        // Reset sorting
        tinysort(current.dataset.sortTarget, {
            selector: "div",
            attr: "data-index",
            order: "asc",
        });

    }

    // Filter
    filter() {
        var filters = {};

        // Check if there is a search filter
        if (this.html_search && this.html_search.value != "") {
            filters["search"] = this.html_search.value.toLowerCase();
        }

        // Check if there is a set filter
        if (this.html_filter && this.html_filter.value != "") {
            if (this.html_filter.value.startsWith("-")) {
                filters["filter"] = this.html_filter.value.substring(1);
                filters["filter-target"] = "0";
            } else {
                filters["filter"] = this.html_filter.value;
                filters["filter-target"] = "1";
            }
        }

        // Check if there is a theme filter
        if (this.html_theme && this.html_theme.value != "") {
            filters["theme"] = this.html_theme.value;
        }

        // Filter all cards
        if (this.html_grid) {
            const cards = this.html_grid.querySelectorAll("div > div.card");
            cards.forEach(current => {
                // Set filter
                if ("filter" in filters) {
                    if (current.getAttribute("data-" + filters["filter"]) != filters["filter-target"]) {
                        current.parentElement.classList.add("d-none");
                        return;
                    }
                }

                // Theme filter
                if ("theme" in filters) {
                    if (current.getAttribute("data-theme") != filters["theme"]) {
                        current.parentElement.classList.add("d-none");
                        return;
                    }
                }

                // Check all searchable fields for a match
                if ("search" in filters) {
                    for (let attribute of ["data-name", "data-number", "data-parts", "data-theme", "data-year"]) {
                        if (current.getAttribute(attribute).includes(filters["search"])) {
                            current.parentElement.classList.remove("d-none");
                            return;
                        }
                    }

                    // If no match, we need to hide it
                    current.parentElement.classList.add("d-none");
                    return;
                }

                // If we passed all filters, we need to display it
                current.parentElement.classList.remove("d-none");
            })
        }
    }

    // Sort
    sort(current, no_flip=false) {
        const target = current.data.sortTarget;
        const attribute = current.data.sortAttribute;
        const natural = current.data.sortNatural;

        // Cleanup all
        for (const [id, button] of Object.entries(this.html_sort_buttons)) {
            if (button != current) {
                button.toggle();
                button.inactive();
            }
        }

        // Sort
        if (target && attribute) {
            let order = current.data.sortOrder;

            // First ordering
            if (!no_flip) {
                if(!order) {
                    if (current.data.sortDesc) {
                        order = "desc"
                    } else {
                        order = "asc"
                    }
                } else {
                    // Flip the sorting order
                    order = (order == "desc") ? "asc" : "desc";
                }
            }

            // Toggle the ordering
            current.toggle(order);

            // Store cookies
            document.cookie = `sort-id="${encodeURIComponent(current.button.id)}"; Path=/; SameSite=strict`;
            document.cookie = `sort-order="${encodeURIComponent(order)}"; Path=/; SameSite=strict`;

            // Do the sorting
            tinysort(target, {
                selector: "div",
                attr: "data-" + attribute,
                natural: natural == "true",
                order: order,
            });
        }
    }
}

// Helper to setup the grids
const setup_grids = () => document.querySelectorAll('*[data-grid="true"]').forEach(
    el => new BrickGrid(el)
);
