//1- submit the form by ajax
function addUpdate(e, method) {

    e.preventDefault();

    suToggle(0, method);
    var formdata = new FormData($("#" + method + "-form")[0]);
    var redirectUR = ($("#" + method + "-submit").data("args2"));

    // Add method spoofing for update requests (Laravel resource routes require PUT/PATCH)
    if (method === 'update') {
        formdata.append('_method', 'PUT');
    }

    $.ajax({
        type: 'POST',
        url: $("#" + method + "-submit").data("args1"),
        data: formdata,
        processData: false,
        contentType: false,

        success: function (data) {

            $(".text-danger").text('');
            $(".text-success").text('');
            if ($.isEmptyObject(data.error)) {

                // reset all ckeditor
                for (const key in window) {
                    if (window.hasOwnProperty(key) && key.endsWith('_editor')) {
                        window[key].setData('');
                    }
                }


                $("#success").toggle();
                $("#success").html(data.success);
                suToggle(1, method);
                if (data.redirect) {
                    window.location.href = BASE_URL + data.redirect;  // Redirect to the specified URL
                    return;
                }
                if (redirectUR != "No") {
                    window.location.href = BASE_URL + redirectUR;
                    return;
                } else {
                    $("#" + method + "-form").trigger("reset");
                    // If form contains any Chosen dropdowns, reset them too
                    let chosenDropdowns = $("#" + method + "-form").find('select.chosen-select');
                    if (chosenDropdowns.length > 0) {
                        chosenDropdowns.val('').trigger('chosen:updated');
                    }
                }
            } else {
                suToggle(1, method);
                // Collect messages for SweetAlert
                let firstMsg = '';
                let allMsgs = [];
                $.each(data.error, function (index, message) {
                    // Laravel errors are often arrays: ["The client id field is required."]
                    if (Array.isArray(message)) {
                        message = message[0] ?? '';
                    }
                    message = String(message ?? '');
                    // Remove "id" word from field labels (client id -> client)
                    message = message.replace(/\bid\b/gi, '').replace(/\s{2,}/g, ' ').trim();
                    $("#" + method + "-" + index + "Error").text("*" + message);
                    if (!firstMsg && message) firstMsg = message;
                    if (message) allMsgs.push(message);
                });

                // SweetAlert (if available) for visibility
                if (typeof Swal !== 'undefined') {
                    Swal.fire({
                        icon: 'error',
                        title: 'Validation error',
                        html: allMsgs.length ? ('<ul style=\"text-align:left; padding-left:18px;\">' + allMsgs.map(m => '<li>' + m + '</li>').join('') + '</ul>') : firstMsg,
                    });
                }

            }

        }
        ,
        error: function (xhr) {
            suToggle(1, method);
            // Try to extract message from JSON
            let msg = 'Failed to process the request. Please try again.';
            try {
                const r = xhr.responseJSON || JSON.parse(xhr.responseText || '{}');
                if (r && r.message) msg = r.message;
            } catch (e) {}

            if (typeof Swal !== 'undefined') {
                Swal.fire({ icon: 'error', title: 'Error', text: msg });
            } else {
                alert(msg);
            }
        }

    });
}

// Import CSV via AJAX (no page reload)
function importCsvAjax(fileInput, url) {
    try {
        const file = fileInput && fileInput.files ? fileInput.files[0] : null;
        if (!file) return;

        const formdata = new FormData();
        formdata.append('file', file);

        $.ajax({
            type: 'POST',
            url: url,
            data: formdata,
            processData: false,
            contentType: false,
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            },
            success: function (data) {
                // reset input so same file can be selected again
                fileInput.value = '';

                const msg = (data && (data.success || data.message)) ? (data.success || data.message) : 'CSV imported.';
                if (typeof Swal !== 'undefined') {
                    Swal.fire({ icon: 'success', title: 'Imported', text: msg });
                }

                // If DataTable exists, refresh it
                if (typeof table !== 'undefined' && table && typeof table.ajax === 'object' && typeof table.ajax.reload === 'function') {
                    table.ajax.reload(null, false);
                }
            },
            error: function (xhr) {
                fileInput.value = '';
                let msg = 'CSV import failed.';
                try {
                    const r = xhr.responseJSON || JSON.parse(xhr.responseText || '{}');
                    if (r && (r.error || r.message)) msg = r.error || r.message;
                } catch (e) {}

                if (typeof Swal !== 'undefined') {
                    Swal.fire({ icon: 'error', title: 'Import failed', text: msg });
                } else {
                    alert(msg);
                }
            }
        });
    } catch (e) {
        if (typeof Swal !== 'undefined') {
            Swal.fire({ icon: 'error', title: 'Import failed', text: 'Unexpected error.' });
        }
    }
}

