// Shared UI primitives: Popover, Toast, FieldEditor, etc.

// ─── Toast (singleton) ─────────────────────────
let toastEl = null;
function showToast(msg) {
  if (!toastEl) {
    toastEl = document.createElement('div');
    toastEl.className = 'toast';
    document.body.appendChild(toastEl);
  }
  toastEl.textContent = msg;
  toastEl.classList.add('show');
  clearTimeout(showToast._t);
  showToast._t = setTimeout(() => toastEl.classList.remove('show'), 1800);
}

// ─── Popover ─────────────────────────
function Popover({ anchor, onClose, children, align = 'right' }) {
  const ref = React.useRef();
  const [pos, setPos] = React.useState({ top: 0, left: 0 });

  React.useLayoutEffect(() => {
    if (!anchor) return;
    const r = anchor.getBoundingClientRect();
    const w = ref.current?.offsetWidth || 200;
    const h = ref.current?.offsetHeight || 200;
    // Find the nearest container we should stay inside (modal, or viewport)
    const modal = anchor.closest('.card-modal') || anchor.closest('.modal');
    const cr = modal ? modal.getBoundingClientRect() : { left: 8, right: window.innerWidth - 8, top: 8, bottom: window.innerHeight - 8 };
    let left = align === 'right' ? r.right - w : r.left;
    // Clamp to container, then to viewport
    left = Math.max(cr.left + 4, Math.min(cr.right - w - 4, left));
    left = Math.max(8, Math.min(window.innerWidth - w - 8, left));
    let top = r.bottom + 4;
    // Flip up if overflowing bottom of container
    if (top + h > cr.bottom - 4 && r.top - 4 - h > cr.top + 4) top = r.top - 4 - h;
    setPos({ top, left });
  }, [anchor, align]);

  React.useEffect(() => {
    function down(e) {
      if (ref.current && !ref.current.contains(e.target) && e.target !== anchor) onClose();
    }
    function key(e) {if (e.key === 'Escape') onClose();}
    document.addEventListener('mousedown', down);
    document.addEventListener('keydown', key);
    return () => {
      document.removeEventListener('mousedown', down);
      document.removeEventListener('keydown', key);
    };
  }, [anchor, onClose]);

  return ReactDOM.createPortal(
    <div className="popover" style={{ top: pos.top, left: pos.left }} ref={ref}>
      {children}
    </div>,
    document.body
  );
}

// ─── ContentEditable wrapper that doesn't fight the cursor ────
function Editable({ value, onChange, className = '', placeholder = '', tag: Tag = 'div', autoFocus, ...rest }) {
  const ref = React.useRef();
  React.useEffect(() => {
    if (ref.current && ref.current.textContent !== value) ref.current.textContent = value || '';
  }, [value]);
  React.useEffect(() => {
    if (autoFocus && ref.current) {
      ref.current.focus();
      // place cursor at end
      const range = document.createRange();
      range.selectNodeContents(ref.current);
      range.collapse(false);
      const sel = window.getSelection();
      sel.removeAllRanges();sel.addRange(range);
    }
  }, [autoFocus]);
  return (
    <Tag
      ref={ref}
      contentEditable
      suppressContentEditableWarning
      data-placeholder={placeholder}
      className={className}
      onBlur={(e) => onChange(e.currentTarget.textContent)}
      onKeyDown={(e) => {
        if (e.key === 'Enter' && !e.shiftKey) {e.preventDefault();e.currentTarget.blur();}
        if (e.key === 'Escape') {e.currentTarget.blur();}
      }}
      {...rest} />);


}

