// Author: Sam Lautenbach — Motor Row (offerlaneauto.com)
/* listings.jsx — Motor Row marketplace inventory, shown first on the home page.
   Anyone can browse. Only approved sellers (Google accounts on the server's ADMIN_EMAILS list)
   can sign in — via the "Seller login" link in the footer — to post, edit, mark sold or remove cars.
   Loaded BEFORE app.bundle.jsx so <CarsForSale /> exists when App renders.
   Uses Icon / Field / VehiclePicker / MiniSpin / olMoney from app.bundle at render time. */
const { useState: useStateC, useEffect: useEffectC, useRef: useRefC, useCallback: useCallbackC } = React;

/* ------------------------------ api ------------------------------ */
async function cfsApi(path, opts = {}) {
  const res = await fetch(path, {
    credentials: 'same-origin',
    headers: opts.body ? { 'Content-Type': 'application/json' } : undefined,
    ...opts,
    body: opts.body ? JSON.stringify(opts.body) : undefined,
  });
  let data = {};
  try { data = await res.json(); } catch (e) {}
  if (!res.ok) {
    const msg = typeof data.error === 'string' && data.error.includes(' ') ? data.error : 'Something went wrong. Please try again.';
    const err = new Error(msg); err.status = res.status; err.code = data.error; throw err;
  }
  return data;
}

/* ------------------------------ staff auth ------------------------------ */
let _cfsGisPromise = null;
function cfsLoadGis() {
  if (window.google && window.google.accounts && window.google.accounts.id) return Promise.resolve();
  if (_cfsGisPromise) return _cfsGisPromise;
  _cfsGisPromise = new Promise((resolve, reject) => {
    const s = document.createElement('script');
    s.src = 'https://accounts.google.com/gsi/client';
    s.async = true; s.defer = true;
    s.onload = () => resolve();
    s.onerror = () => { _cfsGisPromise = null; reject(new Error('gis_load_failed')); };
    document.head.appendChild(s);
  });
  return _cfsGisPromise;
}

function useCfsAuth() {
  const [state, setState] = useStateC({ loading: true, user: null, clientId: '' });
  useEffectC(() => {
    Promise.all([cfsApi('/api/me'), cfsApi('/api/config')])
      .then(([me, cfg]) => setState({ loading: false, user: me.user, clientId: cfg.googleClientId }))
      .catch(() => setState({ loading: false, user: null, clientId: '' }));
  }, []);
  const setUser = (user) => setState(s => ({ ...s, user }));
  const signOut = async () => {
    try { await cfsApi('/api/auth/logout', { method: 'POST' }); } catch (e) {}
    try { window.google && window.google.accounts.id.disableAutoSelect(); } catch (e) {}
    setUser(null);
  };
  return { ...state, setUser, signOut };
}

function CfsGoogleButton({ clientId, onSignedIn }) {
  const ref = useRefC(null);
  const [err, setErr] = useStateC('');
  useEffectC(() => {
    if (!clientId) { setErr('Google sign-in isn’t set up yet.'); return; }
    let alive = true;
    cfsLoadGis().then(() => {
      if (!alive || !ref.current) return;
      window.google.accounts.id.initialize({
        client_id: clientId,
        callback: async (resp) => {
          setErr('');
          try {
            const r = await cfsApi('/api/auth/google', { method: 'POST', body: { credential: resp.credential } });
            onSignedIn(r.user);
          } catch (e) {
            setErr(e.status === 403
              ? 'That Google account isn’t an approved seller. This login is only for dealers Motor Row has approved.'
              : 'Sign-in didn’t go through. Please try again.');
            try { window.google.accounts.id.disableAutoSelect(); } catch (e2) {}
          }
        },
      });
      window.google.accounts.id.renderButton(ref.current, {
        theme: 'outline', size: 'large', shape: 'pill', text: 'signin_with', logo_alignment: 'left', width: 300,
      });
    }).catch(() => alive && setErr('Couldn’t reach Google. Check your connection and try again.'));
    return () => { alive = false; };
  }, [clientId]);
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12 }}>
      <div ref={ref} style={{ minHeight: 44 }} />
      {err && <div role="alert" style={{ color: '#B23A12', fontSize: 13.5, fontWeight: 600, lineHeight: 1.45 }}>{err}</div>}
    </div>
  );
}

