// app-notes.jsx — NotesEditor: textarea with motion chips + inline shorthand expansion
(function () {
  const { useRef, useCallback } = React;
  const { MOTIONS, CLAUSES, INLINE, PLACEHOLDER } = window.MeetingData;

  // Insert `text` into a textarea at the caret, replacing the {{}} marker with
  // PLACEHOLDER and returning the [start,end] range of that placeholder so the
  // caller can select it. Handles spacing so words don't run together.
  function spliceTemplate(el, template, onChange) {
    const value = el.value;
    let start = el.selectionStart;
    let end = el.selectionEnd;

    const markerIndex = template.indexOf("{{}}");
    let out = template.replace("{{}}", PLACEHOLDER);

    // pad with a leading space if mid-sentence, trailing handled by caller
    const before = value.slice(0, start);
    const needsLeadSpace = before.length > 0 && !/\s$/.test(before);
    if (needsLeadSpace) out = " " + out;

    const after = value.slice(end);
    const needsTrailSpace = after.length > 0 && !/^\s/.test(after);
    if (needsTrailSpace) out = out + " ";

    const newValue = before + out + after;
    onChange(newValue);

    // compute placeholder selection range
    const lead = needsLeadSpace ? 1 : 0;
    const phStart = start + lead + (markerIndex >= 0 ? markerIndex : out.length);
    const phEnd = phStart + PLACEHOLDER.length;

    requestAnimationFrame(() => {
      el.focus();
      try { el.setSelectionRange(phStart, phEnd); } catch (e) {}
    });
  }

  // Insert a vote clause before the trailing period of the current sentence.
  function insertClause(el, clause, onChange) {
    const value = el.value;
    const caret = el.selectionStart;
    // find the period that ends the sentence the caret is in / nearest before
    const upto = value.slice(0, caret);
    const lastPeriod = upto.lastIndexOf(".");
    let insertAt;
    if (lastPeriod >= 0 && lastPeriod === upto.length - 1) {
      insertAt = lastPeriod; // caret right after a period -> put clause before it
    } else {
      const nextPeriod = value.indexOf(".", caret);
      insertAt = nextPeriod >= 0 ? nextPeriod : caret;
    }
    const text = clause.replace("{{}}", PLACEHOLDER);
    const newValue = value.slice(0, insertAt) + text + value.slice(insertAt);
    onChange(newValue);
    const phRel = text.indexOf(PLACEHOLDER);
    const phStart = insertAt + phRel;
    requestAnimationFrame(() => {
      el.focus();
      try { el.setSelectionRange(phStart, phStart + PLACEHOLDER.length); } catch (e) {}
    });
  }

  // Inline expansion: when user types a space right after a known shorthand,
  // expand it. Called from onChange after detecting the trigger.
  function tryInlineExpand(el, value, onChange) {
    const caret = el.selectionStart;
    // only when the char just typed is a space
    if (value[caret - 1] !== " ") return false;
    const before = value.slice(0, caret - 1); // without the trailing space
    const m = before.match(/(^|[\s(])((?:m\/s\/[ucf])|tabled)$/i);
    if (!m) return false;
    const code = m[2].toLowerCase();
    const motion = INLINE[code];
    if (!motion) return false;

    const codeStart = caret - 1 - m[2].length;
    const newBefore = value.slice(0, codeStart);
    const after = value.slice(caret); // text after the space we typed
    let expanded = motion.template.replace("{{}}", PLACEHOLDER);
    const needLead = newBefore.length > 0 && !/\s$/.test(newBefore);
    if (needLead) expanded = " " + expanded;

    const newValue = newBefore + expanded + after;
    onChange(newValue);
    const lead = needLead ? 1 : 0;
    const phStart = codeStart + lead + motion.template.indexOf("{{}}");
    requestAnimationFrame(() => {
      el.focus();
      try { el.setSelectionRange(phStart, phStart + PLACEHOLDER.length); } catch (e) {}
    });
    return true;
  }

  function NotesEditor({ value, onChange, placeholder }) {
    const ref = useRef(null);

    const handleChange = useCallback((e) => {
      const el = ref.current;
      const v = e.target.value;
      // attempt inline expansion; if it fires it calls onChange itself
      if (tryInlineExpand(el, v, onChange)) return;
      onChange(v);
    }, [onChange]);

    return (
      <div className="notes-editor">
        <div className="chip-row" role="toolbar" aria-label="Motion shortcuts">
          <span className="chip-row__label">Insert motion</span>
          {MOTIONS.map((mo) => (
            <button
              key={mo.code}
              type="button"
              className="chip chip--motion"
              title={mo.hint + "  ·  type \"" + mo.code.toLowerCase() + "\" + space to expand inline"}
              onMouseDown={(e) => e.preventDefault()}
              onClick={() => spliceTemplate(ref.current, mo.template, onChange)}
            >
              <span className="chip__code">{mo.code}</span>
              <span className="chip__label">{mo.label}</span>
            </button>
          ))}
          <span className="chip-row__divider" aria-hidden="true"></span>
          {CLAUSES.map((c) => (
            <button
              key={c.code}
              type="button"
              className="chip chip--clause"
              title={"Add \u201c" + c.clause.trim().replace(PLACEHOLDER, "n") + "\u201d to the motion"}
              onMouseDown={(e) => e.preventDefault()}
              onClick={() => insertClause(ref.current, c.clause, onChange)}
            >
              {c.label}
            </button>
          ))}
        </div>
        <textarea
          ref={ref}
          className="notes-textarea"
          value={value}
          onChange={handleChange}
          placeholder={placeholder || "Record discussion, motions, and resolutions\u2026"}
          spellCheck={true}
          rows={3}
        />
        <div className="notes-hint">
          Tip — type <kbd>m/s/u</kbd>, <kbd>m/s/c</kbd>, <kbd>m/s/f</kbd> or <kbd>tabled</kbd> then <kbd>space</kbd> to auto-expand. The highlighted <span className="ph-demo">{PLACEHOLDER}</span> is yours to fill in.
        </div>
      </div>
    );
  }

  window.NotesEditor = NotesEditor;
})();