// ─── FieldValueEditor: edits a field on a task per type ───
function FieldValueEditor({ field, value, onChange, autoFocus, project }) {
  if (field.type === 'select') {
    return (
      <SelectEditor field={field} value={value} onChange={onChange} project={project} autoFocus={autoFocus} />
    );
  }
  if (field.type === 'multi_select') {
    return <MultiSelectEditor field={field} value={value} onChange={onChange} project={project} autoFocus={autoFocus} />;
  }
  if (field.type === 'date') {
    return <DateEditor value={value} onChange={onChange} autoFocus={autoFocus} />;
  }
  if (field.type === 'number') {
    return <input autoFocus={autoFocus} type="number" value={value ?? ''} onChange={(e) => onChange(e.target.value === '' ? '' : Number(e.target.value))} />;
  }
  if (field.type === 'duration') {
    return <input autoFocus={autoFocus} type="text" placeholder="e.g. 2h 30m" defaultValue={value || ''} onBlur={(e) => onChange(e.target.value)} key={value} />;
  }
  if (field.type === 'checkbox') {
    return <input autoFocus={autoFocus} type="checkbox" checked={!!value} onChange={(e) => onChange(e.target.checked)} />;
  }
  if (field.type === 'url') {
    return <input autoFocus={autoFocus} type="url" placeholder="https://" defaultValue={value || ''} onBlur={(e) => onChange(e.target.value)} key={value} />;
  }
  if (field.type === 'email') {
    return <input autoFocus={autoFocus} type="email" placeholder="name@example.com" defaultValue={value || ''} onBlur={(e) => onChange(e.target.value)} key={value} />;
  }
  if (field.type === 'phone') {
    return <input autoFocus={autoFocus} type="tel" placeholder="+1 …" defaultValue={value || ''} onBlur={(e) => onChange(e.target.value)} key={value} />;
  }
  if (field.type === 'person') {
    return <input autoFocus={autoFocus} type="text" placeholder="Person name" defaultValue={value || ''} onBlur={(e) => onChange(e.target.value)} key={value} />;
  }
  return <input autoFocus={autoFocus} type="text" defaultValue={value || ''} onBlur={(e) => onChange(e.target.value)} key={value} />;
}

// Tint helper — light bg from a base color
function tint(color, pct = 18) {
  return `color-mix(in oklab, ${color} ${pct}%, white)`;
}

// Select editor — shows a "chip-style" trigger button and a styled options popover
function SelectEditor({ field, value, onChange, project, autoFocus }) {
  const [open, setOpen] = React.useState(false);
  const [draft, setDraft] = React.useState('');
  const triggerRef = React.useRef(null);

  // Use field color for the chip; priority is special-cased to use per-priority colors
  const color = field.id === 'priority' && value
    ? (project ? priorityColor(project, value) : field.color)
    : field.color || '#9a948a';

  function commitNew() {
    const v = draft.trim();
    if (v) {
      if (project && !(field.options || []).includes(v)) actions.addFieldOption(project.id, field.id, v);
      onChange(v);
    }
    setDraft('');
    setOpen(false);
  }

  return (
    <>
      <button
        ref={triggerRef}
        autoFocus={autoFocus}
        className={'sel-trigger' + (value ? ' has-value' : '')}
        onClick={(e) => { e.stopPropagation(); setOpen(o => !o); }}
        style={value ? { background: tint(color, 18), color: '#1c1b18', borderColor: 'transparent' } : undefined}
      >
        <span className="sel-trigger-label">{value || <em style={{ color: 'var(--ink-3)' }}>—</em>}</span>
        <span className="sel-trigger-caret">▾</span>
      </button>
      {open && triggerRef.current && (
        <Popover anchor={triggerRef.current} onClose={() => { setOpen(false); setDraft(''); }} align="left">
          <div className="opt-list">
            <div className="opt-item opt-clear" onClick={() => { onChange(''); setOpen(false); }}>
              <em>—</em>
            </div>
            {(field.options || []).map(o => {
              const optColor = field.id === 'priority'
                ? (project ? priorityColor(project, o) : color)
                : color;
              return (
                <div key={o} className={'opt-item' + (o === value ? ' selected' : '')}
                  onClick={() => { onChange(o); setOpen(false); }}>
                  <span className="opt-chip" style={{ background: tint(optColor, 22), color: '#1c1b18' }}>{o}</span>
                </div>
              );
            })}
            {project && (
              <div className="opt-add-row">
                <input
                  className="opt-add-input"
                  placeholder="Add new option…"
                  value={draft}
                  onChange={(e) => setDraft(e.target.value)}
                  onKeyDown={(e) => {
                    if (e.key === 'Enter') { e.preventDefault(); commitNew(); }
                    if (e.key === 'Escape') { setDraft(''); setOpen(false); }
                  }}
                />
                <button className="opt-add-btn" onClick={commitNew} disabled={!draft.trim()}>+</button>
              </div>
            )}
          </div>
        </Popover>
      )}
    </>
  );
}