/* ------------------------------ shared bits ------------------------------ */
let _cfsModalSeq = 0;
const CFS_FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]):not([type=hidden]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
function CfsModal({ title, onClose, children, width = 640 }) {
  const boxRef = useRefC(null);
  const [titleId] = useStateC(() => 'cfs-modal-title-' + (++_cfsModalSeq));
  useEffectC(() => {
    const opener = document.activeElement;
    const box = boxRef.current;
    // Move focus into the dialog, keep Tab inside it, and put it back where it was on close.
    const first = box && box.querySelector(CFS_FOCUSABLE);
    (first || box).focus({ preventScroll: true });
    const onKey = (e) => {
      if (e.key === 'Escape') { e.preventDefault(); onClose(); return; }
      if (e.key !== 'Tab' || !box) return;
      const items = [...box.querySelectorAll(CFS_FOCUSABLE)].filter(el => el.offsetParent !== null);
      if (!items.length) { e.preventDefault(); box.focus(); return; }
      const a = items[0], z = items[items.length - 1];
      if (e.shiftKey && (document.activeElement === a || document.activeElement === box)) { e.preventDefault(); z.focus(); }
      else if (!e.shiftKey && document.activeElement === z) { e.preventDefault(); a.focus(); }
    };
    document.addEventListener('keydown', onKey);
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    const main = document.getElementById('page');
    if (main) main.setAttribute('aria-hidden', 'true');
    return () => {
      document.removeEventListener('keydown', onKey);
      document.body.style.overflow = prev;
      if (main) main.removeAttribute('aria-hidden');
      if (opener && opener.focus && document.contains(opener)) opener.focus({ preventScroll: true });
    };
  }, []);
  let host = document.getElementById('modals');
  if (!host) { host = document.createElement('div'); host.id = 'modals'; document.body.appendChild(host); }
  return ReactDOM.createPortal(
    <div role="presentation"
      onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}
      style={{ position: 'fixed', inset: 0, zIndex: 100, background: 'rgba(5,32,77,.55)', display: 'grid', placeItems: 'center', padding: 16, animation: 'olFade .15s ease' }}>
      <div ref={boxRef} role="dialog" aria-modal="true" aria-labelledby={titleId} tabIndex={-1}
        style={{ background: '#fff', borderRadius: 'var(--r-lg)', width: '100%', maxWidth: width, maxHeight: 'calc(100vh - 32px)', overflow: 'auto', boxShadow: 'var(--shadow-lg)', animation: 'olRise .2s ease', outline: 'none' }}>
        <div style={{ position: 'sticky', top: 0, background: '#fff', zIndex: 2, display: 'flex', alignItems: 'center', gap: 12, padding: '18px 22px', borderBottom: '1px solid var(--line-soft)' }}>
          <h2 id={titleId} style={{ fontSize: 20, fontWeight: 800, color: 'var(--navy)', textTransform: 'uppercase', flex: 1 }}>{title}</h2>
          <button type="button" onClick={onClose} aria-label="Close dialog" style={{ color: 'var(--ink-soft)', padding: 8, borderRadius: 10, minWidth: 44, minHeight: 44, display: 'grid', placeItems: 'center' }}><Icon.close s={22} /></button>
        </div>
        <div style={{ padding: 22 }}>{children}</div>
      </div>
    </div>,
    host
  );
}

const cfsMiles = (n) => (n == null ? '' : Number(n).toLocaleString('en-US') + ' mi');
const cfsTitle = (l) => [l.year, l.make, l.model].filter(Boolean).join(' ');
function cfsAgo(ts) {
  const d = Math.floor((Date.now() - ts) / 864e5);
  if (d <= 0) return 'Today';
  if (d === 1) return 'Yesterday';
  if (d < 30) return d + ' days ago';
  return new Date(ts).toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
}
const CFS_SPEC_LABELS = { exterior_color: 'Exterior', interior_color: 'Interior', transmission: 'Transmission', drivetrain: 'Drivetrain', engine: 'Engine', fuel: 'Fuel', body: 'Body style', doors: 'Doors', certified: 'Certified' };
const cfsSpecRows = (l) => [...(l.stockNumber ? [['Stock #', l.stockNumber]] : []), ...Object.entries(l.specs || {}).filter(([k, v]) => CFS_SPEC_LABELS[k] && v).map(([k, v]) => [CFS_SPEC_LABELS[k], v === true ? 'Yes' : String(v)])];
const cfsStore = {
  get(k) { try { return localStorage.getItem(k) || ''; } catch (e) { return ''; } },
  set(k, v) { try { localStorage.setItem(k, v); } catch (e) {} },
};

/* Resize in the browser so phone photos upload fast and the server stores small files. */
function cfsResizePhoto(file, maxSide = 1600, quality = 0.82) {
  return new Promise((resolve, reject) => {
    const url = URL.createObjectURL(file);
    const img = new Image();
    img.onload = () => {
      const scale = Math.min(1, maxSide / Math.max(img.width, img.height));
      const c = document.createElement('canvas');
      c.width = Math.round(img.width * scale); c.height = Math.round(img.height * scale);
      c.getContext('2d').drawImage(img, 0, 0, c.width, c.height);
      URL.revokeObjectURL(url);
      resolve(c.toDataURL('image/jpeg', quality));
    };
    img.onerror = () => { URL.revokeObjectURL(url); reject(new Error('bad_image')); };
    img.src = url;
  });
}

