htmx.defineExtension('disable-submit', {
    onEvent: function (name, evt, data) {
    /*
        let elt = evt.detail.elt;
        let result = elt.querySelectorAll('.hx-disable');

        if (name === 'htmx:beforeRequest') {
            result.forEach(element => element.disabled = true);
            if (elt.classList.contains('hx-disable')) {
                elt.disabled = true;}

        } else if(name == 'htmx:afterRequest') {
            result.forEach(element => element.disabled = false);
            if (elt.classList.contains('hx-disable')) elt.disabled = false;
        }
        */
    }
})

htmx.defineExtension('rename-params', {
    onEvent: function(name ,  evt) {
        if (name === "htmx:configRequest") {
            var normal = evt.detail.elt.getAttribute("hx-rename-params");
            if (normal) {
                normal = JSON.parse(normal);
                for (const [key, value] of Object.entries(normal)) {
                    console.log(evt.detail.parameters)
                    evt.detail.parameters[value] = evt.detail.parameters[key];
                    delete evt.detail.parameters[key];
                }
            }
            var exclusive = evt.detail.elt.getAttribute("hx-rename-params-ex");
            if (exclusive) {
                exclusive = JSON.parse(exclusive);
                var params = {};
                for (const [key, value] of Object.entries(exclusive)) {
                    var v = evt.detail.parameters[key]
                    if (v) {
                        params[value] = v;
                    }
                }
                evt.detail.parameters = params;
            }
        }
    }
});


htmx.defineExtension('reactive-trigger', {
    
    onEvent: function(name ,  evt) {
        if (name === "htmx:beforeProcessNode") {
            var element = evt.detail.elt;
            var reactiveTrigger = element.getAttribute("hx-reactive-trigger");
            if (reactiveTrigger) {
                reactiveTrigger = JSON.parse(reactiveTrigger);
                var reactiveSource = element.getAttribute("hx-reactive-source");
                reactiveSource =  reactiveSource ? document.querySelector(reactiveSource) : element.closest("form");

                // var triggerString = Object.keys(reactiveTrigger).map(k => "change from:#" + reactiveSource.getAttribute("id") +  " [name=\"" + k + "\"]").join(", ");
                var triggerString = reactiveTrigger.map(k => "change from:" + "[name=\"" + k + "\"]").join(", ");
                element.setAttribute("hx-trigger", triggerString);
            }
        } else if (name=="htmx:configRequest") {
            var element = evt.detail.elt;
            var reactiveTrigger = element.getAttribute("hx-reactive-trigger");
            if (reactiveTrigger) {
                reactiveTrigger = JSON.parse(reactiveTrigger);
                var reactiveSource = element.getAttribute("hx-reactive-source");
                reactiveSource =  reactiveSource ? document.querySelector(reactiveSource) : element.closest("form");
                for (key of reactiveTrigger) {
                    console.log( reactiveSource.querySelector(`[name="${key}"]`).value)
                    evt.detail.parameters[key] = reactiveSource.querySelector(`[name="${key}"]`).value || "";
                }
            }
        }
    }
});

function deepEqual(obj1, obj2) {
    if (obj1 === obj2) {
        return true; // Check for equality
    }

    if (typeof obj1 !== 'object' || typeof obj2 !== 'object' || obj1 === null || obj2 === null) {
        return false; // Check if both are objects
    }

    const keys1 = Object.keys(obj1);
    const keys2 = Object.keys(obj2);

    if (keys1.length !== keys2.length) {
        return false; // Check if they have the same number of properties
    }

    for (const key of keys1) {
        if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
            return false; // Recursively compare properties
        }
    }

    return true; // Objects are deeply equal
}

htmx.defineExtension('trigger-filter', {
    
    onEvent: function(name ,  evt) {
        if (name=="htmx:beforeRequest") {
            var element = evt.detail.elt;
            if (!deepEqual(element.lastParams, evt.detail.requestConfig.parameters)) {
                element.lastParams = evt.detail.requestConfig.parameters;
            } else {
                console.log("unchanged")
                evt.preventDefault();
            }
        } 
    }
});


initDatepicker = function(elem) {
    const modalParent = elem.closest('#modal-content');
    if (modalParent) {
        console.log('datepicker in modal')
        return new Datepicker(elem, {format: "mm/dd/yyyy", autohide: true, container: "#modal-content .modal-card"});
    } else {
        console.log('datepicker normal')
        return new Datepicker(elem, {format: "mm/dd/yyyy", autohide: true});
    }

}

function formatDateMMDDYYYY(date) {
    const month = String(date.getMonth() + 1).padStart(2, '0'); // Get month (1-12), pad with leading zero if necessary
    const day = String(date.getDate()).padStart(2, '0');        // Get day (1-31), pad with leading zero if necessary
    const year = date.getFullYear();                            // Get full year

    return `${month}/${day}/${year}`;
}

