var UI = {

    apiMethodName: function (args) {
        let methodName = args.method.toLowerCase() + args.db.capitalize();
        if (args.method == 'GET') methodName += "s";
        console.log('args');
        console.log(args);
        console.log('methodName:' + methodName);
        return methodName;
    },

    apiGet: function (args) {
        if (!args.db) { console.log('apiGet requires db parameter'); }
        console.log('apiGet args');
        console.log(args);
        let methodName = this.apiMethodName(args);
        //window.args = args;
        window[methodName](args.item)
            .then(function (data) {
                console.log('apiCall success');
                //let result = JSON.stringify(data, null, 2);
                console.log('args');
                console.log(args);
                let apiCallback = [
                    {
                        "rl:apiGetCallback": {
                            "db": args.db,
                            "template": args.template,
                            "data": data
                        }
                    }
                ];
                js.callback({ do: apiCallback, to: 'data db ' + args.db, value: data });
            })
            .catch(function (err) {
                console.log('apiCall error');
                console.log(err);
            });
    },

    apiPost: function (args) {
        if (!args.db) { console.log('apiPost requires db parameter'); }
        let methodName = this.apiMethodName(args);

        let item = js.replaceProperties('{formDataToJson:.form' + args.db + '}');
        console.log(item);
        //window.args = args;
        window[methodName](item)
            .then(function (data) {
                console.log('apiCall success');
                let result = JSON.stringify(data, null, 2);
                let apiCallback = [
                    {
                        "rl:apiPostCallback": {
                            "db": args.db,
                            "template": args.template,
                            "data": data
                        }
                    }
                ];
                js.callback({ do: apiCallback });
            })
            .catch(function (err) {
                console.log('apiCall error');
                console.log(err);
                let apiCallback = [
                    {
                        "rl:apiPostCallback": {
                            "db": args.db,
                            "template": args.template,
                            "data": err
                        }
                    }
                ];
                js.callback({ do: apiCallback });
            });
    },


    apiCall: function (args) {
        let method = args.method || "GET";
        let db = args.db || "";
        let item = args.item || {};
        let serverUrl = args.serverUrl || "";
        let apiSuccess = args.success;
        let apiError = args.error;
        window.args = args;
        //RESLEVIS_API_BASE = serverUrl;

        let methodName = args.method.toLowerCase() + args.db.capitalize();
        if (method == 'GET') methodName += "s";
        console.log('methodName:' + methodName);
        //let result = window[methodName](item);
        window[methodName](item)
            .then(function (data) {
                console.log('apiCall success');
                let result = JSON.stringify(data, null, 2);
                console.log(data);
                console.log({ do: apiSuccess, to: 'data db ' + db, value: data });
                let apiCallback = [
                    {
                        "rl:apiCallback": {
                            "db": window.args.db,
                            "template": window.args.template,
                            "data": data
                        }
                    }
                ];
                js.do(apiSuccess);
                //js.callback({ do: apiSuccess, to: 'data db ' + db, value: data });
            })
            .catch(function (err) {
                console.log('apiCall error');
                console.log(err);
                let apiCallback = [
                    {
                        "rl:apiCallback": {
                            "db": window.args.db,
                            "template": window.args.template,
                            "data": []
                        }
                    }
                ];
                js.do(apiCallback);
                //js.callback({ do: apiSuccess, to: 'data db ' + db, value: data });
            });

    },

    capitalize: function (val) {
        return String(val).charAt(0).toUpperCase() + String(val).slice(1);
    },

    getVisibleColumns: function (db) {
        if (window.table && window.table[db]) {
            const visibility = {};
            window.table[db].table.getAllLeafColumns().forEach(column => {
                visibility[column.id] = column.getIsVisible();
            });
            return visibility;
        }
    },

    setVisibleColumns: function (db, columns) {
        if (window.table && window.table[db]) {
            const table = window.table[db].table;
            const visibility = {};
            const pinning = { left: [], right: [] };

            for (const [id, val] of Object.entries(columns)) {
                if (val === 'left' || val === 'right') {
                    visibility[id] = true;
                    pinning[val].push(id);
                } else {
                    visibility[id] = !!val;
                }
            }

            table.setColumnVisibility(visibility);
            table.setColumnPinning(pinning);
            window.table[db].render();
        }
    },

    getToken: function (args) {
        if (args.options.body && typeof args.options.body !== 'string') args.options.body = JSON.stringify(args.options.body);
        fetch(args.url, args.options).then(response => response.json()).then(data => {
            //console.log('getToken success');
            //console.log(data);
            js.json.data.user.token = data.access_token;
            js.callback({ do: args.success });
        }).catch((err) => {
            //console.log('getToken error');
            //console.log(err);
            js.json.data.user.token = data.access_token;
            js.callback({ do: args.error });
        })
    },
    init: function () {
    },
    // Function to generate a form as a JSON structure from a JSON schema
    schemaToForm: function (params) {
        /* alert(JSON.stringify(params)); */
        if (!params.schema || !params.schema.properties) {
            return {
                html: [
                    {
                        tag: 'p',
                        text: 'schemaToForm Error: Invalid JSON schema provided.'
                    }
                ]
            };
        }

        const formElements = [];

        // Iterate through schema properties
        for (const [key, prop] of Object.entries(params.schema.properties)) {
            const label = prop.description || key;
            const required = params.schema.required && params.schema.required.includes(key) ? 'required' : '';
            const inputId = `input-${key}`; // Unique ID for accessibility
            // && jsonApp && jsonApp.json.data.settings && 
            const hiddenId = ((key == 'id' || key == 'status') && !jsonApp.json.data.settings.debug) ? ' hidden' : '';

            // Create fieldset for each field
            const fieldsetChildren = [
                {
                    "tag": "label",
                    "attr": {
                        "class": "label text-primary " + hiddenId,
                        "data-value": params.db + "/" + key,
                        "for": key
                    },
                    text: label
                }
            ];

            console.log(fieldsetChildren);

            // Handle different input types
            let inputElement;
            switch (prop.type) {

                case 'string':

                    if (prop.format == 'dbid') {

                        inputElement = {
                            tag: "select",
                            attr: {
                                "data-value": params.db + "/" + key,
                                "name": key,
                                "type": 'text',
                                "value": (params.fields && params.fields[key]) ? params.fields[key] : false,
                                "placeholder": prop.description || ' ',
                                "class": 'field select w-full select-primary' + hiddenId,
                                ...(required && { required: '' })
                            }
                        };
                        inputElement.html = [];
                        let db = (js.json.data.db) ? js.json.data.db : {};
                        if (db[key]) {
                            for (let item of db[key]) {
                                let id = item.id;
                                let name = item.name || '';
                                let attr = { "value": id, "class": "option", "data-value": params.db + "/" + key + "/" + id };
                                if (id == params.fields[key]) attr.selected = true;
                                inputElement.html.push(
                                    {
                                        "tag": "option",
                                        "attr": attr,
                                        "text": name
                                    }
                                )
                            }
                        } else {
                            //js.log('Can\'t load local db: ' + key, 'red');
                            console.log('%c' + 'Can\'t load local db ' + key, 'color: red');
                        }

                    } else if (prop.format == 'date-time') {
                        // https://unpkg.com/flatpickr@2.0.2/index_.html
                        inputElement = {
                            "tag": "input",
                            "attr": {
                                //"id": inputId,
                                "data-value": params.db + "/" + key,
                                "name": key,
                                "type": "number", // datetime-local
                                "value": (params.fields && params.fields[key]) ? new Date(Number(params.fields[key])) : false,
                                "placeholder": new Date().toLocaleDateString("it-IT", { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit" }) || ' ',
                                "data-enable-time": true,
                                "data-enable-seconds": true,
                                "data-time_24hr": true,
                                "data-date-format": "Y-m-d H:i:S",
                                class: "field input datepicker w-full input-primary" + hiddenId,
                                ...(required && { required: '' })
                            },
                            "on": {
                                "in": [

                                    {
                                        "js": "flatpickr('.datepicker', {enableSeconds: true, time_24hr: true})"
                                    }
                                ]
                            }
                        };
                        /* flatpickr("#date-time-flatpickr-demo", {
                            defaultDate: new Date(),
                            enableTime: true,
                        }) */

                    } else if (prop.enum) { // enum ()
                        inputElement = {
                            tag: "select",
                            attr: {
                                //"id": inputId,
                                "data-value": params.db + "/" + key,
                                "name": key,
                                "type": 'text',
                                "value": (params.fields && params.fields[key]) ? params.fields[key] : false,
                                "placeholder": prop.description || ' ',
                                "class": 'field select w-full select-primary' + hiddenId,
                                ...(required && { required: '' })
                            }
                        };

                        inputElement.html = [];
                        for (let item of prop.enum) {
                            let attr = { "value": item, "class": "option", "data-value": params.db + "/" + key + "/" + item };
                            if (params.fields && params.fields[key] && params.fields[key] == item) attr.selected = true;
                            inputElement.html.push(
                                {
                                    "tag": "option",
                                    "attr": attr,
                                    "text": String(item)
                                }
                            )
                        }

                    } else { // string

                        inputElement = {
                            tag: 'input',
                            attr: {
                                //id: inputId,
                                "data-value": params.db + "/" + key,
                                "name": key,
                                type: 'text',
                                value: (params.fields && params.fields[key]) ? params.fields[key] : false,
                                placeholder: prop.description || ' ',
                                class: 'field input w-full input-primary' + hiddenId,
                                ...(required && { required: '' })
                            }
                        };
                    }
                    break;

                case 'number':
                case 'integer':

                    inputElement = {
                        tag: 'input',
                        attr: {
                            //id: inputId,
                            "data-value": params.db + "/" + key,
                            "name": key,
                            type: 'number',
                            value: (params.fields && params.fields[key]) ? params.fields[key] : false,
                            placeholder: prop.description || ' ',
                            class: 'field input w-full input-primary' + hiddenId,
                            ...(required && { required: '' })
                        }
                    };
                    break;

                case 'boolean':
                    inputElement = {
                        tag: 'input',
                        attr: {
                            //id: inputId,
                            "data-value": params.db + "/" + key,
                            "name": key,
                            type: 'checkbox',
                            class: 'field toggle toggle-info' + hiddenId,
                            ...(required && { required: '' })
                        }
                    };
                    if (params.fields[key]) inputElement.attr.checked = true;
                    break;

                case 'array':
                    inputElement = {
                        tag: 'textarea',
                        attr: {
                            //id: inputId,
                            "data-value": params.db + "/" + key,
                            "name": key,
                            value: (params.fields && params.fields[key]) ? params.fields[key] : false,
                            placeholder: prop.description || 'Enter values separated by commas',
                            class: 'field textarea w-full input-primary' + hiddenId,
                            ...(required && { required: '' })
                        }
                    };
                    break;

                case 'object':
                    inputElement = {
                        tag: 'textarea',
                        attr: {
                            //id: inputId,
                            "data-value": params.db + "/" + key,
                            "name": key,
                            placeholder: prop.description || 'Enter JSON object',
                            class: 'field textarea w-full input-primary' + hiddenId,
                            ...(required && { required: '' })
                        }
                    };
                    break;

                default:
                    inputElement = {
                        tag: 'input',
                        attr: {
                            //id: inputId,
                            "data-value": params.db + "/" + key,
                            "name": key,
                            type: 'text',
                            value: (params.fields && params.fields[key]) ? params.fields[key] : false,
                            placeholder: prop.description || ' ',
                            class: 'field input w-full input-primary' + hiddenId,
                            ...(required && { required: '' })
                        }
                    };
            }


            // Add input element to fieldset
            fieldsetChildren.push(inputElement);

            // Add fieldset to form elements
            formElements.push({
                tag: 'fieldset',
                attr: {
                    "class": "fieldset text-center",
                    "data-value": params.db
                },
                html: fieldsetChildren
            });

            /* console.log('fviewRow');
            console.log(inputElement); */
        }

        /* // Add buttons
        formElements.push({
            tag: 'div',
            attr: { 
                "class": "w-full mt-6 text-center px-[50px] flex flex-wrap items-center justify-between gap-2 "
            },
            html: [
              {
                "for": {
                  "var": "button",
                  "of": params.buttons,
                  "do": [
                    {
                        "tag": 'button',
                        "attr": {
                            "type": "{var button type}",
                            "class": "btn {var button class}"
                        },
                        "text": "{var button title}",
                        "on": {
                            "mousedown": "{var button actions}"
                        }
                    }
                  ]
                }
              }
            ]
        }); */

        // Return the full form structure
        return {
            html: formElements
        };
    },
    createForm: function (params) {
        let appForm = UI.schemaToForm(params);
        appForm.selector = params.selector;
        jsonApp.do(appForm);
    },
    columnsFromApi: function (db) {
        let dbFields = js.json.data.api.components.schemas[params.db].properties;
        let columns = [];
        for (let key in dbFields) {
            columns.push({
                "header": key,
                "accessorKey": key
            });
        }
        return columns;
    },
    createTable: function (params) {

        /* console.log('createTable');
        console.log(params); */


        const tableData = jsonApp.json.data.db[params.db].map((data) => {
            return {
                ...data,
                //dateTime: new Date(Date.now()) // - 1000 * 60 * 60 * Math.floor(Math.random() * 24 * 100)),
            }
        })

        const getTableData = () => {
            return [...tableData]
            //return [...tableData].sort(() => 0.5 - Math.random())
        }

        const flexRender = (comp, props) => {
            if (typeof comp === "function") {
                return comp(props)
            }
            return comp
        }


        let data = getTableData()
        let version = 0
        let columns = JSON.parse(JSON.stringify(js.json.data.preferences.tables[params.db].columns));

        /*         
        let columns = this.columnsFromApi(params.db);
        console.log('columns', JSON.stringify(columns));
        let visibility = js.json.data.preferences.tables[params.db].columns;
        console.log('visibility', JSON.stringify(visibility));
         */

        const state = {
            columnPinning: { left: [], right: [] },
            pagination: {
                pageSize: 10,
                pageIndex: 0,
            },
            globalFilter: "",
            columnFilters: [],
            columnVisibility: {},
            rowSelection: {},
        }
        const table = TableCore.createTable({
            state,
            data,
            columns,
            getCoreRowModel: TableCore.getCoreRowModel(),
            getPaginationRowModel:
                TableCore.getPaginationRowModel(),
            getFilteredRowModel: TableCore.getFilteredRowModel(),
            globalFilterFn: "auto",
            onStateChange: (updater) => {
                const newState =
                    typeof updater === "function"
                        ? updater(state)
                        : updater
                Object.assign(state, newState)
            },
        });


        if (!window.table) window.table = {};

        window.table[params.db] = Alpine.reactive({
            dbId: params.db,
            version,
            columns,
            pageSizes: [5, 10, 20, 50],
            flexRender,
            search: "",
            get table() {
                this.version
                return table
            },
            get visibleRows() {
                this.version
                return this.table.getRowModel().rows
            },
            get selectedCount() {
                return this.table.getSelectedRowModel().rows.length
            },
            get totalCount() {
                return this.table.getPaginationRowModel().rows
                    .length
            },
            get isIndeterminateAllRowsSelected() {
                this.version
                return (
                    this.table.getIsSomePageRowsSelected() &&
                    !this.table.getIsAllPageRowsSelected()
                )
            },
            get allLeafColumns() {
                this.version
                return this.table.getAllLeafColumns()
            },
            get pageSize() {
                this.version
                return this.table.getState().pagination.pageSize
            },
            get pageIndex() {
                this.version
                return this.table.getState().pagination.pageIndex
            },
            get rowCount() {
                this.version
                return data.length
            },
            get start() {
                this.version
                return this.rowCount === 0
                    ? 0
                    : this.pageIndex * this.pageSize + 1
            },
            get end() {
                this.version
                return Math.min(
                    this.start + this.pageSize - 1,
                    this.rowCount
                )
            },

            /* updateInterval(duration) {
                console.log('updateInterval:'+this.dbId);
                clearInterval(this.interval);
                this.interval = setInterval(function (event) {console.log(event); this.dbId}, duration)
            }, */

            updateData() {
                //console.log('updateData:'+this.dbId);
                let newData = jsonApp.json.data.db[this.dbId];

                this.table.setOptions(prev => ({
                    ...prev,
                    data: newData
                }))


                this.render()
            },

            setPageIndex(n) {
                this.table.setPageIndex(n)
                this.render()
            },

            nextPage() {
                this.version
                if (this.table.getCanNextPage()) {
                    this.table.setPageIndex(this.pageIndex + 1)
                    this.render()
                }
            },

            prevPage() {
                this.version
                if (this.table.getCanPreviousPage()) {
                    this.table.setPageIndex(this.pageIndex - 1)
                    this.render()
                }
            },

            changePageSize(newSize) {
                this.table.setPageSize(Number(newSize))
                this.render()
            },
            updateSearch() {
                table.setState({
                    ...table.getState(),
                    globalFilter: this.search,
                })
                this.render()
            },
            getVisibleCells(row) {
                this.version
                return row.getVisibleCells()
            },
            isColumnVisible(column) {
                this.version
                return column.getIsVisible()
            },
            toggleColumn(column) {
                column.toggleVisibility();
                /* let preferences = JSON.parse(localStorage.getItem("preferences"));
                preferences.tables[this.dbId].columns = this.getVisibleColumns(this.dbId);
                localStorage.setItem("preferences", JSON.stringify(preferences)); */
                this.render()
            },
            toggleSelectedRow(row) {
                row.toggleSelected()
                this.render()
            },
            isRowSelected(row) {
                this.version
                return row.getIsSelected()
            },
            toggleAllRowsSelected() {
                this.table.toggleAllPageRowsSelected()
                this.render()
            },
            viewRow(row) {
                let fields = Alpine.raw(row.original);
                //let id = `${row.original.id}`;
                js.part({ 'do': 'rl:openPost', arguments: { db: params.db, fields: fields, method: 'UPDATE' } });

            },
            deleteRow(row) {
                let fields = Alpine.raw(row.original);
                //let id = `${row.original.id}`;
                js.part({ 'do': 'removePost', arguments: { db: params.db, fields: fields } });
            },
            clearFilters() {
                this.search = ""
                this.updateSearch()
            },
            render() {
                this.version++
            }

        });

        return window.table[params.db]
    },

    loadTemplate: function (params) {
        console.log('loadTemplate', params);
        // add to html the parameters {url, to}
        var xmlhttp = new XMLHttpRequest();

        xmlhttp.onreadystatechange = function () {
            console.log('readyState', this.readyState, 'status', this.status);
            //console.log(this);
            if (this.readyState == 4 && this.status == 200) {
                //console.log(this.responseText);
            } else if (this.readyState == 4 && this.status == 401) {
                // unauthenticated
                window.location.reload();
            } else {
                if (this.status !== 0)
                    console.log('Error loading ' + params.url);
            }
        };

        xmlhttp.open("GET", params.url, false);
        xmlhttp.send();/* .then(function (data) {
            console.log('loadTemplate success');
            console.log(data);
            //js.callback({ do: params.success });
        }).catch((err) => {
            console.log('loadTemplate error');
            console.log(err);
            window.location.reload();
            //js.callback({ do: params.error });
        }); */

        if (xmlhttp.responseText) {
            var responseText = xmlhttp.responseText;
            if (params.arguments) {
                responseText = js.replacePropertyWithPrefix(responseText, 'arguments', params.arguments);
            }
            if (params.to)
                js.element({ root: js.json, path: params.to, value: responseText });
            if (params.selector) {
                if (params.prepend)
                    document.querySelector(params.selector).innerHTML = responseText + document.querySelector(params.selector).innerHTML;
                else if (params.empty)
                    document.querySelector(params.selector).innerHTML = responseText;
                else
                    document.querySelector(params.selector).innerHTML += responseText;
            }
        } else console.log('Error loading ' + params.url);
    }
}

Object.defineProperty(String.prototype, 'capitalize', {
    value: function () {
        return this.charAt(0).toUpperCase() + this.slice(1);
    },
    enumerable: false
});



/*
var getToken = function (args) {    
    

    //UI.token(args);


    if (args.options.body && typeof args.options.body !== 'string') args.options.body = JSON.stringify(args.options.body); fetch(args.url, args.options).then(response => response.json()).then(data => {console.log('fetchJson success'); console.log(data); js.callback({do:args.success});}).catch((err) => {console.log('fetchJson error');console.log(err);js.callback({do:args.error});})  

}
*/
/*
let args = {
    "url": "https://192.168.1.3:10002/realms/API.Server.local/protocol/openid-connect/token",
    "options": {
        "method": "POST",
        "headers": {
            "Content-Type": "application/x-www-form-urlencoded"
        },
        "body": "grant_type=client_credentials&client_id=Fastapi&client_secret=wojuoB7Z5xhlPFrF2lIxJSSdVHCApEgC"
    }
};
*/
//UI.getToken(args);

//UI.loadTemplate({selector: 'content', url:'./assets/html/tracks.html'});





// components-interactions-form-validations

/* empty css   */; (function () {
    const t = document.createElement("link").relList
    if (t && t.supports && t.supports("modulepreload")) return
    for (const e of document.querySelectorAll('link[rel="modulepreload"]')) i(e)
    new MutationObserver((e) => {
        for (const r of e)
            if (r.type === "childList")
                for (const o of r.addedNodes)
                    o.tagName === "LINK" && o.rel === "modulepreload" && i(o)
    }).observe(document, { childList: !0, subtree: !0 })
    function s(e) {
        const r = {}
        return (
            e.integrity && (r.integrity = e.integrity),
            e.referrerPolicy && (r.referrerPolicy = e.referrerPolicy),
            e.crossOrigin === "use-credentials"
                ? (r.credentials = "include")
                : e.crossOrigin === "anonymous"
                    ? (r.credentials = "omit")
                    : (r.credentials = "same-origin"),
            r
        )
    }
    function i(e) {
        if (e.ep) return
        e.ep = !0
        const r = s(e)
        fetch(e.href, r)
    }
})()