/* ------------------------------ card ------------------------------ */
function CfsCard({ l, onOpen }) {
  const sold = l.status === 'sold';
  return (
    <a href={'/cars/' + encodeURIComponent(l.id)} onClick={(e) => { if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) return; e.preventDefault(); onOpen(l); }} className="cfs-card"
      aria-label={`${cfsTitle(l)}${l.trim ? ' ' + l.trim : ''}, ${olMoney(l.price)}${l.mileage != null ? ', ' + cfsMiles(l.mileage) : ''}${sold ? ', sold' : ''}. Listed by ${l.seller.name}. View details`}
      style={{
      color: 'inherit', textDecoration: 'none', width: '100%',
      textAlign: 'left', background: '#fff', border: '1px solid var(--line)', borderRadius: 'var(--r-md)', overflow: 'hidden',
      display: 'flex', flexDirection: 'column', boxShadow: 'var(--shadow-sm)', transition: 'transform .12s ease, box-shadow .15s ease',
    }}>
      <div style={{ position: 'relative', aspectRatio: '4 / 3', background: 'var(--blue-tint)' }}>
        {l.photos[0]
          ? <img src={l.photos[0]} alt={cfsTitle(l)} loading="lazy" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block', filter: sold ? 'grayscale(.7)' : 'none' }} />
          : <div style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', color: 'var(--muted)', fontSize: 13, fontWeight: 700 }}>Photos coming soon</div>}
        {l.photos.length > 1 && (
          <span style={{ position: 'absolute', right: 10, bottom: 10, background: 'rgba(5,32,77,.78)', color: '#fff', fontSize: 12, fontWeight: 700, padding: '4px 9px', borderRadius: 999 }}>{l.photos.length} photos</span>
        )}
        {sold && <span style={{ position: 'absolute', left: 10, top: 10, background: 'var(--navy)', color: '#fff', fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 12, letterSpacing: '.08em', padding: '5px 10px', borderRadius: 999 }}>SOLD</span>}
      </div>
      <div style={{ padding: '14px 16px 16px', display: 'flex', flexDirection: 'column', gap: 6, flex: 1 }}>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 17, color: 'var(--ink)', lineHeight: 1.2 }}>
          {cfsTitle(l)}{l.trim ? <span style={{ fontWeight: 600, color: 'var(--ink-soft)' }}> {l.trim}</span> : null}
        </div>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 22, color: 'var(--green-600)' }}>{olMoney(l.price)}</div>
        <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', color: 'var(--ink-soft)', fontSize: 13.5, fontWeight: 600, marginTop: 'auto' }}>
          {l.mileage != null && <span>{cfsMiles(l.mileage)}</span>}
          {(l.city || l.zip) && <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}><Icon.pin s={13} />{l.city || l.zip}</span>}
          <span style={{ marginLeft: 'auto', color: 'var(--muted)', fontWeight: 500 }}>{cfsAgo(l.createdAt)}</span>
        </div>
        <div style={{ fontSize: 12.5, color: 'var(--muted)', fontWeight: 600 }}>Listed by {l.seller.name}</div>
      </div>
    </a>
  );
}