function parseMMDDYYYY(dateString) {
    const parts = dateString.split('/');
    if (parts.length !== 3) {
        throw new Error('Invalid date format. Expected mm/dd/yyyy');
    }
    const month = parseInt(parts[0], 10) - 1; // Months are zero-based in JavaScript
    const day = parseInt(parts[1], 10);
    const year = parseInt(parts[2], 10);
    
    return new Date(year, month, day);
}

const getFourWeekPeriods = endDate => {
    if (!endDate) {
        endDate= formatDateMMDDYYYY(new Date())
    }
    let periods = [endDate];
    for (let i = 0; i < 13; i++) {
        const currentDate = new Date(parseMMDDYYYY(endDate).getTime());
        currentDate.setDate(currentDate.getDate() - 28 * (i + 1));
        periods.push(formatDateMMDDYYYY(new Date(currentDate)));
    }
    return periods;
};

function getFourWeekPeriodsPeriods(endDate) {
    // Determine today's date based on data or current local date
    const today = endDate ? parseMMDDYYYY(endDate) : new Date();
  
    // Calculate the total period
    const totalStart = dateFns.addDays(dateFns.subWeeks(today, 13 * 4), 1);
  
    // Construct the array of periods
    return [
      {
        start: dateFns.format(totalStart, 'MM/dd/yyyy'),
        end: dateFns.format(today, 'MM/dd/yyyy'),
        title: "Total"
      },
      ...Array.from({ length: 13 }, (_, i) => ({
        start: dateFns.format(dateFns.addDays(dateFns.subWeeks(today, (i + 1) * 4), 1), 'MM/dd/yyyy'),
        end: dateFns.format(dateFns.subWeeks(today, i * 4), 'MM/dd/yyyy')
      }))
    ];
  }
  
  const getTwelveCalendarMonthsPeriods = (endDate) => {
      console.log(endDate)
    // If no date is provided, default to today's date
    const today = endDate ? parseMMDDYYYY(endDate) : new Date();
    
    // Set the last day of the provided month as the end date
    const inputEndDate = new Date(today.getFullYear(), today.getMonth() + 1, 0);
    
    // Calculate the start of the total year range (12 months back from the end of input month)
    const totalStartDate = new Date(inputEndDate.getFullYear(), inputEndDate.getMonth() - 11, 1);

    // Build the array of months
    
    // Build the array of months
    const months = [
        {
            start: formatDateMMDDYYYY(totalStartDate),
            end: formatDateMMDDYYYY(inputEndDate),
            title: "Total"
        },
        ...Array.from({ length: 12 }, (_, i) => {
            const monthEnd = new Date(inputEndDate.getFullYear(), inputEndDate.getMonth() - (11 - i) + 1, 0); // Last day of the month
            const monthStart = new Date(monthEnd.getFullYear(), monthEnd.getMonth(), 1); // First day of the month
            return {
                start: formatDateMMDDYYYY(monthStart),
                end: formatDateMMDDYYYY(monthEnd),
                title: monthEnd.toLocaleString('default', { month: 'long', year: 'numeric' })
            };
        })
    ];
      console.log(months)

    return months;
};

const  withLastYear = (date) => {

    if (!date) {
        date= new Date()
    } else {
        date = parseMMDDYYYY(date)
    }
    const originalYear = date.getFullYear();
    const priorYear = originalYear - 1;

    // Create new Date objects for both years
    const originalDate = new Date(originalYear, date.getMonth(), date.getDate());
    const priorYearDate = new Date(priorYear, date.getMonth(), date.getDate());

    return [formatDateMMDDYYYY(originalDate), formatDateMMDDYYYY(priorYearDate)];
}

const  lastYearPeriod = (date) => {
    if (!date) {
        date= new Date()
    } else {
        date = parseMMDDYYYY(date)
    }
    const originalYear = date.getFullYear();
    const priorYear = originalYear - 1;

    // Create new Date objects for both years
    const originalDate = new Date(originalYear, date.getMonth(), date.getDate());
    const priorYearDate = dateFns.addDays(new Date(priorYear, date.getMonth(), date.getDate()), 1);

    return {end: formatDateMMDDYYYY(originalDate), start: formatDateMMDDYYYY(priorYearDate)};
}

const  calendarYearPeriod = (date) => {
    if (!date) {
        date= new Date()
    } else {
        date = parseMMDDYYYY(date)
    }
    const originalYear = date.getFullYear();
    const priorYear = originalYear - 1;

    // Create new Date objects for both years
    const start = new Date(originalYear, 0, 1);
    const end = new Date(originalYear, 11, 31);

    return {end: formatDateMMDDYYYY(end), start: formatDateMMDDYYYY(start)};
}

