/* ============================================================
   ui.js — UI utility layer
   ------------------------------------------------------------
   DOM helpers, modal manager, toast, escape utilities.
   Keeps app.js focused on state & behavior.
   ============================================================ */
(function (global) {
  'use strict';

  /* ---- DOM helpers ---- */
  function $(sel, root) { return (root || document).querySelector(sel); }
  function $all(sel, root) { return Array.prototype.slice.call((root || document).querySelectorAll(sel)); }

  function el(tag, attrs, children) {
    var node = document.createElement(tag);
    if (attrs) {
      for (var k in attrs) {
        if (!Object.prototype.hasOwnProperty.call(attrs, k)) continue;
        var v = attrs[k];
        if (k === 'class') node.className = v;
        else if (k === 'text') node.textContent = v;
        else if (k === 'html') node.innerHTML = v;
        else if (k === 'dataset') { for (var d in v) node.dataset[d] = v[d]; }
        else if (k.slice(0, 2) === 'on' && typeof v === 'function') {
          node.addEventListener(k.slice(2).toLowerCase(), v);
        } else if (v !== null && v !== undefined && v !== false) {
          node.setAttribute(k, v === true ? '' : v);
        }
      }
    }
    appendChildren(node, children);
    return node;
  }

  function appendChildren(node, children) {
    if (children == null) return;
    if (Array.isArray(children)) {
      children.forEach(function (c) { appendChildren(node, c); });
    } else if (typeof children === 'string' || typeof children === 'number') {
      node.appendChild(document.createTextNode(String(children)));
    } else if (children instanceof Node) {
      node.appendChild(children);
    }
  }

  function clear(node) { while (node.firstChild) node.removeChild(node.firstChild); return node; }

  // Escape text for safe insertion
  function esc(str) {
    if (str == null) return '';
    return String(str)
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#39;');
  }

  /* ---- Avatar ---- */
  // Pick a deterministic avatar color & initials
  var AVA_PALETTE = [
    ['#6366f1', '#4338ca'],
    ['#ec4899', '#be185d'],
    ['#14b8a6', '#0f766e'],
    ['#f59e0b', '#b45309'],
    ['#8b5cf6', '#6d28d9'],
    ['#ef4444', '#b91c1c'],
    ['#0ea5e9', '#0369a1'],
    ['#22c55e', '#15803d']
  ];
  function initials(firstName, lastName, fallback) {
    var f = (firstName || '').trim();
    var l = (lastName || '').trim();
    if (f && l) return (f[0] + l[0]);
    if (f) return f.slice(0, 2);
    if (l) return l.slice(0, 2);
    if (fallback) return fallback.slice(0, 2);
    return '؟';
  }
  function avatarStyle(seed) {
    var h = 0;
    var s = String(seed || '');
    for (var i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) >>> 0;
    var pair = AVA_PALETTE[h % AVA_PALETTE.length];
    return 'background: linear-gradient(135deg, ' + pair[0] + ', ' + pair[1] + ');';
  }

  /* ---- Toast ---- */
  var toastTimer = null;
  var toastEl = null;
  function toast(message, type) {
    if (!toastEl) toastEl = $('#toast');
    toastEl.hidden = false;
    toastEl.className = 'toast' + (type ? ' toast--' + type : '');
    toastEl.innerHTML = '';
    var icon = el('svg', { class: 'icon', viewBox: '0 0 24 24', html: type === 'success'
      ? '<path d="M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>'
      : type === 'error'
        ? '<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>'
        : '<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>' });
    toastEl.appendChild(icon);
    toastEl.appendChild(document.createTextNode(message));
    // force reflow then show
    void toastEl.offsetWidth;
    toastEl.classList.add('show');

    clearTimeout(toastTimer);
    toastTimer = setTimeout(function () {
      toastEl.classList.remove('show');
      setTimeout(function () { toastEl.hidden = true; }, 200);
    }, 3200);
  }

  /* ---- Modal manager ---- */
  // Returns helpers to open/close a named modal + focus trap-ish behavior
  function openModal(id) {
    var m = $('#' + id);
    if (!m) return null;
    m.hidden = false;
    document.body.style.overflow = 'hidden';
    // Focus first focusable element
    setTimeout(function () {
      var focusable = m.querySelector('input:not([type=hidden]):not([readonly]), select, textarea, button.primary-btn, button.danger-btn');
      if (focusable) focusable.focus();
    }, 50);
    return m;
  }
  function closeModal(id) {
    var m = (typeof id === 'string') ? $('#' + id) : id;
    if (!m) return;
    m.hidden = true;
    // If no other modal open, restore scroll
    if (!$all('.modal').some(function (x) { return !x.hidden; })) {
      document.body.style.overflow = '';
    }
  }
  function closeAllModals() {
    $all('.modal').forEach(function (m) { m.hidden = true; });
    document.body.style.overflow = '';
    var dp = $('#datepicker');
    if (dp) dp.hidden = true;
  }

  /* ---- Confirm dialog (promise-based, resolves false on dismissal) ---- */
  // The confirm modal has its own [data-close] buttons + backdrop. We hook
  // BOTH the OK button and any dismissal to resolve the promise exactly once.
  var confirmState = { resolve: null, modal: null };
  function confirm(opts) {
    return new Promise(function (resolve) {
      $('#confirm-title').textContent = opts.title || 'تأیید';
      $('#confirm-msg').textContent = opts.message || '';
      var okBtn = $('#confirm-ok');
      okBtn.className = 'danger-btn' + (opts.okClass === 'primary' ? ' primary-btn' : '');
      okBtn.textContent = opts.okText || 'تأیید';
      confirmState.resolve = resolve;
      confirmState.modal = openModal('confirm-modal');
    });
  }
  // Resolve exactly once (used by both OK and dismissal paths).
  function resolveConfirm(value) {
    if (!confirmState.resolve) return;
    var fn = confirmState.resolve;
    confirmState.resolve = null;
    confirmState.modal = null;
    fn(value);
  }
  // OK button -> true
  document.addEventListener('click', function (e) {
    if (e.target.closest('#confirm-ok')) {
      closeModal('confirm-modal');
      resolveConfirm(true);
    }
  });
  // Dismissal (backdrop/close) inside the confirm modal -> false
  document.addEventListener('click', function (e) {
    if (confirmState.resolve && e.target.closest('#confirm-modal [data-close]')) {
      closeModal('confirm-modal');
      resolveConfirm(false);
    }
  }, true);

  /* ---- Copy to clipboard ---- */
  function copyText(text) {
    if (navigator.clipboard && navigator.clipboard.writeText) {
      return navigator.clipboard.writeText(text);
    }
    return new Promise(function (resolve, reject) {
      var ta = document.createElement('textarea');
      ta.value = text;
      ta.style.position = 'fixed';
      ta.style.opacity = '0';
      document.body.appendChild(ta);
      ta.select();
      try { document.execCommand('copy'); resolve(); } catch (e) { reject(e); }
      document.body.removeChild(ta);
    });
  }

  /* ---- Debounce ---- */
  function debounce(fn, wait) {
    var t = null;
    return function () {
      var ctx = this, args = arguments;
      clearTimeout(t);
      t = setTimeout(function () { fn.apply(ctx, args); }, wait);
    };
  }

  /* ---- Public ---- */
  global.UI = {
    $: $,
    $$: $all,
    el: el,
    clear: clear,
    esc: esc,
    initials: initials,
    avatarStyle: avatarStyle,
    toast: toast,
    openModal: openModal,
    closeModal: closeModal,
    closeAllModals: closeAllModals,
    confirm: confirm,
    copyText: copyText,
    debounce: debounce
  };

})(window);