/* ------------------------------ detail ------------------------------ */
function CfsDetail({ l, staff, onClose, onChanged, onEdit }) {
  const [i, setI] = useStateC(0);
  const [busy, setBusy] = useStateC(false);
  const [err, setErr] = useStateC('');
  const [confirmRemove, setConfirmRemove] = useStateC(false);
  const photos = l.photos;
  useEffectC(() => { if (i >= photos.length) setI(0); }, [photos.length]);
  const act = async (fn) => { setBusy(true); setErr(''); try { await fn(); } catch (e) { setErr(e.message); } setBusy(false); };
  const setStatus = (status) => act(async () => { const r = await cfsApi('/api/listings/' + l.id, { method: 'PATCH', body: { status } }); onChanged(r.listing); });
  const remove = () => act(async () => { await cfsApi('/api/listings/' + l.id, { method: 'DELETE' }); onChanged(null, l.id); onClose(); });

  return (
    <CfsModal title={cfsTitle(l)} onClose={onClose} width={760}>
      {photos.length > 0 && (
        <div style={{ marginBottom: 18 }}>
          <div style={{ position: 'relative', aspectRatio: '16 / 10', background: '#0B1A33', borderRadius: 'var(--r-md)', overflow: 'hidden' }}>
            <img src={photos[i] || photos[0]} alt={`${cfsTitle(l)} photo ${i + 1} of ${photos.length}`} style={{ width: '100%', height: '100%', objectFit: 'contain', display: 'block' }} />
            {photos.length > 1 && [['prev', -1, 'left'], ['next', 1, 'right']].map(([k, d, side]) => (
              <button key={k} type="button" aria-label={k === 'prev' ? 'Previous photo' : 'Next photo'}
                onClick={() => setI((i + d + photos.length) % photos.length)}
                style={{ position: 'absolute', top: '50%', [side]: 10, transform: 'translateY(-50%)' + (d < 0 ? ' scaleX(-1)' : ''), width: 40, height: 40, borderRadius: 999, background: 'rgba(255,255,255,.92)', color: 'var(--navy)', display: 'grid', placeItems: 'center' }}>
                <Icon.arrow s={18} />
              </button>
            ))}
          </div>
          {photos.length > 1 && (
            <div style={{ display: 'flex', gap: 8, marginTop: 10, overflowX: 'auto' }}>
              {photos.map((p, k) => (
                <button key={p} type="button" onClick={() => setI(k)} aria-label={`Show photo ${k + 1}`} style={{ flexShrink: 0, width: 72, height: 54, borderRadius: 8, overflow: 'hidden', outline: k === i ? '3px solid var(--green)' : '1px solid var(--line)', outlineOffset: k === i ? 1 : 0 }}>
                  <img src={p} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
                </button>
              ))}
            </div>
          )}
        </div>
      )}

      <div style={{ display: 'flex', alignItems: 'baseline', gap: 14, flexWrap: 'wrap' }}>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: 30, color: 'var(--green-600)' }}>{olMoney(l.price)}</div>
        {l.trim && <div style={{ color: 'var(--ink-soft)', fontWeight: 700 }}>{l.trim}</div>}
        {l.status === 'sold' && <span style={{ background: 'var(--navy)', color: '#fff', fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 12, letterSpacing: '.08em', padding: '5px 10px', borderRadius: 999 }}>SOLD</span>}
      </div>

      <dl style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(150px, 1fr))', gap: '12px 18px', margin: '16px 0', padding: 16, background: 'var(--paper)', borderRadius: 'var(--r-md)' }}>
        {[['Mileage', l.mileage != null ? cfsMiles(l.mileage) : '—'], ['Location', l.city || l.zip || '—'], ['VIN', l.vin || '—'], ...cfsSpecRows(l), ['Listed', cfsAgo(l.createdAt)], ['Seller', l.seller.name]].map(([k, v]) => (
          <div key={k}>
            <dt className="field-label">{k}</dt>
            <dd style={{ margin: 0, fontWeight: 700, color: 'var(--ink)', wordBreak: 'break-all' }}>{v}</dd>
          </div>
        ))}
      </dl>

      {l.description && <p style={{ whiteSpace: 'pre-wrap', lineHeight: 1.6, color: 'var(--ink)', marginBottom: 18 }}>{l.description}</p>}

      {l.status !== 'sold' && (l.seller.phone || l.seller.email) && (
        <div style={{ borderTop: '1px solid var(--line-soft)', paddingTop: 16 }}>
          <div className="kicker" style={{ marginBottom: 10 }}>Interested? Contact the seller, {l.seller.name}</div>
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
            {l.seller.phone && <a className="btn btn-green btn-md" href={'tel:' + l.seller.phone.replace(/[^\d+]/g, '')} aria-label={`Call ${l.seller.name} at ${l.seller.phone}`}><Icon.phone s={17} /> {l.seller.phone}</a>}
            {l.seller.email && <a className="btn btn-ghost btn-md" href={`mailto:${l.seller.email}?subject=${encodeURIComponent(cfsTitle(l) + ' on Motor Row (' + l.id + ')')}`}>Email {l.seller.name}</a>}
          </div>
          <p style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 12, lineHeight: 1.55 }}>
            You’ll be dealing directly with {l.seller.name}. Motor Row is a listing marketplace and isn’t a party to the sale. Confirm price, mileage and availability with the seller and inspect the vehicle and title before buying. See our <a href="/terms" style={{ color: 'var(--navy)', textDecoration: 'underline' }}>Terms</a>.
          </p>
        </div>
      )}

      {staff && (
        <div style={{ borderTop: '1px solid var(--line-soft)', marginTop: 18, paddingTop: 16, display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'center' }}>
          <span className="kicker" style={{ marginRight: 'auto' }}>Seller tools</span>
          {confirmRemove ? (
            <>
              <span style={{ fontWeight: 700, color: '#B23A12', fontSize: 14 }}>Remove for good? Photos are deleted too.</span>
              <button className="btn btn-ghost btn-sm" disabled={busy} onClick={() => setConfirmRemove(false)}>Keep it</button>
              <button className="btn btn-sm" disabled={busy} onClick={remove} style={{ background: '#B23A12', color: '#fff' }}>Yes, remove</button>
            </>
          ) : (
            <>
              <button className="btn btn-ghost btn-sm" disabled={busy} onClick={() => onEdit(l)}>Edit</button>
              {l.status === 'active'
                ? <button className="btn btn-navy btn-sm" disabled={busy} onClick={() => setStatus('sold')}>Mark as sold</button>
                : <button className="btn btn-green btn-sm" disabled={busy} onClick={() => setStatus('active')}>Relist</button>}
              <button className="btn btn-ghost btn-sm" disabled={busy} onClick={() => setConfirmRemove(true)} style={{ color: '#B23A12' }}>Remove</button>
            </>
          )}
        </div>
      )}
      {err && <div role="alert" style={{ marginTop: 12, color: '#B23A12', fontWeight: 600 }}>{err}</div>}
    </CfsModal>
  );
}

