/**
 *
 * -----------------------------------------------------------
 *
 * CodexShaper Framework
 * A complete framework for WordPress
 *
 * -----------------------------------------------------------
 *
 */
(function ($, window, document, undefined) {
  "use strict";

  /**
   * Replace all occurrences of a string in a string
   * @param {string} str - search string
   */
  function pregQuote(str) {
    return (str + "").replace(/(\[|\])/g, "\\$1");
  }

  /**
   * Replace name attribute of nested elements
   * @param {string} $selector - jQuery selector
   * @param {string} field_id - Field ID
   */
  function nameNestedReplace($selector, field_id) {
    var checks = [];
    var regex = new RegExp(pregQuote(field_id + "[\\d+]"), "g");

    $selector.find(":radio").each(function () {
      if (this.checked || this.originalChecked) {
        this.originalChecked = true;
      }
    });

    $selector.each(function (index) {
      $(this)
        .find(":input")
        .each(function () {
          this.name = this.name.replace(regex, field_id + "[" + index + "]");
          if (this.originalChecked) {
            this.checked = true;
          }
        });
    });
  }

  /**
   * DependsOn Plugin
   * @param {object} options - Plugin options
   */
  $.fn.csmfDependsOn = function (options) {
    const settings = $.extend(
      {
        // Default settings
        attribute: "data-depends",
        conditionAttribute: "data-condition",
        valueAttribute: "data-value",
        groupAttribute: "data-group",
        actionsAttribute: "data-actions",
        triggerInitial: true,
        onEnable: null,
        onDisable: null,
        debug: false,
      },
      options
    );

    // Store element rules
    const rules = new Map();

    // Helper function to log debug messages
    const debug = (message) => {
      if (settings.debug) {
      }
    };

    // Parse dependency string into rules
    const parseRules = (dependencyStr) => {
      if (!dependencyStr) return [];

      return dependencyStr.split("|").map((rule) => {
        const [selector, condition, value] = rule
          .trim()
          .split(":")
          .map((part) => part.trim());
        return { selector, condition, value };
      });
    };

    // Parse actions string into array
    const parseActions = (actionsStr) => {
      if (!actionsStr) return ["show"];
      return actionsStr.split(",").map((action) => action.trim());
    };

    // Evaluate conditions
    const evaluateCondition = (element, condition, expectedValue) => {
      const $element = $(element);
      const actualValue = $element.is(":checkbox, :radio") ? $element.prop("checked") : $element.val();

      switch (condition) {
        case "equals":
        case "==":
        case "===":
          return actualValue === expectedValue;
        case "notEquals":
        case "!=":
        case "!==":
          return actualValue !== expectedValue;
        case "contains":
          return actualValue?.includes(expectedValue);
        case "empty":
          return !actualValue || actualValue.length === 0;
        case "notEmpty":
          return actualValue && actualValue.length > 0;
        case "checked":
          return $element.prop("checked");
        case "unchecked":
          return !$element.prop("checked");
        case "greaterThan":
        case ">":
          return parseFloat(actualValue) > parseFloat(expectedValue);
        case "greaterThanOrEqual":
        case ">=":
          return parseFloat(actualValue) >= parseFloat(expectedValue);
        case "lessThan":
        case "<":
          return parseFloat(actualValue) < parseFloat(expectedValue);
        case "lessThanOrEqual":
        case "<=":
          return parseFloat(actualValue) <= parseFloat(expectedValue);
        case "matches":
          return new RegExp(expectedValue).test(actualValue);
        default:
          debug(`Unknown condition: ${condition}`);
          return false;
      }
    };

    // Apply actions based on conditions
    const applyActions = ($element, satisfied, actions) => {
      actions.forEach((action) => {
        switch (action) {
          case "show":
            $element[satisfied ? "show" : "hide"]();
            break;
          case "hide":
            $element[satisfied ? "hide" : "show"]();
            break;
          case "enable":
            $element.prop("disabled", !satisfied);
            break;
          case "disable":
            $element.prop("disabled", satisfied);
            break;
          case "addClass":
            $element.toggleClass("dependent-active", satisfied);
            break;
          case "removeClass":
            $element.toggleClass("dependent-active", !satisfied);
            break;
          default:
            debug(`Unknown action: ${action}`);
        }
      });

      // Trigger callbacks
      if (satisfied && typeof settings.onEnable === "function") {
        settings.onEnable.call($element[0]);
      } else if (!satisfied && typeof settings.onDisable === "function") {
        settings.onDisable.call($element[0]);
      }
    };

    // Handle group dependencies
    const handleGroups = ($element, satisfied) => {
      const group = $element.attr(settings.groupAttribute);
      if (group) {
        $(`[${settings.groupAttribute}="${group}"]`).not($element).toggleClass("group-active", satisfied);
      }
    };

    // Evaluate all dependencies for an element
    const evaluateDependencies = ($target) => {
      debug(`Evaluating dependencies for ${$target.attr("id") || "element"}`);

      rules.forEach((dependentElements, ruleSet) => {
        dependentElements.forEach(({ $element, rules, actions }) => {
          const results = rules.map((rule) => {
            const $ruleTarget = $(rule.selector);
            return evaluateCondition($ruleTarget[0], rule.condition, rule.value);
          });

          // All conditions must be true
          const satisfied = results.every((result) => result);
          applyActions($element, satisfied, actions);
          handleGroups($element, satisfied);
        });
      });
    };

    // Initialize plugin for each element
    return this.each(function () {
      const $element = $(this);
      const dependencyStr = $element.attr(settings.attribute);

      if (!dependencyStr) {
        debug("No dependencies found");
        return;
      }

      const parsedRules = parseRules(dependencyStr);
      const actions = parseActions($element.attr(settings.actionsAttribute));

      // Store rules
      parsedRules.forEach((rule) => {
        if (!rules.has(rule.selector)) {
          rules.set(rule.selector, []);
        }
        rules.get(rule.selector).push({
          $element,
          rules: parsedRules,
          actions,
        });

        // Attach event handlers
        $(rule.selector).on("change input", function () {
          evaluateDependencies($(this));
        });
      });

      // Initial evaluation
      if (settings.triggerInitial) {
        evaluateDependencies($element);
      }
    });
  };

  /**
   * Builder File Upload Plugin
   * @param {object} options - Plugin options
   */
  $.fn.csmfBuilderFileUpload = function (options) {
    const settings = $.extend(
      {
        library: [], // Allowed file types (e.g., ['image', 'video'])
        onFileSelect: null, // Callback for file selection
        onFileRemove: null, // Callback for file removal
      },
      options
    );

    return this.each(function () {
      const $container = $(this),
        $input = $container.find('input[type="text"]'),
        $uploadButton = $container.find(".csmf--upload-button"),
        $removeButton = $container.find(".csmf--upload-remove"),
        $previewWrap = $container.find(".csmf--upload-preview"),
        $previewImage = $container.find(".csmf--upload-preview-img"),
        $mediaId = $container.find(".csmf--media-id"),
        $mediaThumbnail = $container.find(".csmf--media-thumbnail"),
        $mediaAlt = $container.find(".csmf--media-alt"),
        $mediaTitle = $container.find(".csmf--media-title"),
        $mediaDescription = $container.find(".csmf--media-description"),
        $mediaWidth = $container.find(".csmf--media-width"),
        $mediaHeight = $container.find(".csmf--media-height"),
        $library = ($uploadButton.data("library") && $uploadButton.data("library").split(",")) || [];

      let wpMediaFrame = null;

      settings.library = Array.isArray(settings.library) ? settings.library : [];

      if (Array.isArray($library) && $library.length > 0) {
        settings.library = $library;
      }

      // Open WordPress Media Library
      $uploadButton.on("click", function (e) {
        e.preventDefault();

        // Check for WordPress media support
        if (typeof window.wp === "undefined" || !window.wp.media) {
          alert("WordPress media library is not available.");
          return;
        }

        // Reuse existing frame or create a new one
        if (!wpMediaFrame) {
          wpMediaFrame = window.wp.media({
            title: "Select a File",
            library: {
              type: settings.library,
            },
            button: {
              text: "Use this file",
            },
            multiple: false,
          });

          // Handle file selection
          wpMediaFrame.on("select", function () {
            const attributes = wpMediaFrame.state().get("selection").first().attributes;
            var preview_size = $uploadButton.data("preview-size") || "thumbnail";
            var thumbnail = attributes.icon;

            if (attributes.type === "image") {
              thumbnail = attributes.url;
            }

            if (attributes?.sizes && attributes?.sizes?.full) {
              thumbnail = attributes.sizes.full.url;
            }

            if (attributes.sizes && attributes.sizes.thumbnail && preview_size === "thumbnail") {
              thumbnail = attributes.sizes.thumbnail.url;
            }

            if (
              settings.library.length &&
              settings.library.indexOf(attributes.subtype) === -1 &&
              settings.library.indexOf(attributes.type) === -1
            ) {
              alert("This file type is not allowed.");
              return;
            }

            $input.val(attributes.url).trigger("change");

            if ($mediaThumbnail.length) {
              $mediaThumbnail.val(thumbnail);
            }

            if ($mediaId.length) {
              $mediaId.val(attributes.id);
            }

            if ($mediaWidth.length) {
              $mediaWidth.val(attributes.width);
            }

            if ($mediaHeight.length) {
              $mediaHeight.val(attributes.height);
            }

            if ($mediaAlt.length) {
              $mediaAlt.val(attributes.alt);
            }

            if ($mediaTitle.length) {
              $mediaTitle.val(attributes.title);
            }

            if ($mediaDescription.length) {
              $mediaDescription.val(attributes.description);
            }

            if (typeof settings.onFileSelect === "function") {
              settings.onFileSelect(attributes);
            }
          });
        }

        wpMediaFrame.open();
      });

      // Remove file.
      $removeButton.on("click", function (e) {
        e.preventDefault();
        $input.val("").trigger("change");

        if (typeof settings.onFileRemove === "function") {
          settings.onFileRemove();
        }
      });

      // Update preview and toggle visibility.
      $input.on("change", function (e) {
        e.preventDefault();
        const fileUrl = $input.val();

        if (fileUrl) {
          $removeButton.removeClass("hidden");

          if ($previewWrap.length) {
            const fileExtension = fileUrl.split(".").pop().toLowerCase();

            if (["jpg", "jpeg", "gif", "png", "svg", "webp"].includes(fileExtension)) {
              $previewImage.attr("src", fileUrl);
              if ($previewWrap.hasClass("hidden")) {
                $previewWrap.removeClass("hidden");
              }
            } else {
              $previewWrap.addClass("hidden");
            }
          }
        } else {
          $removeButton.addClass("hidden");
          $previewWrap.addClass("hidden");
        }
      });
    });
  };

  /**
   * Repeater Field Plugin
   * @param {object} options - Plugin options
   *
   */
  $.fn.csmfFieldRepeater = function (options) {
    const settings = $.extend(
      {
        wrapperSelector: ".csmf--repeater-wrapper",
        itemSelector: ".csmf--repeater-item",
        cloneableItemSelector: ".csmf--repeater-cloneable",
        addButtonSelector: ".csmf--repeater-add",
        cloneButtonSelector: ".csmf--repeater-clone",
        sortButtonSelector: ".csmf--repeater-sort",
        removeButtonSelector: ".csmf--repeater-remove",
      },
      options
    );
    return this.each(function () {
      const $repeater = $(this);
      const $wrapper = $repeater.find(settings.wrapperSelector);
      const $fieldId = $wrapper.data("field-id");

      $wrapper.sortable({
        axis: "y",
        handle: settings.sortButtonSelector,
        helper: "original",
        cursor: "move",
        placeholder: "widget-placeholder",
        update: function (event, ui) {
          nameNestedReplace($wrapper.find(settings.itemSelector), $fieldId);
        },
      });

      var addItem = function () {
        var $currentItem = $(this);
        var $parent = $currentItem.parent().parent();
        var $items = $parent.find(settings.itemSelector);

        if ($items.length < 1) {
          return;
        }

        var $cloneableItem = $items.first();

        if (settings.cloneableItemSelector) {
          $cloneableItem = $parent.find(settings.cloneableItemSelector);
        }

        const $clonedItem = $cloneableItem.clone();

        const cloneableItemSelectorClass = settings.cloneableItemSelector.replace(".", "");

        if ($clonedItem.hasClass(cloneableItemSelectorClass)) {
          $clonedItem.removeClass(cloneableItemSelectorClass);

          $clonedItem.find(':input[name!="_pseudo"]').each(function () {
            this.name = this.name.replace("___", "").replace(`${$fieldId}[0]`, `${$fieldId}[${$items.length}]`);
          });
        }
        // Append new item
        $wrapper.append($clonedItem);
        $clonedItem.csmfInit();

        const $choiceItems = $clonedItem.find(".csmf--choice");
        $choiceItems.each((_, element) => {
          initChoice(element);
        });
      };

      var cloneItem = function () {
        const $parentItem = $(this).closest(settings.itemSelector);
        if ($parentItem) {
          let $cloneRepeaterButtonItem = $parentItem.clone();
          $wrapper.children().eq($parentItem.index()).after($cloneRepeaterButtonItem);
          $cloneRepeaterButtonItem.csmfInit();
          nameNestedReplace($wrapper.find(settings.itemSelector), $fieldId);

          const $choiceItems = $cloneRepeaterButtonItem.find(".csmf--choice");
          $choiceItems.each((_, element) => {
            initChoice(element);
          });
        }
      };

      var removeItem = function () {
        var confirmation = confirm("Are you sure to delete this item?");
        if (confirmation) {
          const $itemToRemove = $(this).closest(settings.itemSelector);
          if ($itemToRemove) {
            $itemToRemove.remove();
          }
        }
      };

      $repeater.on("click", settings.addButtonSelector, addItem);
      $repeater.on("click", settings.cloneButtonSelector, cloneItem);
      $repeater.on("click", settings.removeButtonSelector, removeItem);
    });
  };

  /**
   * Init Plugin
   * @param {object} options - Plugin options
   */
  $.fn.csmfInit = function (options) {
    var settings = $.extend({}, options);

    return this.each(function () {
      var $this = $(this);

      // Avoid for conflicts.
      if (!$this.data("inited")) {
        $this.find(".csmf--field-repeater").csmfFieldRepeater();
        $this.find(".csmf--field-upload").csmfBuilderFileUpload();
        $this.find(".csmf--field-media").csmfBuilderFileUpload();

        $("[data-depends]").csmfDependsOn({
          // Optional settings
          triggerInitial: true,
          debug: true,
        });

        $this.data("inited", true);
        $(document).trigger("csmf--reload-script", $this);
      }
    });
  };

  $(".csmf--builder-init").csmfInit();

  // Animation settings.
  $(".csmf--animation-settings-save").on("click", function (e) {
    var self = $(this);
    var forms = self.closest("form");

    let saveButtonText = self.html();

    $.ajax({
      url: CSMF_ADMIN_LOCALIZE_JS.ajax_url,
      data: {
        action: "csmf_settings_store",
        csmf_nonce: CSMF_ADMIN_LOCALIZE_JS.csmf_nonce,
        option_name: forms.attr("name"),
        form: forms.serialize(),
      },
      type: "POST",
      beforeSend: function beforeSend() {
        self.html("Saving Data...");
      },
      success: function success(response) {},
      complete: function complete(response) {
        self.html(saveButtonText);
      },
      error: function error(err) {},
    });
  });

  // Module settings.
  $(".csmf--module-settings-save").on("click", function (e) {
    e.preventDefault();
    var self = $(this);
    var forms = self.closest("form");
    let saveButtonText = self.html();

    $.ajax({
      url: CSMF_ADMIN_LOCALIZE_JS.ajax_url,
      data: {
        action: "csmf_module_settings_store",
        csmf_nonce: CSMF_ADMIN_LOCALIZE_JS.csmf_nonce,
        option_name: forms.attr("name"),
        form: forms.serialize(),
      },
      type: "POST",
      beforeSend: function beforeSend() {
        self.html("Saving Data...");
      },
      success: function success(response) {},
      complete: function complete(response) {
        self.html(saveButtonText);
      },
      error: function error(err) {},
    });
  });

  // Module settings refresh.
  $(".csmf--module-settings-refresh").on("click", function (e) {
    e.preventDefault();
    var self = $(this);
    var forms = self.closest("form");
    let saveButtonText = self.html();

    $.ajax({
      url: CSMF_ADMIN_LOCALIZE_JS.ajax_url,
      data: {
        action: "csmf_module_settings_refresh",
        csmf_nonce: CSMF_ADMIN_LOCALIZE_JS.csmf_nonce,
        option_name: forms.attr("name"),
      },
      type: "POST",
      beforeSend: function beforeSend() {
        self.html("Saving Data...");
      },
      success: function success(response) {
        window.location.reload();
      },
      complete: function complete(response) {
        self.html(saveButtonText);
      },
    });
  });

  // Module settings reset.
  $(".csmf--module-settings-reset").on("click", function (e) {
    e.preventDefault();
    var self = $(this);
    var forms = self.closest("form");
    let saveButtonText = self.html();

    $.ajax({
      url: CSMF_ADMIN_LOCALIZE_JS.ajax_url,
      data: {
        action: "csmf_module_settings_reset",
        csmf_nonce: CSMF_ADMIN_LOCALIZE_JS.csmf_nonce,
        option_name: forms.attr("name"),
      },
      type: "POST",
      beforeSend: function beforeSend() {
        self.html("Saving Data...");
      },
      success: function success(response) {
        window.location.reload();
      },
      complete: function complete(response) {
        self.html(saveButtonText);
      },
    });
  });

  // Import/Export settings.
  $(".csmf--import").on("click", function (e) {
    e.preventDefault();
    window.wp.ajax
      .post("csmf_import_option", {
        identifier: $(this).data("identifier"),
        option_name: $(this).data("option-name"),
        nonce: $(this).data("nonce"),
        data: $(this).parent().find(".csmf--import-data").val(),
      })
      .done(function (response) {
        window.location.reload(true);
      });
  });

  // Backup Reset settings.
  $(".csmf--reset-backup").on("click", function (e) {
    e.preventDefault();

    window.wp.ajax
      .post("csmf_reset_option", {
        identifier: $(this).data("identifier"),
        option_name: $(this).data("option-name"),
        nonce: $(this).data("nonce"),
      })
      .done(function (response) {
        window.location.reload(true);
      });
  });
})(jQuery, window, document);

