/* Loadpath — shared UI atoms. Exported to window for cross-file use. */
(function () {
  const { Icon } = window;
  const h = React.createElement;
  const { useState, useEffect, useRef } = React;

  function Btn({ kind = 'secondary', size, icon, iconRight, children, block, ...rest }) {
    const cls = ['btn', 'btn-' + kind, size ? 'btn-' + size : '', block ? 'btn-block' : '']
      .filter(Boolean).join(' ');
    return h('button', { className: cls, ...rest },
      icon && h(Icon, { name: icon, size: size === 'sm' ? 14 : 16 }),
      children,
      iconRight && h(Icon, { name: iconRight, size: size === 'sm' ? 14 : 16 }));
  }

  const STATUS = {
    PASS:   { cls: 'badge-pass', icon: 'check', label: 'PASS' },
    FAIL:   { cls: 'badge-fail', icon: 'x', label: 'FAIL' },
    EXEMPT: { cls: 'badge-exempt', icon: 'info', label: 'EXEMPT' },
    WARN:   { cls: 'badge-warn', icon: 'alert-triangle', label: 'FLAG' },
  };
  function Status({ s, label }) {
    const m = STATUS[s] || STATUS.PASS;
    return h('span', { className: 'badge badge-mono ' + m.cls },
      h(Icon, { name: m.icon, size: 12 }), label || m.label);
  }

  const PROJ_STATUS = {
    delivered:    { cls: 'badge-pass', label: 'Delivered', icon: 'check' },
    in_progress:  { cls: 'badge-accent', label: 'In progress', icon: 'clock' },
    sistering:    { cls: 'badge-warn', label: 'Sistering', icon: 'wrench' },
    rejected:     { cls: 'badge-fail', label: 'Rejected', icon: 'x' },
    missing_info: { cls: 'badge-neutral', label: 'Needs info', icon: 'alert-triangle' },
    draft:        { cls: 'badge-neutral', label: 'Draft', icon: 'clock' },
  };
  function ProjStatus({ s }) {
    const m = PROJ_STATUS[s] || PROJ_STATUS.draft;
    return h('span', { className: 'badge ' + m.cls }, h(Icon, { name: m.icon, size: 12 }), m.label);
  }

  function Badge({ kind = 'neutral', icon, mono, children }) {
    return h('span', { className: 'badge badge-' + kind + (mono ? ' badge-mono' : '') },
      icon && h(Icon, { name: icon, size: 12 }), children);
  }

  function ConfDot({ level }) {
    const cls = level === 'high' ? 'conf-high' : level === 'med' ? 'conf-med' : 'conf-low';
    const label = level === 'high' ? 'High confidence' : level === 'med' ? 'Medium — verify' : 'Low — flagged';
    return h('span', { className: 'conf-dot ' + cls, title: label });
  }

  function SrcTag({ sheet }) { return h('span', { className: 'srctag' }, sheet); }

  // DCR bar with the 1.00 gate marker
  function DCRBar({ dcr, animate = true }) {
    const [w, setW] = React.useState(animate ? 0 : Math.min(dcr, 1.25));
    React.useEffect(() => {
      if (!animate) return;
      const t = setTimeout(() => setW(Math.min(dcr, 1.25)), 60);
      return () => clearTimeout(t);
    }, [dcr, animate]);
    const over = dcr > 1.0;
    const warnish = dcr > 0.85 && dcr <= 1.0;
    const fillCls = over ? 'over' : warnish ? 'warnish' : 'ok';
    // bar scaled so 1.0 sits at 80% of track (gate marker), allowing overflow display
    const pct = (w / 1.25) * 100;
    return h('div', { className: 'dcr-cell' },
      h('div', { className: 'dcr-bar' },
        h('div', { className: 'dcr-fill ' + fillCls, style: { width: pct + '%' } }),
        h('div', { className: 'gate', style: { left: '80%' } })),
      h('span', { className: 'dcr-num', style: { color: over ? 'var(--signal-danger)' : 'var(--fg)' } },
        dcr.toFixed(3)));
  }

  function Callout({ kind = 'info', icon, title, children }) {
    const defIcon = { info: 'info', warn: 'alert-triangle', danger: 'alert-octagon', success: 'check-circle', accent: 'sparkles' }[kind];
    return h('div', { className: 'callout callout-' + kind },
      h(Icon, { name: icon || defIcon, size: 18 }),
      h('div', null, title && h('div', { className: 'ct-title' }, title), h('p', null, children)));
  }

  function KV({ k, children }) {
    return h('div', { className: 'kv' }, h('span', { className: 'k' }, k), h('span', { className: 'v' }, children));
  }

  function Card({ title, eyebrow, right, tight, className, children }) {
    return h('div', { className: 'card' + (tight ? ' card-tight' : '') + (className ? ' ' + className : '') },
      (title || eyebrow || right) && h('div', { className: 'card-head' },
        h('div', null,
          eyebrow && h('div', { className: 'eyebrow', style: { marginBottom: title ? 4 : 0 } }, eyebrow),
          title && h('h3', null, title)),
        right),
      children);
  }

  function Money({ amount, size }) {
    if (amount == null) return h('span', { className: 'num' }, '—');
    const [d, c] = amount.toFixed(2).split('.');
    return h('span', { className: 'quote-amount' + (size ? ' ' + size : '') },
      '$', d, h('span', { className: 'quote-cents' }, '.' + c));
  }

  // ─── Address autocomplete (server-side proxy, no Maps JS needed) ─────────────
  function AddressInput({ value, onChange, onFill, placeholder, className, required, style }) {
    const [suggestions, setSuggestions] = useState([]);
    const [open, setOpen] = useState(false);
    const [busy, setBusy] = useState(false);
    const [active, setActive] = useState(-1);
    const timer = useRef(null);
    const wrap = useRef(null);

    useEffect(() => {
      function outside(e) {
        if (wrap.current && !wrap.current.contains(e.target)) setOpen(false);
      }
      document.addEventListener('mousedown', outside);
      return () => document.removeEventListener('mousedown', outside);
    }, []);

    function search(q) {
      clearTimeout(timer.current);
      if (!q || q.length < 2) { setSuggestions([]); setOpen(false); return; }
      setBusy(true);
      timer.current = setTimeout(async () => {
        try {
          const r = await fetch('/api/v1/places/autocomplete?q=' + encodeURIComponent(q));
          const d = await r.json();
          const list = (d.data && d.data.suggestions) || d.suggestions || [];
          setSuggestions(list);
          setOpen(list.length > 0);
        } catch (_) {}
        setBusy(false);
      }, 320);
    }

    async function pick(s) {
      setOpen(false);
      setSuggestions([]);
      onChange && onChange({ target: { value: s.description } });
      try {
        const r = await fetch('/api/v1/places/details?place_id=' + encodeURIComponent(s.place_id));
        const d = await r.json();
        onFill && onFill(d.data || d);
      } catch (_) {}
    }

    function onKey(e) {
      if (!open) return;
      if (e.key === 'ArrowDown') { e.preventDefault(); setActive(i => Math.min(i + 1, suggestions.length - 1)); }
      else if (e.key === 'ArrowUp') { e.preventDefault(); setActive(i => Math.max(i - 1, 0)); }
      else if (e.key === 'Enter' && active >= 0) { e.preventDefault(); pick(suggestions[active]); }
      else if (e.key === 'Escape') { setOpen(false); }
    }

    return h('div', { ref: wrap, style: { position: 'relative', flex: 1 } },
      h('input', {
        className: className || 'input',
        style,
        value: value || '',
        onChange: e => { onChange && onChange(e); search(e.target.value); },
        onKeyDown: onKey,
        placeholder,
        required,
        autoComplete: 'off',
        spellCheck: false,
      }),
      busy && h('span', {
        style: { position: 'absolute', right: 10, top: '50%', transform: 'translateY(-50%)', pointerEvents: 'none' }
      }, h('span', { className: 'spin', style: { width: 14, height: 14 } })),
      open && suggestions.length > 0 && h('ul', {
        style: {
          position: 'absolute', top: 'calc(100% + 3px)', left: 0, right: 0, zIndex: 999,
          background: 'var(--surface, #fff)', border: '1px solid var(--border, #e4e7ee)',
          borderRadius: 8, boxShadow: '0 8px 28px rgba(0,0,0,.13)',
          padding: '4px 0', margin: 0, listStyle: 'none',
        }
      },
        suggestions.map((s, i) =>
          h('li', {
            key: s.place_id,
            onMouseDown: e => { e.preventDefault(); pick(s); },
            onMouseEnter: () => setActive(i),
            style: {
              padding: '9px 14px', cursor: 'pointer', fontSize: 14,
              display: 'flex', gap: 8, alignItems: 'center',
              background: i === active ? 'var(--surface-2, #f5f7fa)' : 'transparent',
              color: 'var(--fg, #13171c)',
            },
          },
            h(Icon, { name: 'map-pin', size: 13, style: { color: 'var(--accent, #c77d1e)', flexShrink: 0, marginTop: 1 } }),
            h('span', null,
              h('span', { style: { fontWeight: 500 } }, s.main_text || s.description),
              s.secondary_text && h('span', { style: { color: 'var(--fg-subtle, #9ba3b2)', marginLeft: 5, fontSize: 12.5 } }, s.secondary_text))))));
  }

  // ─── ProjectNameEditor ───────────────────────────────────────────────────────
  // Inline edit: click pencil → name becomes an input field + ✓/✗ buttons.
  // No popup/portal needed — works inside any overflow container.
  function ProjectNameEditor({ projectId, name, onSaved, style, textStyle }) {
    const [editing, setEditing] = useState(false);
    const [value, setValue] = useState(name || '');
    const [saving, setSaving] = useState(false);
    const inputRef = useRef(null);

    useEffect(() => { setValue(name || ''); }, [name]);
    useEffect(() => {
      if (editing && inputRef.current) { inputRef.current.focus(); inputRef.current.select(); }
    }, [editing]);

    const open = (e) => { e.stopPropagation(); setValue(name || ''); setEditing(true); };
    const cancel = (e) => { if (e) e.stopPropagation(); setEditing(false); };

    const save = async (e) => {
      if (e) e.stopPropagation();
      const v = value.trim();
      if (!v) return;
      setSaving(true);
      try {
        const updated = await window.API.projects.rename(projectId, v);
        const newName = (updated && (updated.name || (updated.project && updated.project.name))) || v;
        setEditing(false);
        if (onSaved) onSaved(newName);
      } catch (_) {}
      setSaving(false);
    };

    const onKey = (e) => {
      e.stopPropagation();
      if (e.key === 'Enter') save(e);
      if (e.key === 'Escape') cancel(e);
    };

    if (editing) {
      return h('span', { style: Object.assign({ display: 'inline-flex', alignItems: 'center', gap: 4 }, style),
        onClick: (e) => e.stopPropagation() },
        h('input', {
          ref: inputRef, value,
          onChange: (e) => setValue(e.target.value),
          onKeyDown: onKey,
          style: {
            padding: '2px 6px', fontSize: 'inherit', fontWeight: 'inherit',
            borderRadius: 4, border: '1px solid var(--accent, #c77d1e)',
            background: 'var(--surface, #fff)', color: 'var(--fg)',
            outline: 'none', minWidth: 120, maxWidth: 240,
          },
        }),
        h('button', {
          onClick: save, disabled: saving, title: 'Save',
          style: { background: 'none', border: 'none', cursor: 'pointer', padding: '2px 3px', lineHeight: 0, color: 'var(--accent)' },
        }, saving ? h('span', { className: 'spin', style: { width: 12, height: 12, borderWidth: 1.5 } }) : h(Icon, { name: 'check', size: 14 })),
        h('button', {
          onClick: cancel, title: 'Cancel',
          style: { background: 'none', border: 'none', cursor: 'pointer', padding: '2px 3px', lineHeight: 0, color: 'var(--fg-muted)' },
        }, h(Icon, { name: 'x', size: 14 })));
    }

    return h('span', { style: Object.assign({ display: 'inline-flex', alignItems: 'center', gap: 5 }, style) },
      h('span', { style: textStyle }, name || 'New Project'),
      h('button', {
        onClick: open, title: 'Rename project',
        style: { background: 'none', border: 'none', padding: '2px 3px', cursor: 'pointer', lineHeight: 0, opacity: 0.45, borderRadius: 4, display: 'inline-flex', alignItems: 'center' },
      }, h(Icon, { name: 'pencil', size: 12 })));
  }

  // engineerTypeLabel maps the internal engineer_type letter (A/B/C — still
  // the matching key used everywhere in project data) to the human-readable
  // system name shown in the UI. Purely cosmetic.
  function engineerTypeLabel(t) {
    switch (String(t || '').trim().toUpperCase()) {
      case 'A': return 'Roof Mounted';
      case 'B': return 'Ground Mount';
      case 'C': return 'Battery';
      default: return 'Engineer ' + t;
    }
  }

  Object.assign(window, { Btn, Status, ProjStatus, Badge, ConfDot, SrcTag, DCRBar, Callout, KV, Card, Money, AddressInput, ProjectNameEditor, engineerTypeLabel });
})();