// Date editor — trigger chip + custom-styled month calendar popover (no native OS picker).
function fmtDateNumeric(value) {
  if (!value) return '';
  const d = new Date(value + 'T00:00:00');
  if (isNaN(d)) return value;
  const dd = String(d.getDate()).padStart(2, '0');
  const mm = String(d.getMonth() + 1).padStart(2, '0');
  return `${dd}.${mm}.${d.getFullYear()}`;
}
function DateEditor({ value, onChange, autoFocus, compact }) {
  const s = useStore();
  const weekStartsMonday = s.weekStartsMonday !== false;
  const [open, setOpen] = React.useState(false);
  const triggerRef = React.useRef(null);
  const [viewMonth, setViewMonth] = React.useState(() => {
    const d = value ? new Date(value + 'T00:00:00') : new Date();
    return isNaN(d) ? new Date() : new Date(d.getFullYear(), d.getMonth(), 1);
  });

  React.useEffect(() => {
    if (!open) return;
    const d = value ? new Date(value + 'T00:00:00') : new Date();
    setViewMonth(isNaN(d) ? new Date() : new Date(d.getFullYear(), d.getMonth(), 1));
  }, [open]);

  function toISO(d) {
    const y = d.getFullYear(), m = String(d.getMonth() + 1).padStart(2, '0'), day = String(d.getDate()).padStart(2, '0');
    return `${y}-${m}-${day}`;
  }
  function pick(d) { onChange(toISO(d)); setOpen(false); }

  const selected = value ? new Date(value + 'T00:00:00') : null;
  const today = new Date(); today.setHours(0, 0, 0, 0);

  const firstOfMonth = new Date(viewMonth.getFullYear(), viewMonth.getMonth(), 1);
  const rawDow = firstOfMonth.getDay();
  const startDow = weekStartsMonday ? (rawDow + 6) % 7 : rawDow;
  const gridStart = new Date(firstOfMonth); gridStart.setDate(1 - startDow);
  const days = Array.from({ length: 42 }, (_, i) => { const d = new Date(gridStart); d.setDate(gridStart.getDate() + i); return d; });
  const dowLabels = weekStartsMonday ? ['M', 'T', 'W', 'T', 'F', 'S', 'S'] : ['S', 'M', 'T', 'W', 'T', 'F', 'S'];

  return (
    <>
      <button
        ref={triggerRef}
        autoFocus={autoFocus}
        type="button"
        className={'sel-trigger date-trigger' + (value ? ' has-value' : '') + (compact ? ' compact' : '')}
        onClick={(e) => { e.stopPropagation(); setOpen(o => !o); }}
      >
        <span className="date-trigger-icon">📅</span>
        <span className="sel-trigger-label">{value ? fmtDateNumeric(value) : <em style={{ color: 'var(--ink-3)' }}>—</em>}</span>
      </button>
      {open && triggerRef.current && (
        <Popover anchor={triggerRef.current} onClose={() => setOpen(false)} align="left">
          <div className="date-pop">
            <div className="date-pop-head">
              <button type="button" className="date-nav" onClick={() => setViewMonth(new Date(viewMonth.getFullYear(), viewMonth.getMonth() - 1, 1))}>‹</button>
              <span className="date-pop-title">{viewMonth.toLocaleDateString(undefined, { month: 'long', year: 'numeric' })}</span>
              <button type="button" className="date-nav" onClick={() => setViewMonth(new Date(viewMonth.getFullYear(), viewMonth.getMonth() + 1, 1))}>›</button>
            </div>
            <div className="date-pop-dow">
              {dowLabels.map((d, i) => <span key={i}>{d}</span>)}
            </div>
            <div className="date-pop-grid">
              {days.map((d, i) => {
                const inMonth = d.getMonth() === viewMonth.getMonth();
                const isToday = d.getTime() === today.getTime();
                const isSelected = selected && d.getTime() === new Date(selected.getFullYear(), selected.getMonth(), selected.getDate()).getTime();
                return (
                  <button type="button" key={i}
                    className={'date-cell' + (inMonth ? '' : ' outside') + (isToday ? ' today' : '') + (isSelected ? ' selected' : '')}
                    onClick={() => pick(d)}>
                    {d.getDate()}
                  </button>
                );
              })}
            </div>
            <div className="date-pop-foot">
              <button type="button" className="add-inline-tiny" onClick={() => pick(new Date())}>Today</button>
              {value && <button type="button" className="add-inline-tiny" onClick={() => { onChange(''); setOpen(false); }}>Clear</button>}
            </div>
          </div>
        </Popover>
      )}
    </>
  );
}