/**
 * Tab Manager
 */
class TabManager {
  constructor(container) {
    this.container = container;
    this.tabItem = container.querySelectorAll(".csmf--tab-item");
    this.tabButtons = container.querySelectorAll(".csmf--tab-btn");
    this.arrowButtons = container.querySelectorAll(".csmf--tab-has-children > .csmf--tab-btn");
    this.tabNav = container.querySelector(".csmf--tabs-nav");
    this.tabPanels = container.querySelectorAll(".tab-panel");
    this.isLink = false;

    this.init();
  }

  init() {
    this.isLink = this.tabButtons[0].hasAttribute("href");
    this.setupInitialStates();
    this.bindEvents();
  }

  setupInitialStates() {
    this.initTabNavStates();
    this.updatePanelStates();
    // this.updateTabNavState();
  }

  getUrlHash() {
    return window.location.hash.substring(1);
  }

  initTabNavStates() {
    const hash = this.isLink ? this.getUrlHash() : this.tabButtons[0].getAttribute("data-csmf-tab");
    let activeButton = this.container.querySelector(`.csmf--tab-btn[data-csmf-tab="${hash}"]`);

    if (!activeButton) {
      activeButton = this.container.querySelectorAll(".csmf--tab-btn")[0];
    }

    const parent = activeButton?.parentElement;
    const grandparent = parent?.parentElement?.parentElement;

    // Collapse other tabs
    this.collapseOtherTabs(parent);

    // Handle expansion states
    this.handleExpansionStates(parent, grandparent);

    // Update button states
    this.updateButtonStates(activeButton, grandparent);

    this.tabItem.forEach((item) => {
      if (item.classList.contains("expanded")) {
        const firstTab = item.querySelectorAll(".csmf--tab-btn")[1];
        const firstTabId = firstTab?.getAttribute("data-csmf-tab");

        if (!this.getUrlHash() || this.getUrlHash() === firstTabId) {
          firstTab.classList.add("active");
        }
      }
    });
  }