/* ------------------------------ post / edit form (staff) ------------------------------ */
function CfsPostForm({ user, initial, onClose, onSaved }) {
  const editing = !!initial;
  const [v, setV] = useStateC(() => initial ? {
    method: initial.vin ? 'vin' : 'ymm', vin: initial.vin || '',
    yr: initial.year ? String(initial.year) : '', mk: initial.make || '', md: initial.model || '', trim: initial.trim || '',
    miles: initial.mileage != null ? String(initial.mileage) : '', zip: initial.zip || '',
    decoded: initial.vin ? { year: initial.year, make: initial.make, model: initial.model, trim: initial.trim } : null,
  } : { method: 'vin', vin: '', yr: '', mk: '', md: '', trim: '', miles: '', zip: cfsStore.get('ol_staff_zip'), decoded: null });
  const set = (patch) => setV(prev => ({ ...prev, ...patch }));
  const [price, setPrice] = useStateC(initial ? String(initial.price) : '');
  const [city, setCity] = useStateC(initial ? (initial.city || '') : (cfsStore.get('ol_staff_city') || 'Indianapolis'));
  const [phone, setPhone] = useStateC(initial ? (initial.seller.phone || '') : cfsStore.get('ol_staff_phone'));
  const [showEmail] = useStateC(false);   // email is never shown on the site (owner's instruction, Oct 28, 2026); buyers call or use the contact form
  const [desc, setDesc] = useStateC(initial ? (initial.description || '') : '');
  const [photos, setPhotos] = useStateC(initial ? initial.photos.slice() : []); // existing /uploads/ urls + new data URLs
  const [photoBusy, setPhotoBusy] = useStateC(false);
  const [busy, setBusy] = useStateC(false);
  const [err, setErr] = useStateC('');
  const fileRef = useRefC(null);

  const year = v.yr && v.yr !== 'Year' ? v.yr : '';
  const make = v.mk && v.mk !== 'Make' ? v.mk : '';
  const model = v.md && v.md !== 'Model' ? v.md : '';
  const ready = year && make && model && Number(price) >= 100 && (phone.replace(/\D/g, '').length >= 10 || showEmail);

  const addPhotos = async (files) => {
    const room = 8 - photos.length;
    const list = [...files].filter(f => /^image\//.test(f.type)).slice(0, room);
    if (!list.length) return;
    setPhotoBusy(true);
    const out = [];
    for (const f of list) { try { out.push(await cfsResizePhoto(f)); } catch (e) {} }
    setPhotos(p => [...p, ...out].slice(0, 8));
    setPhotoBusy(false);
  };
  const makeCover = (k) => setPhotos(ps => [ps[k], ...ps.filter((_, j) => j !== k)]);

  const submit = async (e) => {
    e.preventDefault();
    if (!ready || busy) return;
    setBusy(true); setErr('');
    try {
      const body = { year, make, model, trim: v.trim || '', vin: v.method === 'vin' ? v.vin : '', mileage: v.miles, zip: v.zip, city, price, phone, showEmail, description: desc, photos };
      const r = editing
        ? await cfsApi('/api/listings/' + initial.id, { method: 'PUT', body })
        : await cfsApi('/api/listings', { method: 'POST', body });
      if (phone) cfsStore.set('ol_staff_phone', phone);
      if (city) cfsStore.set('ol_staff_city', city);
      if (v.zip) cfsStore.set('ol_staff_zip', v.zip);
      onSaved(r.listing);
    } catch (e2) { setErr(e2.status === 401 ? 'Your seller sign-in expired. Close this, sign in again, and retry.' : e2.message); setBusy(false); }
  };

  return (
    <form onSubmit={submit} style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, fontSize: 13.5, color: 'var(--ink-soft)' }}>
        {user.picture && <img src={user.picture} alt="" referrerPolicy="no-referrer" style={{ width: 26, height: 26, borderRadius: 999 }} />}
        Signed in as <strong style={{ color: 'var(--ink)' }}>{user.email}</strong>
      </div>

      <div>
        <div className="kicker" style={{ marginBottom: 10 }}>Vehicle</div>
        <VehiclePicker v={v} set={set} showMileage={true} />
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }} className="cfs-two">
        <Field label="Price ($)" value={price ? Number(price).toLocaleString('en-US') : ''} onChange={val => setPrice(val.replace(/\D/g, '').slice(0, 7))} placeholder="e.g. 18,500" />
        <Field label="City" value={city} onChange={setCity} placeholder="e.g. Indianapolis" />
      </div>

      <div>
        <div className="kicker" style={{ marginBottom: 10 }}>Photos <span style={{ color: 'var(--muted)', letterSpacing: 0, textTransform: 'none', fontWeight: 600 }}>(up to 8 &middot; first one is the cover)</span></div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(96px, 1fr))', gap: 10 }}>
          {photos.map((p, k) => (
            <div key={p.slice(-40) + k} style={{ position: 'relative', aspectRatio: '4 / 3', borderRadius: 10, overflow: 'hidden', border: '1px solid var(--line)' }}>
              <img src={p} alt={`Photo ${k + 1}`} style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
              {k === 0
                ? <span style={{ position: 'absolute', left: 6, bottom: 6, background: 'var(--green)', color: '#fff', fontSize: 10.5, fontWeight: 800, padding: '2px 7px', borderRadius: 999 }}>COVER</span>
                : <button type="button" onClick={() => makeCover(k)} style={{ position: 'absolute', left: 6, bottom: 6, background: 'rgba(255,255,255,.92)', color: 'var(--navy)', fontSize: 10.5, fontWeight: 800, padding: '2px 7px', borderRadius: 999 }}>Make cover</button>}
              <button type="button" aria-label={`Remove photo ${k + 1}`} onClick={() => setPhotos(ps => ps.filter((_, j) => j !== k))}
                style={{ position: 'absolute', right: 5, top: 5, width: 26, height: 26, borderRadius: 999, background: 'rgba(5,32,77,.8)', color: '#fff', display: 'grid', placeItems: 'center' }}><Icon.close s={14} /></button>
            </div>
          ))}
          {photos.length < 8 && (
            <button type="button" onClick={() => fileRef.current && fileRef.current.click()} disabled={photoBusy}
              style={{ aspectRatio: '4 / 3', borderRadius: 10, border: '2px dashed var(--line)', color: 'var(--navy)', fontWeight: 800, fontSize: 13, display: 'grid', placeItems: 'center', background: 'var(--paper)' }}>
              {photoBusy ? <MiniSpin size={20} /> : '+ Add photos'}
            </button>
          )}
        </div>
        <input ref={fileRef} type="file" accept="image/*" multiple hidden onChange={e => { addPhotos(e.target.files); e.target.value = ''; }} />
      </div>

      <label className="field">
        <span className="field-label">Description</span>
        <textarea className="field-input" rows={4} maxLength={2000} value={desc} onChange={e => setDesc(e.target.value)}
          placeholder="Condition, options, service history…" style={{ resize: 'vertical', fontSize: 15.5, fontWeight: 500, lineHeight: 1.5 }} />
      </label>

      <div>
        <div className="kicker" style={{ marginBottom: 10 }}>How buyers reach {user.dealer || 'you'}</div>
        <Field label="Phone" value={phone} onChange={val => setPhone(val.replace(/[^\d()+\-. ]/g, '').slice(0, 20))} placeholder="(317) 555-0123" type="tel" />
      </div>

      {err && <div role="alert" style={{ background: '#FCE7DA', border: '1.5px solid #F0B89E', borderRadius: 'var(--r-md)', padding: '11px 14px', color: '#B23A12', fontSize: 14, fontWeight: 600 }}>{err}</div>}

      <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end', flexWrap: 'wrap' }}>
        <button type="button" className="btn btn-ghost btn-md" onClick={onClose}>Cancel</button>
        <button type="submit" className="btn btn-green btn-md" disabled={!ready || busy}>
          {busy ? <><MiniSpin size={16} /> Saving…</> : editing ? 'Save changes' : <>Post car <Icon.arrow s={16} /></>}
        </button>
      </div>
      <p style={{ fontSize: 12, color: 'var(--muted)', lineHeight: 1.55 }}>
        {editing ? 'Changes show on the site right away.' : 'The car goes live on the home page as soon as you post it.'} By posting you confirm the listing is accurate and that you’re authorized to sell this vehicle (see <a href="/terms#sellers" style={{ color: 'var(--navy)', textDecoration: 'underline' }}>Seller terms</a>).
      </p>
    </form>
  );
}

