// YJ Electric — Booking & Quote Flow v2: step screens
// Load after schedule-shared.jsx and schedule-v2-shared.jsx.

// ── STEP 01 — THE JOB ──────────────────────────────────────
function V2StepJob({ data, setData, quoteOnly }) {
  const props = data.customerType ? V2_PROPS.filter(p => V2_PROPS_BY_CUSTOMER[data.customerType].includes(p.key)) : [];
  const workOptions = data.customerType ? V2_WORK[data.customerType] : [];
  const work = workOptions.find(w => w.key === data.workType);
  const services = (data.customerType && data.propertyType && work?.style === 'services')
    ? v2ServicesFor(data.customerType, data.propertyType) : [];
  const { selected, quoteOnlyPicks, totalHours, kind } = v2BookingInfo(data);

  const pickCustomer = (key) => setData(d => {
    if (d.customerType === key) return d;
    const p = V2_PROPS_BY_CUSTOMER[key];
    const w = V2_WORK[key];
    return {
      ...d, customerType: key,
      propertyType: p.length === 1 ? p[0] : null,
      workType: w.length === 1 ? w[0].key : null,
      services: [], projectDetails: '', path: null, date: null, slot: null,
    };
  });

  const pickProperty = (key) => setData(d => d.propertyType === key ? d : ({ ...d, propertyType: key, services: [], path: null, date: null, slot: null }));
  const pickWork = (key) => setData(d => d.workType === key ? d : ({ ...d, workType: key, services: [], projectDetails: '', path: null, date: null, slot: null }));
  const toggleService = (key) => setData(d => ({
    ...d,
    services: d.services.includes(key) ? d.services.filter(k => k !== key) : [...d.services, key],
    path: null, date: null, slot: null,
  }));

  return (
    <div>
      <V2StepHeader num="01" eyebrow="The Job" title="What do you need done?" />

      <div style={v2Eyebrow}>I Am A…</div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(170px, 1fr))', gap: 8 }}>
        {V2_CUSTOMERS.map(c => (
          <V2Choice key={c.key} active={data.customerType === c.key} onClick={() => pickCustomer(c.key)} label={c.label} />
        ))}
      </div>

      {data.customerType && (
        <div style={{ marginTop: 26 }}>
          <div style={v2Eyebrow}>Property Type</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(170px, 1fr))', gap: 8 }}>
            {props.map(p => (
              <V2Choice key={p.key} active={data.propertyType === p.key} onClick={() => pickProperty(p.key)} label={p.label} sub={p.sub} />
            ))}
          </div>
        </div>
      )}

      {data.customerType && data.propertyType && (
        <div style={{ marginTop: 26 }}>
          <div style={v2Eyebrow}>Work Type</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(170px, 1fr))', gap: 8 }}>
            {workOptions.map(w => (
              <V2Choice key={w.key} active={data.workType === w.key} onClick={() => pickWork(w.key)} label={w.label} sub={w.sub} />
            ))}
          </div>
        </div>
      )}

      {work && work.style === 'project' && (
        <div style={{ marginTop: 26 }}>
          <div style={v2Eyebrow}>Project Details</div>
          <textarea
            value={data.projectDetails}
            onChange={e => setData(d => ({ ...d, projectDetails: e.target.value }))}
            placeholder="Tell us about the project — estimated start date, square footage, scope of work, permits needed, etc."
            rows={6}
            style={{ ...v2Input, resize: 'vertical' }}
          />
          <div style={{ marginTop: 10, fontFamily: 'Barlow Condensed', fontSize: 13, fontWeight: 600, color: SG.gray, lineHeight: 1.5 }}>
            Projects like this start with a free quote — you'll get it within 24 hours, then we schedule the work.
          </div>
        </div>
      )}

      {work && work.style === 'services' && (
        <div style={{ marginTop: 26 }}>
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 12 }}>
            <div style={v2Eyebrow}>Services Needed</div>
            <div style={{ fontFamily: 'Barlow Condensed', fontSize: 12, fontWeight: 700, color: SG.gray, letterSpacing: '0.06em', textTransform: 'uppercase' }}>Select all that apply</div>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))', gap: 8 }}>
            {services.map(s => (
              <V2ServiceCard key={s.key} active={data.services.includes(s.key)} onClick={() => toggleService(s.key)} service={s} quoteOnly={quoteOnly} />
            ))}
          </div>

          {selected.length > 0 && (
            <div style={{
              marginTop: 14, padding: '12px 16px', borderRadius: 4,
              background: 'rgba(245,166,35,0.1)', border: `1px solid ${SG.gold}`,
              display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap',
              fontFamily: 'Barlow Condensed',
            }}>
              <svg width="16" height="16" viewBox="0 0 22 22" fill="none" style={{ flexShrink: 0 }}>
                <circle cx="11" cy="11" r="8" stroke={SG.navy} strokeWidth="1.6"/>
                <path d="M11 6v5l3 2" stroke={SG.navy} strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/>
              </svg>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontWeight: 800, fontSize: 14, color: SG.navy, lineHeight: 1.3 }}>
                  {(!quoteOnly && quoteOnlyPicks.length === 0)
                    ? `${selected.length} selected | Books as a ${V2_KIND_LABEL[kind]}`
                    : `${selected.length} selected`}
                </div>
                <div style={{ fontWeight: 600, fontSize: 12, color: SG.navy, lineHeight: 1.4, marginTop: 2, opacity: 0.85 }}>
                  {quoteOnly
                    ? `The more detail you give us here, the more accurate your quote. Final pricing is confirmed at the appointment.`
                    : quoteOnlyPicks.length > 0
                    ? `Includes work we always quote first, so you'll get a quote within 24 hours before anything is booked.`
                    : `Durations are estimates and will be confirmed upon booking; final pricing is confirmed at the appointment.`}
                </div>
              </div>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// ── STEP 02 — PHOTOS & FILES ───────────────────────────────
