(function (window, document) {
  'use strict';

  const DEFAULT_MAX_LENGTH = 160;
  const DEFAULT_NOTE_LABELS = {
    addToggle: 'Add note',
    editToggle: 'Edit note',
    addButton: 'Add',
    cancelButton: 'Cancel',
    deleteButton: 'Delete',
    displayLabel: 'Note',
    placeholder: 'Add a note (max {max} characters)',
    error: 'Could not update the note. Please try again.'
  };

  const NOTE_LABELS = (function () {
    const localized = (window.foodordCartNotesLabels && typeof window.foodordCartNotesLabels === 'object') ? window.foodordCartNotesLabels : {};
    return Object.assign({}, DEFAULT_NOTE_LABELS, localized);
  })();

  const CONTEXT_CONFIG = {
    desktop: {
      wrapper: 'wr-card__item-note',
      toggle: 'wr-card__note-toggle',
      form: 'wr-card__note-form',
      counter: 'wr-card__note-counter',
      input: 'wr-card__note-input',
      actions: 'wr-card__note-actions',
      cancel: 'wr-card__note-btn wr-card__note-btn--cancel',
      save: 'wr-card__note-btn wr-card__note-btn--add',
      display: 'wr-card__note-display',
      label: 'wr-card__note-display-label',
      text: 'wr-card__note-display-text',
      feedback: 'wr-card__note-feedback'
    },
    mobile: {
      wrapper: 'foodord-mobile-cart__note',
      toggle: 'foodord-mobile-cart__note-toggle',
      form: 'foodord-mobile-cart__note-form',
      counter: 'foodord-mobile-cart__note-counter',
      input: 'foodord-mobile-cart__note-input',
      actions: 'foodord-mobile-cart__note-actions',
      cancel: 'foodord-mobile-cart__note-btn foodord-mobile-cart__note-btn--cancel',
      save: 'foodord-mobile-cart__note-btn foodord-mobile-cart__note-btn--add',
      display: 'foodord-mobile-cart__note-display',
      label: 'foodord-mobile-cart__note-label',
      text: 'foodord-mobile-cart__note-text',
      feedback: 'foodord-mobile-cart__note-feedback'
    }
  };

  const tempDiv = document.createElement('div');

  const escapeHtml = (value) => {
    if (value === null || value === undefined) {
      return '';
    }
    tempDiv.textContent = String(value);
    return tempDiv.innerHTML;
  };

  const getMaxLength = () => {
    const raw = window.foodord_modal_vars && window.foodord_modal_vars.note_max_length;
    const parsed = Number(raw);
    if (Number.isFinite(parsed) && parsed > 0) {
      return Math.min(parsed, DEFAULT_MAX_LENGTH);
    }
    return DEFAULT_MAX_LENGTH;
  };

  const MAX_LENGTH = getMaxLength();

  const getRemainingLength = (value) => {
    const length = value ? String(value).length : 0;
    return Math.max(0, MAX_LENGTH - length);
  };

  const formatCounter = (value) => {
    return getRemainingLength(value) + '/' + MAX_LENGTH;
  };

  const buildFieldId = (context, item) => {
    let base = '';
    if (item && item.cart_item_key) {
      base = String(item.cart_item_key);
    } else if (item && item.product_id) {
      base = String(item.product_id);
    }
    base = base.replace(/[^a-zA-Z0-9_-]/g, '');
    if (!base) {
      base = Math.random().toString(36).slice(2);
    }
    return (context === 'mobile' ? 'foodord-mobile-note-' : 'foodord-note-') + base;
  };

  const buildToggleMarkup = (item, context) => {
    const cfg = CONTEXT_CONFIG[context] || CONTEXT_CONFIG.desktop;
    const note = item && typeof item.note === 'string' ? item.note : '';
    const hasNote = note.length > 0;

    return '<button type="button" class="' + cfg.toggle + '" data-foodord-note-action="toggle">' + (hasNote ? NOTE_LABELS.editToggle : NOTE_LABELS.addToggle) + '</button>';
  };

  const buildMarkup = (item, context, options) => {
    const cfg = CONTEXT_CONFIG[context] || CONTEXT_CONFIG.desktop;
    const note = item && typeof item.note === 'string' ? item.note : '';
    const hasNote = note.length > 0;
    const id = buildFieldId(context, item || {});
    const name = item && item.name ? item.name : 'item';
    const opts = options && typeof options === 'object' ? options : {};
    const includeToggle = opts.includeToggle !== false;
    const wrapperClass = cfg.wrapper + (hasNote ? ' has-note' : '');

    return (
      '<div class="' + wrapperClass + '" data-foodord-note-wrapper data-note-context="' + context + '">' +
        (includeToggle ? buildToggleMarkup(item, context) : '') +
        '<div class="' + cfg.form + '" data-foodord-note-form hidden>' +
          '<label class="screen-reader-text" for="' + id + '">' + NOTE_LABELS.addToggle + ' for ' + escapeHtml(name) + '</label>' +
          '<div class="' + cfg.counter + '" data-foodord-note-counter aria-hidden="true">' + formatCounter(note) + '</div>' +
          '<textarea id="' + id + '" class="' + cfg.input + '" data-foodord-note-input maxlength="' + MAX_LENGTH + '">' + escapeHtml(note) + '</textarea>' +
          '<div class="' + cfg.actions + '">' +
            '<button type="button" class="' + cfg.cancel + '" data-foodord-note-action="cancel">' + NOTE_LABELS.cancelButton + '</button>' +
            '<button type="button" class="' + cfg.save + '" data-foodord-note-action="save">' + NOTE_LABELS.addButton + '</button>' +
          '</div>' +
        '</div>' +
        '<div class="' + cfg.display + '" data-foodord-note-display' + (hasNote ? '' : ' hidden') + '>' +
          '<p class="' + cfg.text + '" data-foodord-note-text>' + escapeHtml(note) + '</p>' +
        '</div>' +
        '<div class="' + cfg.feedback + '" data-foodord-note-feedback aria-live="polite"></div>' +
      '</div>'
    );
  };

  const setFeedback = (container, message, type) => {
    const feedback = container.querySelector('[data-foodord-note-feedback]');
    if (!feedback) {
      return;
    }
    feedback.textContent = message || '';
    if (!message) {
      container.removeAttribute('data-note-feedback');
      return;
    }
    container.setAttribute('data-note-feedback', type || 'error');
  };

  const updateCounter = (container) => {
    const input = container.querySelector('[data-foodord-note-input]');
    const counter = container.querySelector('[data-foodord-note-counter]');
    if (!input || !counter) {
      return;
    }
    counter.textContent = formatCounter(input.value || '');
  };

  const findToggleButton = (container) => {
    const toggleBtn = container.querySelector('[data-foodord-note-action="toggle"]');
    if (toggleBtn) {
      return toggleBtn;
    }

    const itemEl = getItemElement(container);
    if (!itemEl) {
      return null;
    }

    return itemEl.querySelector('[data-foodord-note-action="toggle"]');
  };

  const setLoadingState = (container, isLoading) => {
    const saveBtn = container.querySelector('[data-foodord-note-action="save"]');
    const cancelBtn = container.querySelector('[data-foodord-note-action="cancel"]');
    const toggleBtn = findToggleButton(container);

    if (saveBtn) {
      saveBtn.disabled = !!isLoading;
    }
    if (cancelBtn) {
      cancelBtn.disabled = !!isLoading;
    }
    if (toggleBtn) {
      toggleBtn.disabled = !!isLoading && container.classList.contains('is-editing');
    }

    if (isLoading) {
      container.setAttribute('data-note-saving', '1');
    } else {
      container.removeAttribute('data-note-saving');
    }
  };

  const updateToggleLabel = (container, note) => {
    const toggleBtn = findToggleButton(container);
    if (!toggleBtn) {
      return;
    }
    toggleBtn.textContent = note ? NOTE_LABELS.editToggle : NOTE_LABELS.addToggle;
  };

  const applyNoteToContainer = (container, note) => {
    const display = container.querySelector('[data-foodord-note-display]');
    const text = container.querySelector('[data-foodord-note-text]');
    const form = container.querySelector('[data-foodord-note-form]');
    const input = container.querySelector('[data-foodord-note-input]');
    const cancelBtn = container.querySelector('[data-foodord-note-action="cancel"]');

    if (text) {
      text.textContent = note || '';
    }
    if (display) {
      display.hidden = !note;
    }
    if (form) {
      form.hidden = true;
    }
    if (input) {
      input.value = note || '';
      updateCounter(container);
    }
    if (cancelBtn) {
      cancelBtn.textContent = NOTE_LABELS.cancelButton;
    }

    container.classList.toggle('has-note', !!note);
    container.classList.remove('is-editing');
    updateToggleLabel(container, note);
    setFeedback(container, '');
  };

  const openForm = (container, note) => {
    const form = container.querySelector('[data-foodord-note-form]');
    const display = container.querySelector('[data-foodord-note-display]');
    const input = container.querySelector('[data-foodord-note-input]');
    const cancelBtn = container.querySelector('[data-foodord-note-action="cancel"]');

    container.classList.add('is-editing');
    if (form) {
      form.hidden = false;
    }
    if (display) {
      display.hidden = true;
    }
    if (input) {
      input.value = note || '';
      updateCounter(container);
    }
    if (cancelBtn) {
      cancelBtn.textContent = note ? NOTE_LABELS.deleteButton : NOTE_LABELS.cancelButton;
    }
    updateToggleLabel(container, note);
    setFeedback(container, '');
  };

  const closeForm = (container, note) => {
    const form = container.querySelector('[data-foodord-note-form]');
    const display = container.querySelector('[data-foodord-note-display]');

    container.classList.remove('is-editing');
    if (form) {
      form.hidden = true;
    }
    if (display) {
      display.hidden = !note;
    }
    updateToggleLabel(container, note);
    setFeedback(container, '');
  };

  const sendNoteUpdate = (cartItemKey, note) => {
    const ajaxVars = window.foodord_modal_vars || {};
    const url = ajaxVars.ajax_url || window.ajaxurl || '/wp-admin/admin-ajax.php';
    const nonce = ajaxVars.nonce || '';

    const payload = new URLSearchParams();
    payload.append('action', 'foodord_update_cart_item_note');
    payload.append('nonce', nonce);
    payload.append('cart_item_key', cartItemKey);
    payload.append('note', note);

    if (window.fetch) {
      return window.fetch(url, {
        method: 'POST',
        credentials: 'same-origin',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
        },
        body: payload.toString()
      }).then((response) => {
        if (!response.ok) {
          throw new Error('Request failed');
        }
        return response.json();
      }).then((data) => {
        if (!data || data.success !== true) {
          const errorMessage = data && data.data ? data.data : NOTE_LABELS.error;
          throw new Error(errorMessage);
        }
        return data.data || {};
      });
    }

    if (typeof window.jQuery !== 'undefined') {
      return new Promise((resolve, reject) => {
        window.jQuery.post(url, payload.toString(), (data) => {
          if (!data || data.success !== true) {
            const errorMessage = data && data.data ? data.data : NOTE_LABELS.error;
            reject(new Error(errorMessage));
            return;
          }
          resolve(data.data || {});
        }).fail(() => reject(new Error(NOTE_LABELS.error)));
      });
    }

    return Promise.reject(new Error('Fetch API not available.'));
  };

  const pendingRequests = {};

  const requestNoteUpdate = (cartItemKey, note) => {
    if (pendingRequests[cartItemKey]) {
      return pendingRequests[cartItemKey];
    }

    const promise = sendNoteUpdate(cartItemKey, note)
      .finally(() => {
        delete pendingRequests[cartItemKey];
      });

    pendingRequests[cartItemKey] = promise;
    return promise;
  };

  const updateContainersForKey = (cartItemKey, note) => {
    const items = document.querySelectorAll('[data-cart-item-key]');
    items.forEach((itemEl) => {
      if (itemEl.getAttribute('data-cart-item-key') !== cartItemKey) {
        return;
      }
      itemEl.setAttribute('data-note', note || '');
      const container = itemEl.querySelector('[data-foodord-note-wrapper]');
      if (!container) {
        return;
      }
      applyNoteToContainer(container, note);
    });
  };

  const getItemElement = (element) => {
    if (!element) {
      return null;
    }
    return element.closest('[data-cart-item-key]');
  };

  const handleToggle = (button) => {
    let container = button.closest('[data-foodord-note-wrapper]');
    const itemEl = container ? getItemElement(container) : getItemElement(button);
    if (!container && itemEl) {
      container = itemEl.querySelector('[data-foodord-note-wrapper]');
    }
    if (!container || !itemEl) {
      return;
    }
    const note = itemEl.getAttribute('data-note') || '';
    if (container.classList.contains('is-editing')) {
      closeForm(container, note);
      if (typeof button.blur === 'function') {
        button.blur();
      }
      return;
    }
    openForm(container, note);
    if (typeof button.blur === 'function') {
      button.blur();
    }
  };

  const handleCancel = (button) => {
    const container = button.closest('[data-foodord-note-wrapper]');
    const itemEl = getItemElement(container);
    if (!container || !itemEl) {
      return;
    }
    const note = itemEl.getAttribute('data-note') || '';
    if (!note) {
      closeForm(container, note);
      return;
    }

    const cartItemKey = itemEl.getAttribute('data-cart-item-key');
    if (!cartItemKey) {
      closeForm(container, note);
      return;
    }

    setLoadingState(container, true);
    requestNoteUpdate(cartItemKey, '')
      .then((data) => {
        const normalized = data && typeof data.note === 'string' ? data.note : '';
        updateContainersForKey(cartItemKey, normalized);
      })
      .catch((error) => {
        setFeedback(container, error && error.message ? error.message : NOTE_LABELS.error);
      })
      .finally(() => {
        setLoadingState(container, false);
      });
  };

  const handleSave = (button) => {
    const container = button.closest('[data-foodord-note-wrapper]');
    const itemEl = getItemElement(container);
    if (!container || !itemEl) {
      return;
    }

    const input = container.querySelector('[data-foodord-note-input]');
    if (!input) {
      return;
    }

    let note = input.value || '';
    note = note.trim();
    if (note.length > MAX_LENGTH) {
      note = note.slice(0, MAX_LENGTH);
      input.value = note;
      updateCounter(container);
    }

    const cartItemKey = itemEl.getAttribute('data-cart-item-key');
    if (!cartItemKey) {
      setFeedback(container, NOTE_LABELS.error);
      return;
    }

    setLoadingState(container, true);
    requestNoteUpdate(cartItemKey, note)
      .then((data) => {
        const normalized = data && typeof data.note === 'string' ? data.note : '';
        updateContainersForKey(cartItemKey, normalized);
      })
      .catch((error) => {
        setFeedback(container, error && error.message ? error.message : NOTE_LABELS.error);
      })
      .finally(() => {
        setLoadingState(container, false);
      });
  };

  const handleAction = (target) => {
    const actionEl = target.closest('[data-foodord-note-action]');
    if (!actionEl) {
      return;
    }

    const action = actionEl.getAttribute('data-foodord-note-action');
    if ('toggle' === action) {
      handleToggle(actionEl);
    } else if ('cancel' === action) {
      handleCancel(actionEl);
    } else if ('save' === action) {
      handleSave(actionEl);
    }
  };

  document.addEventListener('click', (event) => {
    handleAction(event.target);
  });

  document.addEventListener('input', (event) => {
    if (!event.target || !event.target.matches('[data-foodord-note-input]')) {
      return;
    }
    const container = event.target.closest('[data-foodord-note-wrapper]');
    if (!container) {
      return;
    }
    updateCounter(container);
  });

  document.addEventListener('keydown', (event) => {
    if (event.key !== 'Escape') {
      return;
    }
    const container = event.target && event.target.closest && event.target.closest('[data-foodord-note-wrapper].is-editing');
    if (!container) {
      return;
    }
    const itemEl = getItemElement(container);
    if (!itemEl) {
      return;
    }
    event.stopPropagation();
    event.preventDefault();
    const note = itemEl.getAttribute('data-note') || '';
    closeForm(container, note);
  });

  window.FoodordCartNotes = window.FoodordCartNotes || {
    renderNoteMarkup(item, context, options) {
      return buildMarkup(item || {}, context || 'desktop', options);
    },
    renderNoteToggleMarkup(item, context) {
      return buildToggleMarkup(item || {}, context || 'desktop');
    },
    updateContainers: updateContainersForKey,
    getMaxLength() {
      return MAX_LENGTH;
    }
  };
})(window, document);