// Multi-select: array of strings; popover with checkable options + free typing.
function MultiSelectEditor({ field, value, onChange, project, autoFocus }) {
  const arr = Array.isArray(value) ? value : value ? [value] : [];
  const [open, setOpen] = React.useState(false);
  const [draft, setDraft] = React.useState('');
  const triggerRef = React.useRef(null);
  const allOptions = field.options || [];
  const color = field.color || '#9a948a';

  function toggle(opt) {
    if (arr.includes(opt)) onChange(arr.filter(v => v !== opt));
    else onChange([...arr, opt]);
  }
  function commitNew() {
    const v = draft.trim();
    if (v) {
      if (project && !allOptions.includes(v)) actions.addFieldOption(project.id, field.id, v);
      if (!arr.includes(v)) onChange([...arr, v]);
    }
    setDraft('');
  }

  return (
    <>
      <button
        ref={triggerRef}
        autoFocus={autoFocus}
        className={'sel-trigger ms-trigger' + (arr.length ? ' has-value' : '')}
        onClick={(e) => { e.stopPropagation(); setOpen(o => !o); }}
      >
        <span className="ms-tags-inline">
          {arr.length === 0 && <em style={{ color: 'var(--ink-3)' }}>—</em>}
          {arr.map(v => (
            <span key={v} className="ms-tag-inline" style={{ background: tint(color, 22), color: '#1c1b18' }}>
              {v}
            </span>
          ))}
        </span>
        <span className="sel-trigger-caret">▾</span>
      </button>
      {open && triggerRef.current && (
        <Popover anchor={triggerRef.current} onClose={() => setOpen(false)} align="left">
          <div className="opt-list">
            {allOptions.map(o => {
              const selected = arr.includes(o);
              return (
                <div key={o} className={'opt-item' + (selected ? ' selected' : '')}
                  onClick={() => toggle(o)}>
                  <span className="opt-check">{selected ? '✓' : ''}</span>
                  <span className="opt-chip" style={{ background: tint(color, 22), color: '#1c1b18' }}>{o}</span>
                </div>
              );
            })}
            {allOptions.length === 0 && <div className="opt-empty">No options yet</div>}
            <div className="opt-add-row">
              <input
                className="opt-add-input"
                placeholder="Add new option…"
                value={draft}
                onChange={(e) => setDraft(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === 'Enter') { e.preventDefault(); commitNew(); }
                  if (e.key === 'Escape') { setDraft(''); setOpen(false); }
                }}
              />
              <button className="opt-add-btn" onClick={commitNew} disabled={!draft.trim()}>+</button>
            </div>
          </div>
        </Popover>
      )}
    </>
  );
}

