/* ========================================================================
   FILTER WIDGET — floating left panel: saved-search combobox + field list.
   Port of renderFieldList / renderSavedSearchCombo / openSsPopover.
   ======================================================================== */

/* ---- saved-search actions (from 06-render.js) --------------------------- */
function loadSavedSearch(id) {
  const ss = findSavedSearch(id);
  if (!ss) return;
  if (ss.entity) state.entity = ss.entity;
  state.filters = ss.filterSpecs.map(spec => ({
    id: uid(),
    fieldId: spec.fieldId,
    op: spec.op,
    value: deepClone(spec.value),
  }));
  state.activeSavedSearchId = id;
  state.openFieldId = null;
  state.editorAnchor = null;
  notify();
}
function clearActiveSavedSearch() {
  state.activeSavedSearchId = null;
  state.filters = [];
  state.openFieldId = null;
  state.editorAnchor = null;
  notify();
}
function isSavedSearchDirty() {
  if (!state.activeSavedSearchId) return false;
  const ss = findSavedSearch(state.activeSavedSearchId);
  if (!ss) return false;
  const cur = state.filters.filter(isFilterComplete);
  const specs = ss.filterSpecs || [];
  if (cur.length !== specs.length) return true;
  const sigA = cur.map(f => JSON.stringify([f.fieldId, f.op, f.value])).sort();
  const sigB = specs.map(s => JSON.stringify([s.fieldId, s.op, s.value])).sort();
  for (let i = 0; i < sigA.length; i++) if (sigA[i] !== sigB[i]) return true;
  return false;
}
function updateActiveSavedSearch() {
  if (!state.activeSavedSearchId) return;
  const ss = findSavedSearch(state.activeSavedSearchId);
  if (!ss) return;
  const cur = state.filters.filter(isFilterComplete);
  ss.filterSpecs = cur.map(f => ({ fieldId: f.fieldId, op: f.op, value: deepClone(f.value) }));
  ss.entity = state.entity;
  try {
    ss.count = applyFilters(datasetFor(state.entity), state.filters, state.entity).length;
  } catch (_) {}
  notify();
}

/* ---- saved-search combobox ------------------------------------------------ */
function SavedSearchCombo() {
  useAppState();
  const [open, setOpen] = React.useState(false);
  const wrapRef = React.useRef(null);
  const active = state.activeSavedSearchId ? findSavedSearch(state.activeSavedSearchId) : null;
  const dirty = isSavedSearchDirty();

  React.useEffect(() => {
    if (!open) return;
    const onDown = (e) => {
      if (wrapRef.current && wrapRef.current.contains(e.target)) return;
      setOpen(false);
    };
    document.addEventListener('mousedown', onDown);
    return () => document.removeEventListener('mousedown', onDown);
  }, [open]);

  // Group searches by folder; un-foldered last.
  const groups = [];
  if (open) {
    const byFolder = new Map();
    SAVED_SEARCH_FOLDERS.forEach(f => byFolder.set(f, []));
    byFolder.set(null, []);
    SAVED_SEARCHES.forEach(s => {
      const f = s.folder || null;
      if (!byFolder.has(f)) byFolder.set(f, []);
      byFolder.get(f).push(s);
    });
    for (const [folder, list] of byFolder) {
      if (list.length) groups.push([folder, list]);
    }
  }

  return (
    <div className="ss-section" ref={wrapRef}>
      <div className="ss-row">
        <div className="ss-combo-wrap">
          <button
            className={cx('ss-combo', active && 'active')} type="button" aria-haspopup="listbox"
            onClick={() => setOpen(o => !o)}
          >
            <Icon name="bookmark" size={14} className="ss-combo-icon" />
            <span className="ss-combo-text">{active ? active.name : 'Open saved search…'}</span>
            <Icon name="chevron-down" size={12} className="ss-combo-chev" />
          </button>
          {active ? (
            <button
              className="ss-clear" type="button" aria-label="Clear active saved search"
              onClick={(e) => { e.stopPropagation(); setOpen(false); clearActiveSavedSearch(); }}
            ><Icon name="x" size={12} /></button>
          ) : null}
        </div>
        {active && dirty ? (
          <button
            className="ss-update-btn" type="button"
            title="Update saved search to match current filters"
            onClick={(e) => { e.stopPropagation(); updateActiveSavedSearch(); }}
          ><Icon name="refresh-cw" size={12} />Update</button>
        ) : null}
      </div>
      {open ? (
        <div className="ss-popover">
          {groups.length === 0 ? <div className="ss-empty">No saved searches yet.</div> : null}
          {groups.map(([folder, list]) => (
            <React.Fragment key={folder || '__unfiled'}>
              <div className="ss-folder-header">
                <Icon name={folder ? 'folder' : 'bookmark'} size={11} />
                {folder || 'Unfiled'}
              </div>
              {list.map(s => (
                <div
                  key={s.id}
                  className={cx('ss-item', state.activeSavedSearchId === s.id && 'active')}
                  onClick={() => { setOpen(false); loadSavedSearch(s.id); }}
                >
                  <span className="ss-item-name">{s.name}</span>
                  <span className="ss-item-meta">{s.count}</span>
                </div>
              ))}
            </React.Fragment>
          ))}
        </div>
      ) : null}
    </div>
  );
}