//2- Soft delete the record 
function suSoftDelete(id, table) {
    if (confirm('Are you sure?')) {
        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }
        });
        $.ajax({
            type: 'DELETE',
            url: (typeof BASE_URL !== 'undefined' ? BASE_URL : '') + 'admin/' + table + "/" + id,
            success: function (data) {
                // Handle response - controller returns {success: "message"}
                if (data && data.success) {
                    // Apply line-through effect to the row and hide trash icon, show restore icon
                    $('#row_' + id + ' td:not(:last-child)').css('text-decoration', 'line-through');
                    $('#row_' + id + ' td:last-child').css('text-decoration', 'none');
                    $('#trash_' + id).css('display', 'none');
                    $('#restore_' + id).css('display', 'inline-block');
                }
            },
            error: function (xhr, status, error) {
                // Show error alert if the AJAX call itself fails
                alert('Failed to process the request. Please try again.');
            }
        });
    }
}
// 4- Restore the record
function suRestore(id, table) {

    $.ajax({
        type: 'GET',
        url: table + "/restore/" + id,
        success: function (data) {
            $('#row_' + id + ' td:not(:last-child)').css('text-decoration', 'none');
            $('#trash_' + id).css('display', 'inline-block');
            $('#restore_' + id).css('display', 'none');
        }

    });

}


// 5- Show/hide password field using Bootstrap Fill Icons
function doShowPassword(id = 'password', iconElement = null) {
    const input = $('#' + id);

    // Detect and get the actual <i> icon element
    let icon = $(iconElement);
    if (!icon.is('i')) {
        icon = icon.find('i'); // For input-group case where <a> wraps <i>
    }

    const showClass = 'bi-eye-fill';
    const hideClass = 'bi-eye-slash-fill';

    // Toggle logic
    if (input.prop('type') === 'password') {
        input.prop('type', 'text');
        icon.removeClass(showClass).addClass(hideClass);
    } else {
        input.prop('type', 'password');
        icon.removeClass(hideClass).addClass(showClass);
}
}




//6- change submit button text to processing
function suToggle(toggle, method) {

    if (toggle) {
        $("#" + method + "-submit").prop("disabled", false);
        $("#" + method + "-submit").html("<i class=\"ri-save-line\"></i> Save ");

    } else {

        $("#" + method + "-submit").prop("disabled", true);
        $("#" + method + "-submit").text("Processing");

    }

    // Move to the top of the page
    window.scrollTo({top: 0, behavior: "smooth"});
}

//7- 
function doChangePassword(fld) {
    $('#' + fld + '-1').show();
    $('#' + fld + '-note').show();
    $('#' + fld + '-change-password').hide()

}

//8- Toggle settings dropdown/textbox use for settings module
function doSettings(selectedValue) {

    if ($('#setting_type').val() == 'Text') {

        $('#setting_options').val('');
        $('#setting_options').prop('readonly', true);
        $('#option-wrapper').html(optTextbox);
    } else {
        $('#setting_options').prop('readonly', false);
        $('#option-wrapper').html(optSelect);
        opt = $('#setting_options').val();
        opt = opt.split(',');

        o = '<option value="">Select..</option>';
        for (i = 0; i < opt.length; i++) {
            ot = opt[i].trim()
            if (ot != '') {
                if (ot == selectedValue) {
                    sel = " selected=\"selected\" ";
                } else {
                    sel = '';
                }
                o += '<option' + sel + '>' + ot + '</option>';
            }
        }
        $('#setting_value').html(o);
    }

}



//9- Slugify text
function doSlugify(text, spaceCharacter)
{
    return text.toString().toLowerCase()
            .replace(/\s+/g, spaceCharacter)           // Replace spaces with -
            .replace(/[^\w\-]+/g, '')       // Remove all non-word chars
            .replace(/\-\-+/g, spaceCharacter)         // Replace multiple - with single -
            .replace(/^-+/, '')             // Trim - from start of text
            .replace(/-+$/, '');            // Trim - from end of text
}


//10- validate numeric field
function validateNumericInput(event) {
    // Allow: backspace, delete, tab, escape, enter
    if (
            event.key === "Backspace" ||
            event.key === "Delete" ||
            event.key === "Tab" ||
            event.key === "Escape" ||
            event.key === "Enter"
            ) {
        return;
    }

    // Allow: Ctrl+A, Command+A, Ctrl+C, Command+C, Ctrl+X, Command+X
    if (
            (event.ctrlKey || event.metaKey) &&
            (event.key === "a" || event.key === "A" || event.key === "c" || event.key === "C" || event.key === "x" || event.key === "X")
            ) {
        return;
    }

    // Allow: home, end, left, right, up, down
    if (
            event.key === "Home" ||
            event.key === "End" ||
            event.key === "ArrowLeft" ||
            event.key === "ArrowRight" ||
            event.key === "ArrowUp" ||
            event.key === "ArrowDown"
            ) {
        return;
    }

    // Digits only
    if (!/^\d$/.test(event.key)) {
        event.preventDefault();
        return;
    }

    // Enforce digit length if data-maxlen provided (works for type=number too)
    try {
        const el = event.target;
        const maxlen = el && el.dataset ? parseInt(el.dataset.maxlen || '', 10) : NaN;
        if (!Number.isFinite(maxlen) || maxlen <= 0) return;

        const v = String(el.value || '').replace(/\D/g, '');
        const start = (typeof el.selectionStart === 'number') ? el.selectionStart : v.length;
        const end = (typeof el.selectionEnd === 'number') ? el.selectionEnd : v.length;
        const selected = Math.max(0, end - start);
        if ((v.length - selected) >= maxlen) {
            event.preventDefault();
        }
    } catch (e) {}
}