// ─── Render a field value as a chip (compact) ─────
function FieldChip({ field, value, project }) {
  if (value === undefined || value === '' || value === null) return null;
  if (Array.isArray(value) && value.length === 0) return null;
  const color = field.id === 'priority' && value && project
    ? priorityColor(project, value)
    : field.color || '#9a948a';
  const style = { background: tint(color, 22), color: '#1c1b18', borderColor: 'transparent' };
  if (field.id === 'priority') return (
    <span className="chip" style={style}>
      <span className="prio-dot" style={{ background: color }}></span>{value}
    </span>
  );
  if (field.id === 'start') return <span className="chip" style={style}>▶ {fmtDate(value)}</span>;
  if (field.id === 'due') return <span className="chip" style={style}>📅 {fmtDate(value)}</span>;
  if (field.id === 'est') return <span className="chip" style={style}>⏱ {value}</span>;
  if (field.id === 'remaining') return <span className="chip" style={style}>⌛ {value}</span>;
  if (field.type === 'multi_select') {
    const arr = Array.isArray(value) ? value : [value];
    return <>{arr.slice(0, 3).map((v) => <span key={v} className="chip" style={style}>{v}</span>)}{arr.length > 3 && <span className="chip" style={style}>+{arr.length - 3}</span>}</>;
  }
  if (field.type === 'select') return <span className="chip" style={style}>{value}</span>;
  if (field.type === 'date') return <span className="chip" style={style}>{fmtDate(value)}</span>;
  if (field.type === 'checkbox') return <span className="chip" style={style}>{value ? '✓' : '○'} {field.name}</span>;
  if (field.type === 'person') return <span className="chip" style={style}>👤 {value}</span>;
  if (field.type === 'url') return <span className="chip" style={style}>🔗 link</span>;
  if (field.type === 'email') return <span className="chip" style={style}>✉ {value}</span>;
  return <span className="chip" style={style}>{String(value)}</span>;
}

// ─── ColorSwatchPicker — curated palette popover ─────
function ColorSwatchPicker({ value, onChange, anchor: anchorIn, onClose }) {
  // If used as a controlled popover (anchor + onClose passed), render in popover.
  // If used inline, render as a swatch trigger with internal popover.
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef(null);
  const palette = (window.COLOR_PALETTE) || [];

  if (anchorIn) {
    return (
      <Popover anchor={anchorIn} onClose={onClose} align="left">
        <div className="swatch-grid">
          {palette.map(c => (
            <button key={c.id} title={c.label}
              className={'swatch' + (value === c.color ? ' selected' : '')}
              style={{ background: c.color }}
              onClick={() => { onChange(c.color); onClose && onClose(); }} />
          ))}
        </div>
      </Popover>
    );
  }

  return (
    <>
      <button
        ref={ref}
        type="button"
        className="swatch-trigger"
        style={{ background: value || '#9a948a' }}
        title="Pick color"
        onClick={(e) => { e.stopPropagation(); setOpen(o => !o); }}
      />
      {open && ref.current && (
        <Popover anchor={ref.current} onClose={() => setOpen(false)} align="left">
          <div className="swatch-grid">
            {palette.map(c => (
              <button key={c.id} title={c.label}
                className={'swatch' + (value === c.color ? ' selected' : '')}
                style={{ background: c.color }}
                onClick={() => { onChange(c.color); setOpen(false); }} />
            ))}
          </div>
        </Popover>
      )}
    </>
  );
}

// ─── PromptDialog: modal text-input replacement for window.prompt() ───
// Electron does not implement window.prompt() (it silently no-ops), so any
// "type a name" flow must use this instead of the native browser API.
function PromptDialog({ title, placeholder, initialValue = '', confirmLabel = 'Create', onConfirm, onCancel }) {
  const [value, setValue] = React.useState(initialValue);
  function submit() {
    const v = value.trim();
    if (v) onConfirm(v);
  }
  return (
    <div className="modal-backdrop" onClick={onCancel} style={{ zIndex: 300 }}>
      <div className="modal small" onClick={(e) => e.stopPropagation()}>
        <div className="modal-head">
          <span>{title}</span>
          <button className="btn-ghost btn" onClick={onCancel}>✕</button>
        </div>
        <div className="modal-body">
          <input autoFocus className="fc-name" placeholder={placeholder} value={value}
            onChange={(e) => setValue(e.target.value)}
            onKeyDown={(e) => {
              if (e.key === 'Enter') { e.preventDefault(); submit(); }
              if (e.key === 'Escape') onCancel();
            }} />
        </div>
        <div className="modal-foot">
          <button className="btn btn-ghost" onClick={onCancel}>Cancel</button>
          <button className="btn" disabled={!value.trim()} onClick={submit}>{confirmLabel}</button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { showToast, Popover, Editable, FieldValueEditor, FieldChip, ColorSwatchPicker, DateEditor, tint, PromptDialog });