/* ---- field list ------------------------------------------------------------ */
function FieldList({ panel }) {
  useAppState();
  const st = fpState();
  const _opts = (panel && panel.opts) || {};
  const fpHide = (f) => typeof _opts.hideField === 'function' ? _opts.hideField(f) : false;
  const fpLocked = (f) => _opts.lockedFieldIds ? _opts.lockedFieldIds.has(f.id) : false;

  const counts = {};
  st.filters.filter(isFilterComplete).forEach(f => {
    counts[f.fieldId] = (counts[f.fieldId] || 0) + filterParamCount(f);
  });

  const signalLocked = hasSignalFilter();
  const contactLocked = hasContactFilter();
  const disableContactFields = st.entity === 'signals' || signalLocked;
  const disableSignalFields = st.entity === 'contacts' || contactLocked;
  const ordered = orderFieldsFor(st.entity);
  const isFieldDisabled = (f) =>
    (disableContactFields && f.entity === 'contacts') ||
    (disableSignalFields && f.entity === 'signals');

  const groups = [];
  const gmap = {};
  ordered.forEach(f => {
    if (fpHide(f)) return;
    const g = displayGroup(f, st.entity);
    if (!gmap[g]) { gmap[g] = []; groups.push(g); }
    gmap[g].push(f);
  });

  const psAvailable = (kind) => typeof presetSaveAvailable === 'function' && presetSaveAvailable(kind);

  return (
    <div className="fw-items">
      {groups.map(g => (
        <React.Fragment key={g}>
          <div className="fl-section">{g}</div>
          {gmap[g].map(f => {
            const isRelated = f.entity !== st.entity;
            const locked = fpLocked(f);
            const isDisabled = isFieldDisabled(f) || locked;
            let reason;
            if (isDisabled) {
              if (locked) reason = 'Locked by the template — inherited and read-only';
              else if (f.entity === 'contacts') {
                reason = signalLocked
                  ? 'Contact filters aren\u2019t available with a Signal filter applied'
                  : 'Contact filters aren\u2019t available while browsing Signals';
              } else {
                reason = contactLocked
                  ? 'Signal filters aren\u2019t available with a Contact filter applied'
                  : 'Signal filters aren\u2019t available while browsing Contacts';
              }
            }
            let savePreset = null;
            if (!panel && !isDisabled && f.id === 'account.target' && psAvailable('target')) savePreset = 'target';
            else if (!panel && !isDisabled && f.id === 'contact.persona' && psAvailable('persona')) savePreset = 'persona';
            return (
              <button
                key={f.id}
                className={cx('fl-item',
                  counts[f.id] && 'active',
                  st.openFieldId === f.id && 'open',
                  isRelated && 'related',
                  locked && 'fl-item--locked',
                  isDisabled && 'disabled')}
                data-field-id={f.id}
                disabled={isDisabled || undefined}
                aria-disabled={isDisabled ? 'true' : undefined}
                data-helper-tip={isDisabled ? reason : undefined}
                onClick={isDisabled ? undefined : (e) => {
                  const saveEl = e.target.closest('[data-save-preset]');
                  if (saveEl) {
                    e.preventDefault(); e.stopPropagation();
                    if (typeof openSavePresetDialog === 'function') openSavePresetDialog(saveEl.dataset.savePreset);
                    return;
                  }
                  openFilterForField(f.id, e.currentTarget);
                }}
              >
                <span className="fl-glyph"><Icon name={locked ? 'lock' : f.icon} size={13} /></span>
                <span className="fl-name">{displayLabel(f, st.entity)}</span>
                {counts[f.id] ? <span className="fl-count">{counts[f.id]}</span> : null}
                {savePreset ? (
                  <span
                    className="fl-save" data-save-preset={savePreset} role="button" tabIndex={0}
                    title={savePreset === 'target' ? 'Save current filters as a Profile' : 'Save current filters as a Persona'}
                  ><Icon name="bookmark-plus" size={11} /> Save</span>
                ) : null}
              </button>
            );
          })}
        </React.Fragment>
      ))}
    </div>
  );
}

/* ---- the widget -------------------------------------------------------------- */
function FilterWidget({ children }) {
  useAppState();
  const committed = state.filters.filter(isFilterComplete);
  return (
    <div className="floating-widget-spacer">
      <div className="floating-widget">
        <div className="fw-toolbar">
          <span className="fw-toolbar-title">
            <Icon name="filter" size={14} style={{ color: 'var(--muted-foreground)' }} />
            Filter columns
          </span>
          <button
            className="fw-toolbar-action"
            disabled={committed.length === 0}
            onClick={committed.length > 0 ? clearAll : undefined}
          >Clear all</button>
        </div>
        <SavedSearchCombo />
        <FieldList />
        {children /* records-nav slot (detail mode) */}
      </div>
    </div>
  );
}

Object.assign(window, {
  FilterWidget, FieldList, SavedSearchCombo,
  loadSavedSearch, clearActiveSavedSearch, isSavedSearchDirty, updateActiveSavedSearch,
});