//12- validate float
function validateFloatInput(event) {
    // Allow: backspace, delete, tab, escape, enter
    if (
            event.key === "Backspace" ||
            event.key === "Delete" ||
            event.key === "Tab" ||
            event.key === "Escape" ||
            event.key === "Enter"
            ) {
        return;
    }

    // Allow: Ctrl+A, Command+A, Ctrl+C, Command+C, Ctrl+X, Command+X
    if (
            (event.ctrlKey || event.metaKey) &&
            (event.key === "a" || event.key === "A" || event.key === "c" || event.key === "C" || event.key === "x" || event.key === "X")
            ) {
        return;
    }

    // Allow: home, end, left, right, up, down
    if (
            event.key === "Home" ||
            event.key === "End" ||
            event.key === "ArrowLeft" ||
            event.key === "ArrowRight" ||
            event.key === "ArrowUp" ||
            event.key === "ArrowDown"
            ) {
        return;
    }

    const key = event.key;

    // Allow minus only at start (or when entire value is selected)
    if (key === "-") {
        const el = event.target;
        const value = String(el && el.value ? el.value : "");
        const start = (el && typeof el.selectionStart === "number") ? el.selectionStart : 0;
        const end = (el && typeof el.selectionEnd === "number") ? el.selectionEnd : 0;
        const selectingAll = (start === 0 && end === value.length);
        if (value.includes("-") && !selectingAll) {
            event.preventDefault();
        } else if (start !== 0 && !selectingAll) {
            event.preventDefault();
        }
        return;
    }

    // Allow decimal separator: dot or comma (only one total)
    if (key === "." || key === ",") {
        const v = String(event.target && event.target.value ? event.target.value : "");
        if (v.includes(".") || v.includes(",")) {
            event.preventDefault();
        }
        return;
    }

    // Allow digits only
    if (!/^\d$/.test(key)) {
        event.preventDefault();
        return;
    }

    // Enforce total digit length (excluding sign and decimals) if data-maxlen provided
    try {
        const el = event.target;
        const maxlen = el && el.dataset ? parseInt(el.dataset.maxlen || '', 10) : NaN;
        const scale = el && el.dataset ? parseInt(el.dataset.scale || '', 10) : NaN;
        if (!Number.isFinite(maxlen) || maxlen <= 0) return;

        // enforce digits before/after decimal if scale provided
        const raw = String(el.value || '');
        if (Number.isFinite(scale) && scale >= 0) {
            const parts = raw.replace(',', '.').split('.');
            const before = (parts[0] || '').replace(/[^0-9]/g, '');
            const after = (parts[1] || '').replace(/[^0-9]/g, '');
            // If cursor is after decimal part, enforce scale
            if ((raw.includes('.') || raw.includes(',')) && after.length >= scale) {
                event.preventDefault();
                return;
            }
            // If cursor is in integer part, enforce maxlen on integer digits
            if (!raw.includes('.') && !raw.includes(',') && before.length >= maxlen) {
                event.preventDefault();
                return;
            }
        }

        const v = raw.replace(/[^0-9]/g, '');
        const start = (typeof el.selectionStart === 'number') ? el.selectionStart : v.length;
        const end = (typeof el.selectionEnd === 'number') ? el.selectionEnd : v.length;
        const selected = Math.max(0, end - start);
        if ((v.length - selected) >= maxlen) {
            event.preventDefault();
        }
    } catch (e) {}
}


//13- validate 
function validateInput(input, maxLength) {
    try {
        const scale = input && input.dataset ? parseInt(input.dataset.scale || '', 10) : NaN;
        let v = String(input.value ?? '');

        // Normalize decimal separator to '.'
        if (v.includes(',')) v = v.replace(',', '.');

        // If scale is defined, trim decimal places
        if (Number.isFinite(scale) && scale >= 0 && v.includes('.')) {
            const parts = v.split('.');
            const before = parts[0];
            const after = (parts[1] ?? '').slice(0, scale);
            v = before + (scale > 0 ? ('.' + after) : '');
        }

        // Enforce max digits on integer part (and overall digits if no decimal)
        const maxlen = Number.isFinite(maxLength) ? maxLength : NaN;
        if (Number.isFinite(maxlen) && maxlen > 0) {
            const neg = v.trim().startsWith('-');
            const vv = v.replace('-', '');
            const parts = vv.split('.');
            const beforeDigits = parts[0].replace(/[^0-9]/g, '').slice(0, maxlen);
            const afterDigits = (parts[1] ?? '').replace(/[^0-9]/g, '');
            v = (neg ? '-' : '') + beforeDigits + (parts.length > 1 ? ('.' + afterDigits) : '');
        }

        input.value = v;
    } catch (e) {}
}