  bindEvents() {
    // Bind click events to tab buttons
    this.tabButtons.forEach((button) => {
      button.addEventListener("click", (e) => this.handleTabClick(e));
    });

    // Bind click events to arrow buttons
    this.arrowButtons.forEach((button) => {
      button.addEventListener("click", () => this.handleArrowClick(button));
    });
  }

  updateTabNavState() {
    const offset = this.tabNav.getBoundingClientRect().top + 20;
    this.tabNav.style.height = `calc(100vh - ${offset}px)`;
  }

  collapseOtherTabs(activeParent) {
    this.tabButtons.forEach((btn) => {
      if (btn.parentElement !== activeParent) {
        btn.parentElement.classList.remove("expanded");
      }
    });
  }

  handleTabClick(event) {
    const button = event.currentTarget;
    const parent = button.parentElement;
    const grandparent = parent?.parentElement?.parentElement;
    const targetTab = button.getAttribute("data-csmf-tab");

    // Collapse other tabs
    this.collapseOtherTabs(parent);

    // Handle expansion states
    this.handleExpansionStates(parent, grandparent);

    // Update button states
    this.updateButtonStates(button, grandparent);

    // Update panel visibility
    this.updatePanelStates(targetTab);
  }

  handleExpansionStates(parent, grandparent) {
    if (parent?.classList.contains("csmf--tab-has-children") && !parent?.classList.contains("expanded")) {
      parent?.classList.add("expanded");
    }

    if (grandparent?.classList.contains("csmf--tab-has-children") && !grandparent.classList.contains("expanded")) {
      grandparent.classList.add("expanded");
    }
  }