/* ------------------------------ section ------------------------------ */
function CarsForSale() {
  const auth = useCfsAuth();
  const staff = !!auth.user;
  const [listings, setListings] = useStateC(null);
  const [loadErr, setLoadErr] = useStateC('');
  const [manage, setManage] = useStateC(false);    // staff: include sold cars
  const [q, setQ] = useStateC('');
  const [maxPrice, setMaxPrice] = useStateC('Any price');
  const [sort, setSort] = useStateC('Newest');
  const [open, setOpen] = useStateC(null);         // listing in detail view
  const [editor, setEditor] = useStateC(null);     // null | 'new' | listing being edited
  const [signingIn, setSigningIn] = useStateC(false);
  const [showCount, setShowCount] = useStateC(12);
  const [dealerDraft, setDealerDraft] = useStateC('');
  const [inbox, setInbox] = useStateC(false);
  const [msgs, setMsgs] = useStateC(null);
  const [feedOpen, setFeedOpen] = useStateC(false);   // Inventory feed panel (feeds.jsx)
  const unread = msgs ? msgs.messages.filter(m => !m.read_at).length : 0;
  useEffectC(() => { if (!staff) { setMsgs(null); return; } cfsApi('/api/messages').then(setMsgs).catch(() => {}); }, [staff]);
  useEffectC(() => { setDealerDraft(auth.user ? (auth.user.dealer || '') : ''); }, [auth.user && auth.user.dealer]);

  // Footer "Staff login" link, or visiting /#staff, opens the sign-in box.
  useEffectC(() => {
    const openLogin = () => setSigningIn(true);
    window.addEventListener('ol-staff-login', openLogin);
    if (location.hash === '#staff') openLogin();
    return () => window.removeEventListener('ol-staff-login', openLogin);
  }, []);
  useEffectC(() => { if (!staff) { setManage(false); setFeedOpen(false); } }, [staff]);

  const load = useCallbackC(() => {
    setLoadErr('');
    cfsApi('/api/listings' + (manage ? '?mine=1' : ''))
      .then(r => setListings(r.listings))
      .catch(() => { setListings([]); setLoadErr('Cars couldn’t load. Refresh to try again.'); });
  }, [manage]);
  useEffectC(() => { load(); }, [load, auth.user && auth.user.id]);

  const priceCaps = { 'Any price': Infinity, 'Under $10k': 1e4, 'Under $20k': 2e4, 'Under $30k': 3e4, 'Under $50k': 5e4 };
  const words = q.toLowerCase().split(/\s+/).filter(Boolean);
  const shown = (listings || [])
    .filter(l => l.price <= priceCaps[maxPrice])
    .filter(l => { const hay = [l.year, l.make, l.model, l.trim, l.city, l.zip].join(' ').toLowerCase(); return words.every(w => hay.includes(w)); })
    .sort((a, b) => sort === 'Price: low to high' ? a.price - b.price : sort === 'Price: high to low' ? b.price - a.price : sort === 'Lowest miles' ? (a.mileage ?? 1e9) - (b.mileage ?? 1e9) : b.createdAt - a.createdAt);
  const activeCount = (listings || []).filter(l => l.status === 'active').length;

  const onChanged = (updated, removedId) => {
    setListings(ls => {
      if (!ls) return ls;
      if (removedId) return ls.filter(x => x.id !== removedId);
      const has = ls.some(x => x.id === updated.id);
      const next = has ? ls.map(x => x.id === updated.id ? updated : x) : [updated, ...ls];
      return manage ? next : next.filter(x => x.status === 'active');
    });
    if (updated) setOpen(updated);
  };
  const signOut = () => { auth.signOut(); setOpen(null); setEditor(null); };

  return (
    <section id="cars-for-sale" style={{ scrollMarginTop: 82, background: 'linear-gradient(180deg, var(--blue-tint) 0%, #fff 340px)', borderBottom: '1px solid var(--line-soft)' }}>
      <div className="wrap" style={{ padding: '44px 28px 70px' }}>
        {staff && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap', background: 'var(--navy)', color: '#fff', borderRadius: 'var(--r-md)', padding: '12px 16px', marginBottom: 26 }}>
            {auth.user.picture && <img src={auth.user.picture} alt="" referrerPolicy="no-referrer" style={{ width: 30, height: 30, borderRadius: 999 }} />}
            <div style={{ fontSize: 14, lineHeight: 1.3 }}>
              <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, letterSpacing: '.06em', textTransform: 'uppercase', fontSize: 12, color: '#B9C8E8' }}>Seller mode · {auth.user.dealer || 'Motor Row'}</div>
              <div style={{ fontWeight: 700 }}>{auth.user.email}</div>
            </div>
            <form onSubmit={async (e) => { e.preventDefault(); const name = dealerDraft.trim(); if (!name || name === auth.user.dealer) return; try { const r = await cfsApi('/api/me', { method: 'PUT', body: { dealer: name } }); auth.setUser(r.user); load(); } catch (e2) { alert(e2.message); } }}
              style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <label htmlFor="cfs-dealer" style={{ fontSize: 13, fontWeight: 700, color: '#B9C8E8' }}>Dealership name</label>
              <input id="cfs-dealer" value={dealerDraft} onChange={e => setDealerDraft(e.target.value)} maxLength={60}
                style={{ borderRadius: 10, border: '1.5px solid rgba(255,255,255,.35)', background: 'rgba(255,255,255,.08)', color: '#fff', padding: '8px 10px', fontSize: 14, width: 170 }} />
              <button type="submit" className="btn btn-sm" disabled={dealerDraft.trim() === (auth.user.dealer || '')} style={{ color: '#fff', boxShadow: 'inset 0 0 0 1.5px rgba(255,255,255,.4)' }}>Save</button>
            </form>
            <div style={{ marginLeft: 'auto', display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'center' }}>
              <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13.5, fontWeight: 700, cursor: 'pointer' }}>
                <input type="checkbox" checked={manage} onChange={e => setManage(e.target.checked)} style={{ width: 17, height: 17, accentColor: 'var(--green)' }} />
                Show sold cars
              </label>
              <button className="btn btn-sm" onClick={() => setFeedOpen(true)} style={{ color: '#fff', boxShadow: 'inset 0 0 0 1.5px rgba(255,255,255,.4)' }}>Inventory feed</button>
              <button className="btn btn-sm" onClick={() => setInbox(true)} style={{ color: '#fff', boxShadow: 'inset 0 0 0 1.5px rgba(255,255,255,.4)' }}>Messages{unread ? ` (${unread})` : ''}</button>
              <button className="btn btn-green btn-sm" onClick={() => setEditor('new')}>+ Post a car</button>
              <button className="btn btn-sm" onClick={signOut} style={{ color: '#fff', boxShadow: 'inset 0 0 0 1.5px rgba(255,255,255,.4)' }}>Sign out</button>
            </div>
          </div>
        )}

        <div style={{ marginBottom: 24 }}>
          <div className="kicker">Indianapolis, IN{listings && activeCount ? ` · ${activeCount} car${activeCount === 1 ? '' : 's'} available` : ''}</div>
          <h1 className="h-section" style={{ marginTop: 10 }}>Cars for sale</h1>
          <p style={{ color: 'var(--ink-soft)', fontSize: 17, marginTop: 12, maxWidth: 600, lineHeight: 1.55 }}>
            Used cars listed by local dealers on the Motor Row marketplace. Open any car for photos and details, then contact the seller directly.
          </p>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '1.6fr 1fr 1fr', gap: 12, marginBottom: 22, alignItems: 'stretch' }} id="cfs-filters">
          <label className="field">
            <span className="field-label">Search</span>
            <input className="field-input" value={q} onChange={e => setQ(e.target.value)} placeholder="Make, model, year…" aria-label="Search cars" />
          </label>
          <Field label="Price" value={maxPrice} onChange={setMaxPrice} options={Object.keys(priceCaps)} />
          <Field label="Sort" value={sort} onChange={setSort} options={['Newest', 'Price: low to high', 'Price: high to low', 'Lowest miles']} />
        </div>

        <p className="sr-only" aria-live="polite" role="status">
          {listings === null ? 'Loading cars' : loadErr ? loadErr : `${shown.length} of ${listings.length} cars shown`}
        </p>
        {listings === null ? (
          <div style={{ display: 'grid', placeItems: 'center', padding: 60 }}><div className="ol-spin" role="img" aria-label="Loading cars" /></div>
        ) : shown.length === 0 ? (
          <div style={{ background: '#fff', border: '1px dashed var(--line)', borderRadius: 'var(--r-md)', padding: '46px 24px', textAlign: 'center' }}>
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 20, color: 'var(--navy)' }}>
              {loadErr ? loadErr : listings.length === 0 ? 'No cars listed right now' : 'No cars match those filters'}
            </div>
            {!loadErr && listings.length === 0 && (
              staff
                ? <button className="btn btn-green btn-md" style={{ marginTop: 18 }} onClick={() => setEditor('new')}>+ Post a car</button>
                : <p style={{ color: 'var(--ink-soft)', marginTop: 8 }}>New listings appear as dealers post them &mdash; check back soon.</p>
            )}
          </div>
        ) : (
          <>
            <ul id="cfs-grid" aria-label="Cars for sale" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 20, listStyle: 'none', margin: 0, padding: 0 }}>
              {shown.slice(0, showCount).map(l => <li key={l.id} style={{ display: 'flex' }}><CfsCard l={l} onOpen={setOpen} /></li>)}
            </ul>
            {shown.length > showCount && (
              <div style={{ textAlign: 'center', marginTop: 26 }}>
                <button className="btn btn-ghost btn-md" onClick={() => setShowCount(c => c + 12)}>Show more ({shown.length - showCount} left)</button>
              </div>
            )}
          </>
        )}
      </div>

      {open && !editor && (
        <CfsDetail l={open} staff={staff} onClose={() => setOpen(null)} onChanged={onChanged}
          onEdit={(l) => setEditor(l)} />
      )}

      {editor && staff && (
        <CfsModal title={editor === 'new' ? 'Post a car' : 'Edit car'} onClose={() => setEditor(null)} width={700}>
          <CfsPostForm user={auth.user} initial={editor === 'new' ? null : editor} onClose={() => setEditor(null)}
            onSaved={(l) => { setEditor(null); onChanged(l); }} />
        </CfsModal>
      )}

      {inbox && staff && (
        <CfsModal title="Messages" onClose={() => setInbox(false)} width={720}>
          {!msgs ? <MiniSpin size={24} /> : msgs.messages.length === 0 ? <p style={{ color: 'var(--ink-soft)' }}>No messages yet. Anything sent through the contact form shows up here.</p> : (
            <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'grid', gap: 12 }}>
              {msgs.messages.map(m => (
                <li key={m.id} style={{ border: '1px solid var(--line)', borderLeft: `5px solid ${m.read_at ? 'var(--line)' : 'var(--green)'}`, borderRadius: 'var(--r-md)', padding: '12px 14px' }}>
                  <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'baseline', fontSize: 13.5, color: 'var(--ink-soft)' }}>
                    <strong style={{ color: 'var(--navy)' }}>{msgs.topics[m.topic] || m.topic}</strong>
                    <span>{m.name || 'No name'}</span><span>&middot; {m.reply_to}</span>
                    <span style={{ marginLeft: 'auto' }}>{new Date(m.created_at).toLocaleString('en-US')}</span>
                  </div>
                  <p style={{ whiteSpace: 'pre-wrap', marginTop: 8, lineHeight: 1.55 }}>{m.body}</p>
                  {!m.read_at && <button className="btn btn-ghost btn-sm" style={{ marginTop: 8 }} onClick={() => { cfsApi('/api/messages/' + m.id, { method: 'PATCH', body: {} }).then(() => setMsgs(x => ({ ...x, messages: x.messages.map(y => y.id === m.id ? { ...y, read_at: Date.now() } : y) }))); }}>Mark read</button>}
                </li>
              ))}
            </ul>
          )}
        </CfsModal>
      )}

      {feedOpen && staff && (
        <CfsModal title="Inventory feed" onClose={() => setFeedOpen(false)} width={860}>
          <CfsFeedPanel onImported={() => load()} />
        </CfsModal>
      )}

      {signingIn && (
        <CfsModal title={staff ? 'Signed in' : 'Seller login'} onClose={() => setSigningIn(false)} width={460}>
          {staff ? (
            <div style={{ textAlign: 'center' }}>
              <p style={{ color: 'var(--ink-soft)', fontSize: 15.5, lineHeight: 1.55, marginBottom: 18 }}>You&rsquo;re signed in as <strong>{auth.user.email}</strong>.</p>
              <button className="btn btn-green btn-md" onClick={() => { setSigningIn(false); setEditor('new'); }}>+ Post a car</button>
            </div>
          ) : (
            <div style={{ textAlign: 'center', padding: '4px 4px 6px' }}>
              <p style={{ color: 'var(--ink-soft)', fontSize: 15.5, lineHeight: 1.55, marginBottom: 22 }}>
                For approved Motor Row sellers only. Shoppers don&rsquo;t need an account to browse cars or contact a seller. Want to list your dealership&rsquo;s inventory? See <a href="#for-dealers" onClick={() => setSigningIn(false)} style={{ color: 'var(--navy)', textDecoration: 'underline' }}>For dealers</a>.
              </p>
              {auth.loading ? <MiniSpin size={24} /> : <CfsGoogleButton clientId={auth.clientId} onSignedIn={(u) => { auth.setUser(u); setSigningIn(false); }} />}
            </div>
          )}
        </CfsModal>
      )}
    </section>
  );
}

Object.assign(window, { CarsForSale, CfsModal });