//14- validate email
function validateEmailInput(input) {
    const inputValue = input.value.trim();
    const lastChar = inputValue.slice(-1);

    // Regular expression for a simple email validation
    const validCharsRegex = /^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]$/;

    if (!validCharsRegex.test(lastChar) && lastChar !== '@' && lastChar !== '.') {
        // Invalid character, remove the last character from the input
        input.value = inputValue.slice(0, -1);
    }

    // Check for multiple '@' symbols
    if (inputValue.split('@').length > 2) {
        // More than one '@', remove the last character
        input.value = inputValue.slice(0, -1);
    }
}

//15-  Function to update character count
function updateCharCount(textarea, charCount) {
    // Use setTimeout to allow the textarea value to update after the input event
    setTimeout(function () {
        // Get the current length of the text in the textarea
        const currentLength = textarea.value.length;

        // Get the maximum length from the maxlength attribute
        const maxLength = parseInt(textarea.getAttribute('maxlength'));

        // Calculate the remaining characters
        const remainingChars = maxLength - currentLength;

        // Update the charCountElement
        const charCountElement = document.getElementById(charCount);
        charCountElement.textContent = `Remaining characters: ${remainingChars}/${maxLength}`;
    }, 0);
}


//16- show hide add/main content for main page
function showSection(section_id) {

    if (section_id == "manage-content") {
        document.getElementById("manage-content").style.display = "block";
        document.getElementById("create-content").style.display = "none";
        document.getElementById("update-content").style.display = "none";
        table.ajax.reload();
        updateUrl(BASE_URL + firstSegment);
        //empty error div
        clearErrorDivs();

    } else {
        document.getElementById("manage-content").style.display = "none";
        document.getElementById("create-content").style.display = "block";
        document.getElementById("update-content").style.display = "none";
        updateUrl(BASE_URL + firstSegment + "/#add");
        clearErrorDivs();
    }

}


// 17- get the update page when click on edit page s
function getUpdate(update_url, method = 'update') {
// for add page
    if (method == 'add') {

        /// get add form data
        $.ajax({
            type: 'GET',
            url: BASE_URL + update_url + "/add/",

            success: function (data) {

                document.getElementById("manage-content").style.display = "none";
                document.getElementById("create-content").style.display = "block";
                document.getElementById("update-content").style.display = "none";
                $('#create-content').html(data);
                $('html, body').animate({scrollTop: 0}, 0);
                updateUrl(BASE_URL + update_url + "/#add");
                clearErrorDivs();

            }


        });
    }
// end for add page

// for update page
    if (method == 'update') {
        var update_url_parts = update_url.split('/'); // Split the URL by '/'

        var id = update_url_parts.pop(); // Get the last part, which is the ID (e.g., '1')
        var first_segment = update_url_parts[update_url_parts.length - 2]; // Get 'users' (second last element before 'edit')

        /// get add form data
        $.ajax({
            type: 'GET',
            url: BASE_URL + update_url,
            success: function (data) {

                document.getElementById("manage-content").style.display = "none";
                document.getElementById("create-content").style.display = "none";

                //show update section
                document.getElementById("update-content").style.display = "block";
                $('#update-content').html(data);
                $('html, body').animate({scrollTop: 0}, 0);
                updateUrl(BASE_URL + first_segment + "/#update/" + id);
                clearErrorDivs();


            }


        });
}
// end for update page

}


//18- use in getUpdate function
function updateUrl(segment) {


    window.history.replaceState({}, document.title, segment);
}

// 19 - use to crypt the text
function encrypt(text) {
    return btoa(text);
}

//20-  Function to decrypt (Base64 decode) a string
function decrypt(encodedText) {
    return atob(encodedText);
}

//21- use to clear error div
function clearErrorDivs() {
    // Get all divs inside the form with an ID that ends with "Error"
    var errorDivs = document.querySelectorAll('#add-form span[id$="Error"]');

    // Loop through each div and clear its content
    errorDivs.forEach(function (div) {
        div.innerHTML = '';
    });
    //empty success div
    document.getElementById("success").innerHTML = '';
}


// 22- use to initialize Quill editor
function suCKEditor(editorId) {
    // Create Quill editor instance
    var quill = new Quill('#' + editorId + '-editor', {
        theme: 'snow',
        modules: {
            toolbar: [
                [{ 'font': [] }, { 'size': [] }],
                ['bold', 'italic', 'underline', 'strike'],
                [{ 'color': [] }, { 'background': [] }],
                [{ 'script': 'super' }, { 'script': 'sub' }],
                [{ 'header': [false, 1, 2, 3, 4, 5, 6] }, 'blockquote', 'code-block'],
                [{ 'list': 'ordered' }, { 'list': 'bullet' }, { 'indent': '-1' }, { 'indent': '+1' }],
                ['direction', { 'align': [] }],
                ['link', 'image', 'video'],
                ['clean']
            ]
        }
    });

    // Get the hidden textarea
    var textarea = document.querySelector('#' + editorId);
    
    // Set initial content if textarea has value
    if (textarea && textarea.value) {
        quill.root.innerHTML = textarea.value;
    }

    // Update textarea when Quill content changes
    quill.on('text-change', function() {
        if (textarea) {
            textarea.value = quill.root.innerHTML;
        }
    });

    // Also update on selection change (for better compatibility)
    quill.on('selection-change', function() {
        if (textarea) {
            textarea.value = quill.root.innerHTML;
        }
    });
}