  updateButtonStates(activeButton, grandparent) {
    // Reset all buttons
    this.tabButtons.forEach((btn) => {
      btn.classList.remove("active");
      btn.setAttribute("aria-selected", "false");
    });

    // Set active states
    activeButton?.classList.add("active");
    activeButton?.setAttribute("aria-selected", "true");

    if (grandparent?.classList.contains("expanded")) {
      const firstButton = grandparent.querySelectorAll(".csmf--tab-btn")[0];
      firstButton?.classList.add("active");
    }
  }

  updatePanelStates(targetTab) {
    const activeTab = this.isLink ? this.getUrlHash() : this.tabButtons[0].getAttribute("data-csmf-tab");
    let activePanel = this.container.querySelector(`.tab-panel[data-csmf-tab="${targetTab ?? activeTab}"]`);

    if (!activePanel) {
      activePanel = this.container.querySelectorAll(".tab-panel")[0];
    }

    this.tabPanels.forEach((panel) => {
      panel?.classList.add("hidden");
      panel?.classList.remove("active");
    });

    activePanel?.classList.add("active");
    activePanel?.classList.remove("hidden");
  }

  handleArrowClick(button) {
    const secondButton = button.parentElement.querySelectorAll(".csmf--tab-btn")[1];
    secondButton?.classList.add("active");
  }
}