function V2FileDrop({ files, onAdd, onRemove }) {
  const inputRef = React.useRef(null);
  const [drag, setDrag] = React.useState(false);

  const add = (fileList) => {
    const room = Math.max(0, 12 - files.length);
    const arr = Array.from(fileList).slice(0, room).map(f => ({
      name: f.name, size: f.size, type: f.type,
      url: f.type.startsWith('image/') ? URL.createObjectURL(f) : null,
      file: f, // retain the raw File so Volt.uploadPhotos can PUT the bytes post-booking
    }));
    if (arr.length) onAdd(arr);
  };

  return (
    <div>
      <div
        onClick={() => inputRef.current && inputRef.current.click()}
        onDragOver={e => { e.preventDefault(); setDrag(true); }}
        onDragLeave={() => setDrag(false)}
        onDrop={e => { e.preventDefault(); setDrag(false); add(e.dataTransfer.files); }}
        style={{
          border: `2px dashed ${drag ? SG.gold : SG.grayLight}`, borderRadius: 4,
          background: drag ? 'rgba(245,166,35,0.06)' : '#fff',
          padding: '28px 20px', textAlign: 'center', cursor: 'pointer',
          transition: 'all 150ms ease',
        }}>
        <div style={{
          width: 44, height: 44, borderRadius: 4, background: 'rgba(27,42,74,0.06)',
          display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 12px',
        }}>
          <svg width="22" height="22" viewBox="0 0 24 24" fill="none">
            <path d="M12 16V5M12 5l-4 4M12 5l4 4" stroke={SG.navy} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
            <path d="M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2" stroke={SG.navy} strokeWidth="1.8" strokeLinecap="round"/>
          </svg>
        </div>
        <div style={{ fontFamily: 'Barlow Condensed', fontWeight: 800, fontSize: 16, textTransform: 'uppercase', letterSpacing: '0.04em', color: SG.navy }}>
          Tap to add photos or files
        </div>
        <div style={{ fontFamily: 'Barlow Condensed', fontSize: 13, fontWeight: 600, color: SG.gray, marginTop: 4 }}>
          Photos, PDFs, plans — up to 12 files
        </div>
        <input ref={inputRef} type="file" multiple accept="image/*,.pdf,.heic,.heif"
          onChange={e => { add(e.target.files); e.target.value = ''; }}
          style={{ display: 'none' }} />
      </div>

      {files.length > 0 && (
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(88px, 1fr))', gap: 8, marginTop: 12 }}>
          {files.map((f, i) => (
            <div key={i} style={{ position: 'relative', borderRadius: 4, overflow: 'hidden', border: `1.5px solid ${SG.grayLight}`, background: '#fff', aspectRatio: '1', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              {f.url
                ? <img src={f.url} alt={f.name} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                : (
                  <div style={{ textAlign: 'center', padding: 6 }}>
                    <svg width="24" height="24" viewBox="0 0 32 32" fill="none" style={{ margin: '0 auto' }}><path d="M9 4h10l6 6v18H9z" stroke={SG.navy} strokeWidth="1.8" strokeLinejoin="round"/><path d="M19 4v6h6" stroke={SG.navy} strokeWidth="1.8" strokeLinejoin="round"/></svg>
                    <div style={{ fontFamily: 'Barlow Condensed', fontSize: 10, fontWeight: 700, color: SG.navy, marginTop: 4, wordBreak: 'break-all', lineHeight: 1.2, maxHeight: 24, overflow: 'hidden' }}>{f.name}</div>
                  </div>
                )}
              <button onClick={() => onRemove(i)} aria-label={`Remove ${f.name}`} style={{
                position: 'absolute', top: 4, right: 4, width: 24, height: 24, borderRadius: '50%',
                background: 'rgba(17,16,51,0.75)', border: 'none', cursor: 'pointer',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}>
                <svg width="10" height="10" viewBox="0 0 10 10"><path d="M1.5 1.5l7 7M8.5 1.5l-7 7" stroke="#fff" strokeWidth="1.6" strokeLinecap="round"/></svg>
              </button>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

function V2StepPhotos({ data, setData }) {
  const hasInspection = data.services.includes('inspection');
  const { isProject } = v2BookingInfo(data);
  const sub = hasInspection
    ? 'Upload the inspection report (PDF) — we build the itemized bid straight from it. Photos of flagged items help too.'
    : data.customerType === 'builder'
    ? 'Plans, drawings, or a scope doc help us bid fast and accurately.'
    : isProject
    ? 'Plans, sketches, or photos of the space — anything that helps us scope it.'
    : 'A few photos of the panel, the space, or the problem help us quote accurately and show up prepared.';

  return (
    <div>
      <V2StepHeader num="02" eyebrow="Photos & Files" title="Show us what we're working with" sub={sub} />
      <V2FileDrop
        files={data.files}
        onAdd={arr => setData(d => ({ ...d, files: [...d.files, ...arr] }))}
        onRemove={i => setData(d => ({ ...d, files: d.files.filter((_, x) => x !== i) }))}
      />
      <div style={{ marginTop: 22 }}>
        <label style={v2Label}>Anything else we should know? <span style={{ opacity: 0.5, fontWeight: 500 }}>(optional)</span></label>
        <textarea
          value={data.description}
          onChange={e => setData(d => ({ ...d, description: e.target.value }))}
          placeholder="Timing constraints, gate codes, pets, tenant contact, quirks of the property…"
          rows={4}
          style={{ ...v2Input, resize: 'vertical' }}
        />
      </div>
    </div>
  );
}

// ── STEP 03 — CONTACT ──────────────────────────────────────
// Sample address set — stands in for a real address-verification API.
const V2_ADDRESSES = [
  { line: '4200 Live Oak St',       city: 'Dallas',     state: 'TX', zip: '75204' },
  { line: '6300 Skillman St',       city: 'Dallas',     state: 'TX', zip: '75231' },
  { line: '2727 Turtle Creek Blvd', city: 'Dallas',     state: 'TX', zip: '75219' },
  { line: '5001 Greenville Ave',    city: 'Dallas',     state: 'TX', zip: '75206' },
  { line: '8350 N Central Expy',    city: 'Dallas',     state: 'TX', zip: '75206' },
  { line: '3699 McKinney Ave',      city: 'Dallas',     state: 'TX', zip: '75204' },
  { line: '901 Main St',            city: 'Dallas',     state: 'TX', zip: '75202' },
  { line: '4514 Cole Ave',          city: 'Dallas',     state: 'TX', zip: '75205' },
  { line: '2100 Ross Ave',          city: 'Dallas',     state: 'TX', zip: '75201' },
  { line: '7300 Lemmon Ave',        city: 'Dallas',     state: 'TX', zip: '75209' },
  { line: '1401 Elm St',            city: 'Fort Worth', state: 'TX', zip: '76102' },
  { line: '500 W 7th St',           city: 'Fort Worth', state: 'TX', zip: '76102' },
  { line: '7007 Lindsley Ave',      city: 'Dallas',     state: 'TX', zip: '75223' },
  { line: '3321 Lovers Lane',       city: 'Dallas',     state: 'TX', zip: '75225' },
  { line: '3701 Villanova St',      city: 'Dallas',     state: 'TX', zip: '75225' },
];

function V2StepContact({ data, setData }) {
  const zipCheck = checkZip(data.zip);
  const [showSuggestions, setShowSuggestions] = React.useState(false);
  const [placesReady, setPlacesReady] = React.useState(false);
  const [placeSuggestions, setPlaceSuggestions] = React.useState([]);
  const sessionRef = React.useRef(null);
  const debounceRef = React.useRef(null);
  const addressQuery = data.address.trim();

  // Load Google Places once (only if a key is configured); otherwise the mock
  // V2_ADDRESSES list powers the dropdown (dev / no-key fallback).
  React.useEffect(() => {
    if (!(window.Volt && window.Volt.placesEnabled && window.Volt.placesEnabled())) return undefined;
    let cancelled = false;
    window.Volt.ensurePlaces().then((ok) => { if (!cancelled) setPlacesReady(!!ok); });
    return () => { cancelled = true; };
  }, []);

  // Debounced live predictions from Google (only once Places has loaded).
  const queryPlaces = (q) => {
    if (!placesReady) return;
    clearTimeout(debounceRef.current);
    if (q.trim().length < 3) { setPlaceSuggestions([]); return; }
    debounceRef.current = setTimeout(async () => {
      if (!sessionRef.current) sessionRef.current = window.Volt.newPlacesSession();
      setPlaceSuggestions(await window.Volt.addressSuggestions(q, sessionRef.current));
    }, 220);
  };

  const mockSuggestions = addressQuery.length >= 2
    ? V2_ADDRESSES.filter(a => a.line.toLowerCase().includes(addressQuery.toLowerCase())).slice(0, 5)
        .map(a => ({ line: a.line, sub: `${a.city}, ${a.state} ${a.zip}`, mock: a }))
    : [];
  // The mock V2_ADDRESSES list is DEV-only — in production a missing Places key
  // means a plain input, not a dropdown of unrelated real addresses that could
  // mislead a customer into picking the wrong one.
  const isLocalDev = typeof window !== 'undefined' && /^(localhost|127\.0\.0\.1)$/.test(window.location.hostname);
  const suggestions = placesReady ? placeSuggestions : (isLocalDev ? mockSuggestions : []);

  const pickSuggestion = async (a) => {
    setShowSuggestions(false);
    if (a.prediction) {
      const det = await window.Volt.placeDetails(a.prediction);
      sessionRef.current = null; // a selection closes the billing session
      setPlaceSuggestions([]);
      setData(d => ({
        ...d,
        address: (det && det.address) || a.line,
        city: (det && det.city) || d.city,
        state: (det && det.state) || d.state,
        zip: (det && det.zip) || d.zip,
      }));
    } else if (a.mock) {
      setData(d => ({ ...d, address: a.mock.line, city: a.mock.city, state: a.mock.state, zip: a.mock.zip }));
    }
  };
  const addressLabel = data.customerType === 'agent' ? 'Listing Address' : data.customerType === 'landlord' ? 'Property Address' : 'Street Address';

  return (
    <div>
      <V2StepHeader num="03" eyebrow="Contact" title="Where's the work, and how do we reach you?" />

      <div style={{ maxWidth: 560 }}>
        <div style={{ position: 'relative' }}>
          <label style={v2Label}>{addressLabel}</label>
          <input type="text" value={data.address} placeholder="Start typing the address…" autoComplete="off"
            onChange={e => { const v = e.target.value; setData(d => ({ ...d, address: v })); setShowSuggestions(true); queryPlaces(v); }}
            onFocus={() => setShowSuggestions(true)}
            onBlur={() => setTimeout(() => setShowSuggestions(false), 160)}
            style={v2Input} />
          {showSuggestions && suggestions.length > 0 && (
            <div style={{
              position: 'absolute', top: '100%', left: 0, right: 0, marginTop: 4,
              background: '#fff', border: `1.5px solid ${SG.grayLight}`, borderRadius: 4,
              boxShadow: '0 8px 24px rgba(0,0,0,0.14)', zIndex: 20, overflow: 'hidden',
            }}>
              {suggestions.map((a, i) => (
                <div key={i}
                  onMouseDown={() => pickSuggestion(a)}
                  style={{ padding: '11px 14px', cursor: 'pointer', fontFamily: 'Barlow Condensed', borderBottom: `1px solid ${SG.grayLight}` }}
                  onMouseEnter={e => e.currentTarget.style.background = 'rgba(245,166,35,0.08)'}
                  onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
                  <div style={{ fontWeight: 700, fontSize: 14, color: SG.navy }}>{a.line}</div>
                  {a.sub && <div style={{ fontSize: 12, color: SG.gray, marginTop: 1 }}>{a.sub}</div>}
                </div>
              ))}
              <div style={{ padding: '6px 14px', fontSize: 10, fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', color: SG.gray, background: SG.cream, fontFamily: 'Barlow Condensed' }}>
                {placesReady ? 'Powered by Google' : 'Address Suggestions'}
              </div>
            </div>
          )}
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '2fr 0.7fr 1.1fr', gap: 12, marginTop: 14 }}>
          <div>
            <label style={v2Label}>City</label>
            <input type="text" name="city" autoComplete="address-level2" value={data.city} onChange={e => setData(d => ({ ...d, city: e.target.value }))} style={v2Input} />
          </div>
          <div>
            <label style={v2Label}>State</label>
            <input type="text" name="state" autoComplete="address-level1" value={data.state} maxLength={2}
              onChange={e => setData(d => ({ ...d, state: e.target.value.toUpperCase() }))}
              style={{ ...v2Input, textTransform: 'uppercase' }} />
          </div>
          <div>
            <label style={v2Label}>ZIP Code</label>
            <input type="text" name="postal-code" autoComplete="postal-code" inputMode="numeric" maxLength={5} value={data.zip}
              onChange={e => setData(d => ({ ...d, zip: e.target.value.replace(/\D/g, '') }))} style={v2Input} />
          </div>
        </div>

        {zipCheck && (
          <div style={{
            marginTop: 12, padding: '12px 16px', borderRadius: 4,
            background: zipCheck.ok ? 'rgba(245,166,35,0.1)' : 'rgba(107,114,128,0.08)',
            border: `1px solid ${zipCheck.ok ? SG.gold : SG.grayLight}`,
            display: 'flex', alignItems: 'center', gap: 10,
          }}>
            <div style={{
              width: 24, height: 24, borderRadius: '50%',
              background: zipCheck.ok ? SG.gold : SG.gray,
              display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
            }}>
              {zipCheck.ok
                ? <svg width="12" height="12" viewBox="0 0 12 12"><path d="M2 6l2.5 2.5L10 3" stroke={SG.navy} strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>
                : <svg width="12" height="12" viewBox="0 0 12 12"><line x1="2" y1="2" x2="10" y2="10" stroke="#fff" strokeWidth="1.8" strokeLinecap="round"/><line x1="10" y1="2" x2="2" y2="10" stroke="#fff" strokeWidth="1.8" strokeLinecap="round"/></svg>
              }
            </div>
            <div style={{ fontFamily: 'Barlow Condensed', fontWeight: 600, fontSize: 14, color: SG.navy, lineHeight: 1.4 }}>{zipCheck.msg}</div>
          </div>
        )}

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginTop: 26 }}>
          <div>
            <label style={v2Label}>First Name</label>
            <input type="text" name="fname" autoComplete="given-name" value={data.firstName} onChange={e => setData(d => ({ ...d, firstName: e.target.value }))} style={v2Input} />
          </div>
          <div>
            <label style={v2Label}>Last Name <span style={{ opacity: 0.5, fontWeight: 500 }}>(optional)</span></label>
            <input type="text" name="lname" autoComplete="family-name" value={data.lastName} onChange={e => setData(d => ({ ...d, lastName: e.target.value }))} style={v2Input} />
          </div>
          <div>
            <label style={v2Label}>Phone</label>
            <input type="tel" name="phone" autoComplete="tel" value={data.phone} placeholder="(214) 555-0000"
              onChange={e => setData(d => ({ ...d, phone: e.target.value }))} style={v2Input} />
          </div>
          <div>
            <label style={v2Label}>Email <span style={{ opacity: 0.5, fontWeight: 500 }}>(optional)</span></label>
            <input type="email" name="email" autoComplete="email" value={data.email} placeholder="you@example.com"
              onChange={e => setData(d => ({ ...d, email: e.target.value }))} style={v2Input} />
            {/* Inline honest-copy: warn on a typo'd address instead of silently
                dropping it server-side while the success screen claims "emailed". */}
            {data.email && data.email.trim() && window.Volt && !window.Volt.emailValid(data.email) && (
              <div style={{ marginTop: 6, fontFamily: 'Barlow Condensed', fontSize: 12, fontWeight: 600, color: '#8a2b2b' }}>
                That email doesn’t look right — double-check it, or leave it blank.
              </div>
            )}
          </div>
        </div>

        <div style={{ marginTop: 18 }}>
          <label style={v2Label}>Best way to reach you <span style={{ opacity: 0.5, fontWeight: 500 }}>(optional)</span></label>
          <div style={{ display: 'flex', gap: 8, marginTop: 6 }}>
            {[['text', 'Text'], ['call', 'Call'], ['email', 'Email']].map(([val, lbl]) => {
              const active = data.contactPreference === val;
              return (
                <button key={val} type="button"
                  onClick={() => setData(d => ({ ...d, contactPreference: d.contactPreference === val ? null : val }))}
                  style={{
                    flex: 1, padding: '11px 12px', borderRadius: 4, cursor: 'pointer',
                    background: active ? SG.navy : '#fff', color: active ? '#fff' : SG.navy,
                    border: active ? `2px solid ${SG.gold}` : `1.5px solid ${SG.grayLight}`,
                    fontFamily: 'Barlow Condensed', fontWeight: 800, fontSize: 14,
                    letterSpacing: '0.04em', textTransform: 'uppercase', transition: 'all 150ms ease',
                  }}>
                  {lbl}
                </button>
              );
            })}
          </div>
        </div>

        <div style={{ marginTop: 18 }}>
          <label style={v2Label}>How did you hear about us? <span style={{ opacity: 0.5, fontWeight: 500 }}>(optional)</span></label>
          <select value={data.howHeard || ''}
            onChange={e => setData(d => ({
              ...d,
              howHeard: e.target.value || null,
              // clear the referral name if they switch away from a referral option
              referredByName: /referr/i.test(e.target.value) ? d.referredByName : '',
            }))}
            style={{ ...v2Input, cursor: 'pointer' }}>
            <option value="">Select…</option>
            {['Google search', 'Google / online ad', 'Facebook or Instagram', 'Nextdoor',
              'Referral (friend, family, or neighbor)', 'Referred by a realtor / agent',
              'Repeat customer', 'Truck or yard sign', 'Home-service site (Angi, Thumbtack, etc.)', 'Other']
              .map(o => <option key={o} value={o}>{o}</option>)}
          </select>
          {data.howHeard && /referr/i.test(data.howHeard) && (
            <div style={{ marginTop: 10 }}>
              <label style={v2Label}>Who can we thank? <span style={{ opacity: 0.5, fontWeight: 500 }}>(optional)</span></label>
              <input type="text" value={data.referredByName}
                placeholder="Name of the friend or realtor who referred you"
                onChange={e => setData(d => ({ ...d, referredByName: e.target.value }))} style={v2Input} />
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// ── STEP 04 — SCHEDULE OR QUOTE ────────────────────────────
function V2PathCard({ active, disabled, onClick, title, sub, note }) {
  return (
    <button onClick={onClick} disabled={disabled} style={{
      textAlign: 'left', padding: '16px 18px', borderRadius: 4, width: '100%',
      cursor: disabled ? 'not-allowed' : 'pointer',
      background: active ? SG.navy : '#fff',
      border: active ? `2px solid ${SG.gold}` : `1.5px solid ${SG.grayLight}`,
      color: active ? '#fff' : SG.navy, fontFamily: 'Barlow Condensed',
      opacity: disabled ? 0.55 : 1, transition: 'all 150ms ease',
    }}
      onMouseEnter={e => { if (!active && !disabled) e.currentTarget.style.borderColor = SG.gold; }}
      onMouseLeave={e => { if (!active && !disabled) e.currentTarget.style.borderColor = SG.grayLight; }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{
          width: 18, height: 18, borderRadius: '50%', flexShrink: 0,
          border: active ? `5px solid ${SG.gold}` : `2px solid ${SG.grayLight}`,
          background: '#fff', boxSizing: 'border-box',
        }} />
        <div style={{ fontWeight: 900, fontSize: 17, textTransform: 'uppercase', letterSpacing: '0.03em' }}>{title}</div>
      </div>
      <div style={{ fontSize: 13, fontWeight: 600, opacity: 0.7, marginTop: 6, lineHeight: 1.4, paddingLeft: 28 }}>{sub}</div>
      {note && <div style={{ fontSize: 12, fontWeight: 700, color: active ? SG.gold : SG.goldDark, marginTop: 6, lineHeight: 1.4, paddingLeft: 28 }}>{note}</div>}
    </button>
  );
}

function V2StepSchedule({ data, setData, goToStep, quoteOnly, slots: propSlots, bookingOff, mode }) {
  const { isProject, quoteOnlyPicks, totalHours, kind, bookable } = v2BookingInfo(data);
  // Live availability from Volt (the shell fetches it on mount and passes it in);
  // fall back to the mock grid only if that feed was unreachable/off. Volt
  // re-checks the exact slot on submit, so a stale fallback can't over-book.
  const slots = (Array.isArray(propSlots) && propSlots.length) ? propSlots : SLOTS;
  const blockNote = isProject
    ? 'Remodels & new builds start with a quote, and a site walk-through when needed.'
    : quoteOnlyPicks.length > 0
    ? `${quoteOnlyPicks.map(s => s.label).join(' & ')}: we always quote this work before booking it.`
    : null;

  // Auto-select the quote path when booking isn't possible (quote-only flow, a
  // quote-only job, or the online-booking lane is OFF) — so we never render the
  // fake mock calendar or let a customer pick a slot that can't be booked.
  React.useEffect(() => {
    if ((quoteOnly || !bookable || bookingOff) && data.path !== 'quote') setData(d => ({ ...d, path: 'quote', date: null, slot: null }));
  }, [bookable, quoteOnly, bookingOff]);

  const [selectedDateIdx, setSelectedDateIdx] = React.useState(() => {
    if (data.date) {
      const i = slots.findIndex(d => d.date.getTime() === data.date.getTime());
      if (i !== -1) return i;
    }
    const firstOpen = slots.findIndex(day => v2WindowsForDay(day, kind).some(w => w.open));
    return firstOpen === -1 ? 0 : firstOpen;
  });
  const selectedDay = slots[Math.min(selectedDateIdx, slots.length - 1)] || slots[0];
  const windows = v2WindowsForDay(selectedDay, kind);

  React.useEffect(() => {
    if (data.path === 'book') setData(d => ({ ...d, date: selectedDay.date }));
  }, [selectedDateIdx, data.path]);

  return (
    <div>
      <V2StepHeader num="04" eyebrow={quoteOnly ? 'Quote' : 'Schedule'} title={quoteOnly ? "You're requesting a free quote" : 'Book it now, or quote first?'} />

      {bookingOff && (
        <div style={{ marginBottom: 18, padding: '14px 18px', background: 'rgba(245,166,35,0.1)', border: `1.5px solid ${SG.gold}`, borderRadius: 4, fontFamily: 'Barlow Condensed', fontSize: 14, fontWeight: 600, color: SG.navy, lineHeight: 1.5 }}>
          Online booking is temporarily unavailable. Please call us at{' '}
          <a href="tel:+12148888799" style={{ color: SG.navy, fontWeight: 800 }}>214-888-8799</a> and we’ll get you scheduled.
        </div>
      )}

      {!quoteOnly && (
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: 10 }}>
        <V2PathCard
          active={data.path === 'book'}
          disabled={!bookable || bookingOff}
          onClick={() => setData(d => ({ ...d, path: 'book' }))}
          title="Book a Time Now"
          sub={bookable
            ? `Est. ${totalHours} hrs on site — pick a day and a ${V2_KIND_LABEL[kind]}. ${mode === 'auto' ? 'Booked instantly.' : 'We’ll confirm your time within the hour.'} Final pricing confirmed at the appointment.`
            : `Pick a day and time window. ${mode === 'auto' ? 'Booked instantly.' : 'We’ll confirm your time.'}`}
          note={blockNote}
        />
        <V2PathCard
          active={data.path === 'quote'}
          onClick={() => setData(d => ({ ...d, path: 'quote', date: null, slot: null }))}
          title="Get a Quote First"
          sub="Written quote within 24 hours by text & email — then book online or by phone."
        />
      </div>
      )}

      {data.path === 'book' && (
        <div style={{ marginTop: 26 }}>
          <div style={v2Eyebrow}>Pick a Day</div>
          <div style={{ display: 'flex', gap: 8, overflowX: 'auto', paddingBottom: 6, marginBottom: 18, WebkitOverflowScrolling: 'touch' }}>
            {slots.map((day, i) => {
              const active = i === selectedDateIdx;
              const rel = fmtDay(day.date, 'relative');
              const openCount = v2WindowsForDay(day, kind).filter(w => w.open).length;
              const dayFull = openCount === 0;
              return (
                <button key={i} onClick={() => { setSelectedDateIdx(i); setData(d => ({ ...d, slot: null })); }}
                  style={{
                    flexShrink: 0, minWidth: 76, padding: '12px 10px', borderRadius: 4, cursor: 'pointer',
                    background: active ? SG.navy : '#fff',
                    color: active ? '#fff' : SG.navy,
                    border: active ? `2px solid ${SG.gold}` : `1.5px solid ${SG.grayLight}`,
                    fontFamily: 'Barlow Condensed', textAlign: 'center',
                    opacity: dayFull && !active ? 0.45 : 1, transition: 'all 150ms ease',
                  }}>
                  <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.12em', textTransform: 'uppercase', opacity: 0.7 }}>
                    {rel === 'Today' || rel === 'Tomorrow' ? rel : fmtDay(day.date, 'dow')}
                  </div>
                  <div style={{
                    fontSize: 26, fontWeight: 900, lineHeight: 1.1, marginTop: 4,
                    color: active ? SG.gold : SG.navy,
                    textDecoration: dayFull ? 'line-through' : 'none',
                    textDecorationColor: dayFull ? SG.gray : 'transparent', textDecorationThickness: '2px',
                  }}>
                    {day.date.getDate()}
                  </div>
                  <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.12em', textTransform: 'uppercase', opacity: 0.6, marginTop: 2 }}>
                    {dayFull ? 'Full' : fmtDay(day.date, 'mon')}
                  </div>
                </button>
              );
            })}
          </div>

          <div style={v2Eyebrow}>Available {V2_KIND_LABEL[kind]}s · {fmtDay(selectedDay.date, 'long')}</div>
          {windows.every(w => !w.open) ? (
            <div style={{ padding: '24px 20px', borderRadius: 4, background: '#fff', border: `1.5px dashed ${SG.grayLight}`, textAlign: 'center', fontFamily: 'Barlow Condensed' }}>
              <div style={{ fontWeight: 900, fontSize: 20, color: SG.navy, textTransform: 'uppercase', letterSpacing: '0.02em', marginBottom: 6 }}>
                No {V2_KIND_LABEL[kind]} open this day
              </div>
              <div style={{ fontSize: 14, color: SG.gray, fontWeight: 500, lineHeight: 1.5, maxWidth: 380, margin: '0 auto 16px' }}>
                A {totalHours}-hour job needs a {V2_KIND_LABEL[kind]}. Try a nearby day, or get the quote first and we'll find you a slot.
              </div>
              {(() => {
                const nextOpenIdx = slots.findIndex((day, idx) => idx > selectedDateIdx && v2WindowsForDay(day, kind).some(w => w.open));
                if (nextOpenIdx === -1) return null;
                return (
                  <button onClick={() => { setSelectedDateIdx(nextOpenIdx); setData(d => ({ ...d, slot: null })); }} style={{
                    fontFamily: 'Barlow Condensed', fontWeight: 800, fontSize: 13, letterSpacing: '0.1em', textTransform: 'uppercase',
                    padding: '12px 20px', borderRadius: 4, border: 'none', background: SG.gold, color: SG.navy, cursor: 'pointer',
                  }}>
                    Next Available → {fmtDay(slots[nextOpenIdx].date, 'short')}
                  </button>
                );
              })()}
            </div>
          ) : (
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', gap: 10 }}>
              {windows.filter(w => w.open).map((w, i) => {
                const active = data.slot === w.label;
                return (
                  <button key={i} onClick={() => setData(d => ({ ...d, slot: w.label, slotStart: w.start, slotEnd: w.end, slotMode: selectedDay.mode || null }))}
                    style={{
                      padding: '15px 16px', borderRadius: 4, cursor: 'pointer', minHeight: 52,
                      background: active ? SG.navy : '#fff',
                      color: active ? '#fff' : SG.navy,
                      border: active ? `2px solid ${SG.gold}` : `1.5px solid ${SG.grayLight}`,
                      fontFamily: 'Barlow Condensed', textAlign: 'left', transition: 'all 150ms ease',
                      display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8,
                    }}>
                    <div style={{ fontWeight: 800, fontSize: 15, letterSpacing: '0.02em' }}>{w.label}</div>
                    <div style={{ width: 8, height: 8, borderRadius: '50%', flexShrink: 0, background: '#22c55e' }} />
                  </button>
                );
              })}
            </div>
          )}
        </div>
      )}

      {data.path === 'quote' && (
        <V2QuoteInfoPanel data={data} goToStep={goToStep} />
      )}
    </div>
  );
}

function V2QuoteInfoPanel({ data, goToStep }) {
  return (
    <div style={{ marginTop: 22, background: '#fff', border: `1.5px solid ${SG.grayLight}`, borderRadius: 4, padding: '20px' }}>
      <div style={v2Eyebrow}>How the Quote Works</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
        {[
          ['Within 1 hour',    'Text confirmation that we have your request.'],
          ['Within 24 hours',  'Written quote by text & email — itemized, no surprises.'],
          ['Your move',        'Approve online and pick a time, or call us with questions. No obligation.'],
        ].map(([when, what], i, arr) => (
          <div key={i} style={{ display: 'flex', alignItems: 'flex-start', gap: 16, padding: '11px 0', borderBottom: i < arr.length - 1 ? `1px dashed ${SG.grayLight}` : 'none', fontFamily: 'Barlow Condensed' }}>
            <div style={{ width: 110, flexShrink: 0, fontWeight: 700, fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase', color: SG.gold, paddingTop: 2 }}>{when}</div>
            <div style={{ fontSize: 15, fontWeight: 600, color: SG.navy, lineHeight: 1.5 }}>{what}</div>
          </div>
        ))}
      </div>
      <div style={{ marginTop: 14, fontFamily: 'Barlow Condensed', fontSize: 13, fontWeight: 600, color: SG.gray, lineHeight: 1.5 }}>
        {data.files.length > 0
          ? `${data.files.length} file${data.files.length === 1 ? '' : 's'} attached — that speeds up the quote.`
          : <React.Fragment>No photos attached yet — adding a few usually tightens the number. <button onClick={() => goToStep(1)} style={{ background: 'none', border: 'none', padding: 0, cursor: 'pointer', fontFamily: 'Barlow Condensed', fontWeight: 700, fontSize: 13, color: SG.goldDark, textDecoration: 'underline' }}>Add photos</button></React.Fragment>}
      </div>
    </div>
  );
}

Object.assign(window, { V2StepJob, V2StepPhotos, V2StepContact, V2StepSchedule, V2FileDrop, V2QuoteInfoPanel });