//23- validate phone number 
function formatPhoneNumber(event, input, countryCode) {
    // Get the pressed key code
    const keyCode = event.keyCode;

    // Check if the pressed key is a number
    if (keyCode >= 48 && keyCode <= 57) {
        // Get the input value and remove non-numeric characters
        let phoneNumber = input.value.replace(/\D/g, '');

        // Apply phone number formatting based on country code
        if (countryCode === 'USA') {
            // For USA (10-digit format)
            if (phoneNumber.length < 10) {
                phoneNumber = phoneNumber.replace(/(\d{3})(\d{0,3})(\d{0,4})/, '($1) $2-$3');
            } else {
                phoneNumber = phoneNumber.substring(0, 10);
                phoneNumber = phoneNumber.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
            }
        } else if (countryCode === 'Pakistan') {
            // For Pakistan (dynamic format)
            if (phoneNumber.length <= 3) {
                phoneNumber = phoneNumber.replace(/(\d{4})(\d{3})(\d{0,4})/, '$1-$2'); // First seven digits
            } else {
                phoneNumber = phoneNumber.substring(0, 10);
                phoneNumber = phoneNumber.replace(/(\d{4})(\d{3})(\d{0,4})/, '$1-$2$3'); // Full format
            }
        } else if (countryCode === 'UK') {
            // For UK phone numbers (dynamic format)
            if (phoneNumber.length <= 5) {
                phoneNumber = phoneNumber.replace(/(\d{5})(\d{0,3})/, '$1 $2'); // Area code (5 digits max)
            } else if (phoneNumber.length <= 10) {
                phoneNumber = phoneNumber.replace(/(\d{5})(\d{3})(\d{0,4})/, '$1 $2 $3'); // Full UK number
            } else {
                phoneNumber = phoneNumber.substring(0, 11); // Limit to 11 digits for UK
                phoneNumber = phoneNumber.replace(/(\d{5})(\d{3})(\d{3})/, '$1 $2 $3'); // Format: (XXXXX) XXX XXX
            }
        } else {
            // For international (adjust the pattern as needed)
            phoneNumber = phoneNumber.replace(/(\d{1,4})(\d{1,4})(\d{1,4})(\d{1,})/, '$1-$2-$3-$4');
        }

        // Update the input value with the formatted phone number
        input.value = phoneNumber;
    } else if (keyCode !== 8 && keyCode !== 9 && keyCode !== 37 && keyCode !== 39) {
        // Ignore non-numeric keys, backspace, tab, left arrow, and right arrow
        event.preventDefault();
    }
}



// 24- resize the image and add to Base64 in hidden div
//
function suResizeImage(event, id, filenameid) {
    const input = event.target;

    if (input.files && input.files[0]) {
        const file = input.files[0];
        const maxKb = parseInt(window.SU_MAX_IMAGE_SIZE_KB, 10) || 0;
        if (maxKb > 0 && file.size > maxKb * 1024) {
            alert('Image must not exceed ' + maxKb + ' KB.');
            input.value = '';
            const resized = document.getElementById(id);
            const filenameEl = document.getElementById(filenameid);
            if (resized) resized.value = '';
            if (filenameEl) filenameEl.value = '';
            const previewId = input.id + '-preview';
            if (typeof clearImagePreview === 'function') {
                clearImagePreview(input.id, previewId);
            }
            return;
        }

        const reader = new FileReader();

        reader.onload = function (e) {
            // Get the original file name
            const originalFileName = input.files[0].name;
            // Replace spaces with hyphens in the filename also add unique number 
            const sanitizedFileName = Math.floor(Math.random() * 1000000) + '-' + originalFileName.replace(/\s+/g, '-');

            document.getElementById(filenameid).value = sanitizedFileName;

            // Update the hidden input value with the original image data (no resizing)
            document.getElementById(id).value = e.target.result;
        };

        reader.readAsDataURL(input.files[0]);
    }
}


function suTitle(e, url) {
    val = e.value;

    if (val != '') {
        $.ajax({
            type: 'GET',
            url: url, // Change this to the actual route for fetching templates
            data: {id: val}, // Pass the selected ID as data
            success: function (response) {
                // Update the div with the retrieved template

                document.getElementById('template').innerHTML = response.template;
            },
            error: function () {
                // Handle error if template retrieval fails
                console.error('Failed to retrieve template.');
            }
        });
    }

}



let timer = 30;
let interval;

// Function to enable the button after the countdown
function enableButtonAfterTimeout() {
    interval = setInterval(function () {
        timer--;
        $('#timer').text('Please wait ' + timer + ' seconds to resend OTP');

        if (timer <= 0) {
            clearInterval(interval); // Stop the interval when timer reaches 0
            $('#resendOtpBtn').prop('disabled', false); // Enable the button
            $('#timer').text('You can now resend OTP.'); // Update the message
        }
    }, 1000); // Decrease timer every second
}