// Initialize tabs.
document.querySelectorAll("[data-csmf-tabs]").forEach((container) => {
  new TabManager(container);
});

// Initialize Foldable Elements.
document.addEventListener("click", (event) => {
  const handler = event.target.closest(".fold-handler");

  if (!handler) return; // Exit if click wasn't on a fold handler

  try {
    const foldableSection = handler.closest(".csmf--foldable");

    if (!foldableSection) {
      // console.warn("No parent found with class `csmf--foldable`");
      return;
    }

    const isFolded = !foldableSection.classList.contains("folded");
    foldableSection.classList.toggle("folded");

    // Update ARIA attributes for accessibility
    handler.setAttribute("aria-expanded", !isFolded);

    // Dispatch custom event for potential listeners
    foldableSection.dispatchEvent(
      new CustomEvent("foldStateChange", {
        detail: { isFolded },
      })
    );
  } catch (error) {
    // console.error("Error toggling fold state:", error);
  }
});

// Initialize all select elements with the Choices library.
function initChoice(element) {
  // Check if the element has a name attribute and if it does NOT start with "___" (three underscores)
  if (element.name && !element.name.startsWith("___")) {
    new Choices(element, {
      searchEnabled: element.hasAttribute("multiple"),
      removeItemButton: element.hasAttribute("multiple"),
    });
  }
}

// Initialize all multiple select elements.
document.querySelectorAll(".csmf--choice").forEach((element) => {
  initChoice(element);
});