const getLastMonthPeriods = (date) => {
    if (!date) {
        date = new Date();
    } else {
        date = parseMMDDYYYY(date);
    }

    // Get the first day of the current month
    const firstDayOfCurrentMonth = new Date(date.getFullYear(), date.getMonth(), 1);

    // Get the last day of the previous month
    const lastDayOfPreviousMonth = dateFns.subDays(firstDayOfCurrentMonth, 1);

    // Get the first day of the previous month
    const firstDayOfPreviousMonth = new Date(lastDayOfPreviousMonth.getFullYear(), lastDayOfPreviousMonth.getMonth(), 1);

    // Get the same period for the previous year
    const firstDayOfPreviousYearMonth = new Date(firstDayOfPreviousMonth.getFullYear() - 1, firstDayOfPreviousMonth.getMonth(), 1);
    const lastDayOfPreviousYearMonth = dateFns.lastDayOfMonth(firstDayOfPreviousYearMonth);

    // Create period objects
    const currentPeriod = {
        start: formatDateMMDDYYYY(firstDayOfPreviousMonth),
        end: formatDateMMDDYYYY(lastDayOfPreviousMonth)
    };

    const previousYearPeriod = {
        start: formatDateMMDDYYYY(firstDayOfPreviousYearMonth),
        end: formatDateMMDDYYYY(lastDayOfPreviousYearMonth)
    };

    return [currentPeriod, previousYearPeriod];
};

const getMonthToDatePeriods = () => {
        date = new Date();

    // Get the first day of the current month
    const firstDayOfCurrentMonth = new Date(date.getFullYear(), date.getMonth(), 1);

    // Get the same period for the previous year
    const firstDayOfPreviousYearMonth = new Date(firstDayOfCurrentMonth.getFullYear() - 1, firstDayOfCurrentMonth.getMonth(), 1);

    // Create period objects
    const currentPeriod = {
        start: formatDateMMDDYYYY(firstDayOfCurrentMonth),
        end: formatDateMMDDYYYY(date)
    };

    const previousYearPeriod = {
        start: formatDateMMDDYYYY(firstDayOfPreviousYearMonth),
        end: formatDateMMDDYYYY(new Date(firstDayOfPreviousYearMonth.getFullYear(), firstDayOfPreviousYearMonth.getMonth(), date.getDate()))
    };

    return [currentPeriod, previousYearPeriod];
};

const getYearToDatePeriods = () => {
        date = new Date();

    // Get the first day of the current month
    const firstDayOfCurrentMonth = new Date(date.getFullYear(), 0, 1);

    // Get the same period for the previous year
    const firstDayOfPreviousYearMonth = new Date(firstDayOfCurrentMonth.getFullYear() - 1, 0, 1);

    // Create period objects
    const currentPeriod = {
        start: formatDateMMDDYYYY(firstDayOfCurrentMonth),
        end: formatDateMMDDYYYY(date)
    };

    const previousYearPeriod = {
        start: formatDateMMDDYYYY(firstDayOfPreviousYearMonth),
        end: formatDateMMDDYYYY(new Date(firstDayOfPreviousYearMonth.getFullYear(), firstDayOfPreviousYearMonth.getMonth(), date.getDate()))
    };

    return [currentPeriod, previousYearPeriod];
}
initMultiDatepicker = function(elem, startingValue) {
    const modalParent = elem.closest('#modal-content');
    if (modalParent) {
        return new Datepicker(elem, {format: "mm/dd/yyyy", autohide: false, container: "#modal-content .modal-card", maxNumberOfDates: 12, dateDelimiter: ", "});
    } else {
        return new Datepicker(elem, {format: "mm/dd/yyyy", autohide: false, maxNumberOfDates: 12, dateDelimiter: ", "});
    }
}

initCalendar = function(elem, startingValue) {
    const modalParent = elem.closest('#modal-content');
    if (modalParent) {
        return new Datepicker(elem, {format: "mm/dd/yyyy", autohide: false, container: "#modal-content .modal-card"});
    } else {
        return new Datepicker(elem, {format: "mm/dd/yyyy", autohide: false, });
    }
}


destroyDatepicker = function(dp) {
    try {
        dp.destroy()
    } catch {

    }
}

countRows = function(id) {
    var table = document.querySelector(id);
    var rows = table.querySelectorAll("tbody tr");
    return rows.length;
}

htmx.onLoad(function(content) {
    var sortables = content.querySelectorAll(".sortable");
    for (var i = 0; i < sortables.length; i++) {
      var sortable = sortables[i];
      var sortableInstance = new Sortable(sortable, {
          animation: 150,
          ghostClass: 'bg-blue-100',

          // Make the `.htmx-indicator` unsortable
          filter: ".htmx-indicator",
          onMove: function (evt) {
            return evt.related.className.indexOf('htmx-indicator') === -1;
          },

          // Disable sorting on the `end` event
          onEnd: function (evt) {
            this.option("disabled", true);
          }
      });

      // Re-enable sorting on the `htmx:afterSwap` event
      sortable.addEventListener("htmx:afterSwap", function() {
        sortableInstance.option("disabled", false);
      });
    }
})

  async function copyToClipboard(text) {
    try {
      // Write the text to the clipboard
      await navigator.clipboard.writeText(text);
      console.log('Text copied to clipboard:', text);
    } catch (err) {
      console.error('Failed to copy text to clipboard:', err);
    }
  }