// Initial 30-second wait to enable the button
$(document).ready(function () {
    // Disable the button initially
    $('#resendOtpBtn').prop('disabled', true);
    enableButtonAfterTimeout();

    // On form submission, re-disable the button for another 30 seconds
    $('#resendOtpForm').submit(function (e) {
        // Prevent default form submission while the button is disabled
        if ($('#resendOtpBtn').prop('disabled')) {
            e.preventDefault();
            return;
        }

        // Disable the button again after form submission
        $('#resendOtpBtn').prop('disabled', true);

        // Reset the timer to 30 seconds
        timer = 30;

        // Clear any existing intervals to prevent multiple intervals from running
        clearInterval(interval);

        // Start the countdown again
        enableButtonAfterTimeout();
    });
});



function suSegment(segmentIndex) {
    // Get the full URL (including hash)
    var fullUrl = window.location.href;

    // Remove the APP_URL from the beginning of the full URL
    var appUrl = BASE_URL;
    var relativeUrl = fullUrl.replace(appUrl, '');  // Strip the APP_URL part
    // Split the URL by '/' and '#'
    var segments = relativeUrl.split(/[\/#]/).filter(Boolean); // Filter out empty segments

    // Return the segment by index or undefined if it doesn't exist
    return segments[segmentIndex] || undefined;
}
function getAllQueryParams() {
    // Initialize an empty object to store query parameters
    const queryParams = new URLSearchParams(window.location.search);

    // Check if there's a hash and if it contains query parameters
    if (window.location.hash.includes('?')) {
        // Extract the query parameters from the hash after the `?`
        const hashParams = new URLSearchParams(window.location.hash.split('?')[1]);
        hashParams.forEach((value, key) => {
            queryParams.set(key, value);
        });
    }

    // If no query parameters are found, return an empty string
    if (!queryParams.toString()) {
        return '';
    }

    // Build and return the formatted query string
    return '?' + queryParams.toString();
}



// show image in bootstrap modal
function suBModal(imageSrc) {
    // Check if the modal already exists
    let existingModal = document.getElementById('imageModal');

    // If modal doesn't exist, create it
    if (!existingModal) {
        // Create modal container
        let modal = document.createElement('div');
        modal.id = 'imageModal';
        modal.style.cssText = `
                display: none;
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.8);
                z-index: 10000;
                justify-content: center;
                align-items: center;
                overflow: auto;
            `;

        // Add an event listener to close the modal when clicking outside the image
        modal.addEventListener('click', function (event) {
            if (event.target === modal) {
                modal.style.display = 'none';
            }
        });

        // Create image wrapper - constrains size so tall/wide images fit in viewport
        let imageWrapper = document.createElement('div');
        imageWrapper.style.cssText = `
                position: relative;
                max-width: 90vw;
                max-height: 85vh;
                display: flex;
                align-items: center;
                justify-content: center;
                flex-shrink: 0;
            `;

        // Create close button
        let closeButton = document.createElement('button');
        closeButton.innerHTML = 'X';
        closeButton.style.cssText = `
                position: absolute;
                top: -10px;
                right: -10px;
                z-index: 10;
                background: red;
                color: white;
                border: none;
                border-radius: 50%;
                padding: 5px 10px;
                cursor: pointer;
            `;
        // Close modal on close button click
        closeButton.addEventListener('click', function () {
            modal.style.display = 'none';
        });

        // Create image element - fit inside wrapper without overflowing
        let modalImage = document.createElement('img');
        modalImage.id = 'modalImage';
        modalImage.alt = 'Preview';
        modalImage.style.cssText = `
                max-width: 100%;
                max-height: 85vh;
                width: auto;
                height: auto;
                object-fit: contain;
                border-radius: 10px;
                display: block;
            `;

        // Append close button and image to wrapper
        imageWrapper.appendChild(closeButton);
        imageWrapper.appendChild(modalImage);

        // Append wrapper to modal
        modal.appendChild(imageWrapper);

        // Append modal to body
        document.body.appendChild(modal);
    }

    // Set the image source and display the modal
    document.getElementById('modalImage').src = imageSrc;
    document.getElementById('imageModal').style.display = 'flex';
}

function doModuleSearch(e) {
    var input, filter, div, a, i, txtValue;
    input = e;
    filter = input.value.toUpperCase();
    div = document.getElementById("menu");
    a = div.getElementsByClassName("nav-link");

    for (i = 0; i < a.length; i++) {
        txtValue = a[i].textContent || a[i].innerText;
        if (txtValue.toUpperCase().indexOf(filter) > -1) {
            a[i].style.display = "";
        } else {
            a[i].style.display = "none";
        }
    }
}



//for multiple images
function previewImages(event) {
    const files = Array.from(event.target.files);
    const previewContainer = document.getElementById('image-preview-container');
    previewContainer.innerHTML = '';

    files.forEach((file, index) => {
        const reader = new FileReader();

        reader.onload = function (e) {
            const wrapper = document.createElement('div');
            wrapper.classList.add('position-relative');

            const img = document.createElement('img');
            img.src = e.target.result;
            img.style.width = '100px';
            img.style.height = '100px';
            img.style.objectFit = 'cover';
            img.classList.add('border', 'rounded');
            wrapper.appendChild(img);

            const deleteButton = document.createElement('button');
            deleteButton.classList.add('btn', 'btn-danger', 'btn-sm', 'rounded', 'position-absolute', 'top-0', 'end-0');
            deleteButton.innerHTML = 'X';
            deleteButton.onclick = function () {
                files.splice(index, 1); // Remove the file from the array
                updateFileInput(files); // Update the input files
                wrapper.remove(); // Remove the preview
            };

            wrapper.appendChild(deleteButton);
            previewContainer.appendChild(wrapper);
        };

        reader.readAsDataURL(file);
    });

    function updateFileInput(updatedFiles) {
        const dataTransfer = new DataTransfer();
        updatedFiles.forEach(file => dataTransfer.items.add(file));
        event.target.files = dataTransfer.files;
    }
}

// Admin index layout: session (window.__ADMIN_INDEX_VIEW__) + cookie (admin_index_view) from login,
// then viewport on resize. Avoids slow matchMedia-only toggling on every page.
function suGetCookie(name) {
    try {
        const m = document.cookie.match(new RegExp('(?:^|;\\s*)' + name.replace(/([.$?*|{}()[\]\\/+^])/g, '\\$1') + '=([^;]*)'));
        return m ? decodeURIComponent(m[1]) : '';
    } catch (e) {
        return '';
    }
}

function suSetCookie(name, value, days) {
    try {
        const d = new Date();
        d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000));
        document.cookie = name + '=' + encodeURIComponent(value) + ';path=/;expires=' + d.toUTCString() + ';SameSite=Lax';
    } catch (e) {}
}

function suIsMobileIndexView() {
    const w = typeof window.__ADMIN_INDEX_VIEW__ !== 'undefined' ? window.__ADMIN_INDEX_VIEW__ : '';
    if (w === 'mobile') return true;
    if (w === 'desktop') return false;
    const c = suGetCookie('admin_index_view');
    if (c === 'mobile') return true;
    if (c === 'desktop') return false;
    return !!(window.matchMedia && window.matchMedia('(max-width: 767.98px)').matches);
}

// Toggle card view (mobile) vs table view (desktop) for index pages.
// Expected markup:
// - Cards wrapper:  <div class="js-index-cards d-none">...</div>
// - Table wrapper:  <div class="js-index-table">...</div>
function suToggleIndexView() {
    try {
        const isMobile = suIsMobileIndexView();
        document.querySelectorAll('.js-index-cards').forEach((el) => {
            el.classList.toggle('d-none', !isMobile);
        });
        document.querySelectorAll('.js-index-table').forEach((el) => {
            el.classList.toggle('d-none', isMobile);
        });
    } catch (e) {
        // no-op: avoid breaking other scripts
    }
}

function suEscapeHtml(str) {
    return String(str ?? '')
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#039;');
}

function suStripHtml(html) {
    try {
        const div = document.createElement('div');
        div.innerHTML = String(html ?? '');
        return (div.textContent || div.innerText || '').trim();
    } catch (e) {
        return String(html ?? '').replace(/<[^>]*>/g, '').trim();
    }
}

function suFirstLetterAvatar(text) {
    const t = String(text ?? '').trim();
    const ch = t ? t[0].toUpperCase() : '?';
    // Bootstrap-y circle avatar, email-list style
    return (
        '<div class="rounded-circle bg-soft-primary text-primary d-inline-flex align-items-center justify-content-center flex-shrink-0" ' +
            'style="width:36px;height:36px;font-weight:600;">' +
            suEscapeHtml(ch) +
        '</div>'
    );
}

function suBuildCardsFromTable(tableEl, cardsEl) {
    if (!tableEl || !cardsEl) return;

    const thead = tableEl.querySelector('thead');
    const tbody = tableEl.querySelector('tbody');
    if (!tbody) return;

    const headers = Array.from(thead ? thead.querySelectorAll('th') : []).map(th => (th.textContent || '').trim());
    const rows = Array.from(tbody.querySelectorAll('tr'));

    if (!rows.length) {
        cardsEl.innerHTML = '<div class="text-center text-muted py-4">No records found.</div>';
        return;
    }

    const cards = rows.map((tr) => {
        const tds = Array.from(tr.querySelectorAll('td'));
        const id = tr.getAttribute('id') || '';

        // Guess action column as last column
        const actionCell = tds.length ? tds[tds.length - 1] : null;
        const actionHtml = actionCell ? actionCell.innerHTML : '';

        // Title: first non-empty non-action cell after Sr.
        let titleHtml = '';
        for (let i = 1; i < Math.max(1, tds.length - 1); i++) {
            const html = (tds[i] && tds[i].innerHTML || '').trim();
            const text = (tds[i] && (tds[i].textContent || '') || '').trim();
            if (text) { titleHtml = html; break; }
        }
        if (!titleHtml && tds[0]) titleHtml = suEscapeHtml((tds[0].textContent || '').trim());

        // Detail lines: label + value, skipping Sr. and action.
        const details = [];
        for (let i = 0; i < tds.length; i++) {
            const isSr = i === 0;
            const isAction = i === tds.length - 1;
            if (isSr || isAction) continue;

            const label = headers[i] || '';
            const valueHtml = (tds[i] && tds[i].innerHTML || '').trim();
            const valueText = (tds[i] && (tds[i].textContent || '') || '').trim();
            const hasMedia = !!(tds[i] && tds[i].querySelector && tds[i].querySelector('img,video,svg,canvas'));
            const hasVisibleHtml = !!valueHtml && /<(img|svg|video|canvas|span|a|button|i)\b/i.test(valueHtml);
            if (!valueText && !hasMedia && !hasVisibleHtml) continue;

            details.push(
                '<div class="d-flex justify-content-between align-items-start gap-2">' +
                '<div class="text-muted small fw-bold flex-shrink-0">' + suEscapeHtml(label) + '</div>' +
                '<div class="small text-end text-break min-w-0">' + valueHtml + '</div>' +
                '</div>'
            );
        }

        const titleText = suStripHtml(titleHtml);
        const avatarHtml = suFirstLetterAvatar(titleText);

        return (
            '<div class="card border rounded-3 mb-0 overflow-hidden" ' + (id ? ('id="card_' + suEscapeHtml(id) + '"') : '') + '>' +
              '<div class="card-body p-3">' +
                '<div class="d-flex align-items-center gap-2 min-w-0">' +
                  avatarHtml +
                  '<div class="min-w-0 flex-grow-1 overflow-hidden">' +
                    '<div class="fw-semibold text-break">' + titleHtml + '</div>' +
                  '</div>' +
                  (actionHtml
                    ? ('<div class="d-flex flex-wrap gap-1 justify-content-end align-items-center flex-shrink-0">' + actionHtml + '</div>')
                    : '') +
                '</div>' +
                (details.length
                    ? ('<div class="mt-2 pt-2 border-top vstack gap-1">' + details.join('') + '</div>')
                    : '') +
              '</div>' +
            '</div>'
        );
    });

    cardsEl.innerHTML = '<div class="vstack gap-2">' + cards.join('') + '</div>';
}

function suBuildIndexCards() {
    try {
        const isMobile = suIsMobileIndexView();
        if (!isMobile) return;

        document.querySelectorAll('.js-index-table').forEach((tableWrap) => {
            const root = tableWrap.closest('.card-body') || document;
            const cardsEl = root.querySelector('.js-index-cards');
            const tableEl = tableWrap.querySelector('table');
            if (!cardsEl || !tableEl) return;

            // If DataTables handles this table, cards are rendered in its drawCallback (see pages that use it).
            if (window.jQuery && jQuery.fn && jQuery.fn.dataTable && jQuery.fn.dataTable.isDataTable && jQuery.fn.dataTable.isDataTable(tableEl)) {
                return;
            }

            suBuildCardsFromTable(tableEl, cardsEl);
        });
    } catch (e) {}
}

let suIndexViewResizeTimer;
let suLastResizeMobile = null;

function suSyncAdminIndexViewFromViewport() {
    try {
        const mq = !!(window.matchMedia && window.matchMedia('(max-width: 767.98px)').matches);
        if (suLastResizeMobile === mq) return;
        suLastResizeMobile = mq;
        const want = mq ? 'mobile' : 'desktop';
        window.__ADMIN_INDEX_VIEW__ = want;
        suSetCookie('admin_index_view', want, 365);
        const token = document.querySelector('meta[name="csrf-token"]');
        if (token && typeof fetch !== 'undefined') {
            let url = '/admin/sync-device-index-view';
            if (typeof BASE_URL !== 'undefined' && BASE_URL) {
                url = String(BASE_URL).replace(/\/?$/, '/') + 'admin/sync-device-index-view';
            }
            fetch(url, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRF-TOKEN': token.getAttribute('content'),
                    Accept: 'application/json',
                },
                body: JSON.stringify({ view: want }),
                credentials: 'same-origin',
            }).catch(function () {});
        }
        suToggleIndexView();
        suBuildIndexCards();
        if (typeof window.jQuery !== 'undefined' && typeof table !== 'undefined' && table && typeof table.draw === 'function') {
            try { table.draw(false); } catch (e2) {}
        }
    } catch (e) {}
}

function suInitIndexView() {
    try {
        suLastResizeMobile = !!(window.matchMedia && window.matchMedia('(max-width: 767.98px)').matches);
    } catch (e) {}
    suToggleIndexView();
    suBuildIndexCards();
}

document.addEventListener('DOMContentLoaded', suInitIndexView);
window.addEventListener('load', suInitIndexView);
window.addEventListener('resize', function () {
    clearTimeout(suIndexViewResizeTimer);
    suIndexViewResizeTimer = setTimeout(suSyncAdminIndexViewFromViewport, 200);
});