// ============================================================
// One Roof Labs — The Map (interactive city intelligence)
// Pan/zoom SVG of scored roof polygons + property report.
// ============================================================
const { RingO: MRing, SCORE_COLORS, SCORE_LABELS, scoreBucket } = window;

function fmtMoney(n) { return '$' + n.toLocaleString('en-US'); }

// ---- Property report panel (right) ----
function ReportCard({ roof, onClose }) {
  if (!roof) return null;
  const color = SCORE_COLORS[roof.bucket];
  const flags = [];
  if (roof.ridgeSag) flags.push('Ridge sag detected');
  if (roof.deckDefl) flags.push('Deck deflection');
  return (
    <div className="report" key={roof.id}>
      <div className="report-hd">
        <div>
          <div className="kicker" style={{ fontSize: 10.5 }}>Property report</div>
          <div className="mono" style={{ fontSize: 11, color: 'var(--faint)', marginTop: 6 }}>PARCEL #{String(roof.id).padStart(5, '0')}</div>
        </div>
        <button className="report-x" onClick={onClose} aria-label="Close">✕</button>
      </div>

      <div className="report-score" style={{ borderColor: color }}>
        <div>
          <div className="mono" style={{ fontSize: 11, letterSpacing: '0.14em', color: 'var(--muted)' }}>DAMAGE SCORE</div>
          <div className="display" style={{ fontSize: 60, lineHeight: 1, color, marginTop: 4 }}>{roof.score}</div>
        </div>
        <div style={{ textAlign: 'right' }}>
          <span className="score-dot" style={{ background: color, width: 14, height: 14, display: 'inline-block' }} />
          <div className="mono" style={{ fontSize: 12, color: 'var(--paper)', marginTop: 8, maxWidth: 120 }}>{SCORE_LABELS[roof.bucket]}</div>
        </div>
      </div>

      <div style={{ padding: '4px 0' }}>
        <div className="report-addr display" style={{ fontSize: 22, color: 'var(--paper)' }}>{roof.address}</div>
        <div className="mono" style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 6 }}>Colorado Springs, CO 80903</div>
      </div>

      {/* RGB ortho placeholder */}
      <div className="ortho">
        <div className="ortho-grid" />
        <div style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center' }}>
          <span className="mono" style={{ fontSize: 11, letterSpacing: '0.18em', color: 'var(--faint)' }}>RGB ORTHOMOSAIC · 100MP</span>
        </div>
        <div className="roof-poly" style={{ borderColor: SCORE_COLORS[roof.bucket] }} />
      </div>

      {[['Damage type', roof.damage], ['Owner', roof.owner + ' (blurred)'], ['Material', roof.material],
        ['Roof age (est.)', roof.age + ' yrs'], ['Footprint', roof.area.toLocaleString() + ' ft²'],
        ['Est. replacement', fmtMoney(roof.cost)], ['Last scan', roof.scanDate]].map(([k, v]) => (
        <div className="spec-row" key={k}><span className="k">{k}</span>
          <span className="v" style={{ filter: k === 'Owner' ? 'blur(0px)' : 'none' }}>
            {k === 'Owner' ? <span><span style={{ filter: 'blur(3.5px)' }}>{roof.owner}</span></span> : v}
          </span></div>
      ))}

      {flags.length > 0 && (
        <div style={{ marginTop: 16, border: '1px solid var(--score-high)', padding: '12px 14px' }}>
          <div className="mono" style={{ fontSize: 11, letterSpacing: '0.12em', color: 'var(--score-high)', marginBottom: 8 }}>⚠ STRUCTURAL FLAGS</div>
          {flags.map((f) => <div key={f} className="mono" style={{ fontSize: 12.5, color: 'var(--paper-dim)' }}>— {f}</div>)}
        </div>
      )}

      <a href="#contractors" className="btn" style={{ width: '100%', justifyContent: 'center', marginTop: 18 }}>
        Route to contractor <span className="arrow">→</span>
      </a>
    </div>
  );
}

// ---- Distribution histogram ----
function Distribution({ counts, total, filters, onToggle }) {
  const order = [['high', '75–100'], ['med', '50–74'], ['low', '25–49'], ['ok', '0–24']];
  const max = Math.max(...Object.values(counts), 1);
  return (
    <div>
      {order.map(([b, range]) => {
        const c = counts[b] || 0;
        const active = filters.has(b);
        return (
          <button key={b} className={'dist-row' + (active ? '' : ' off')} onClick={() => onToggle(b)}>
            <span className="score-dot" style={{ background: SCORE_COLORS[b], opacity: active ? 1 : 0.3 }} />
            <span className="mono dist-range">{range}</span>
            <span className="dist-bar"><span style={{ width: (c / max * 100) + '%', background: SCORE_COLORS[b], opacity: active ? 0.9 : 0.25 }} /></span>
            <span className="mono dist-count" style={{ opacity: active ? 1 : 0.4 }}>{c.toLocaleString()}</span>
          </button>
        );
      })}
      <div className="mono" style={{ fontSize: 11, color: 'var(--faint)', marginTop: 12, letterSpacing: '0.1em' }}>
        {total.toLocaleString()} PARCELS · TAP TO FILTER
      </div>
    </div>
  );
}

function MapSection() {
  const { roofs, streets, parks, VW, VH } = React.useMemo(() => window.generateCity(7, 2400, 1500), []);
  const [selected, setSelected] = React.useState(null);
  const [filters, setFilters] = React.useState(new Set(['high', 'med', 'low', 'ok']));
  const [query, setQuery] = React.useState('');
  const [view, setView] = React.useState({ x: 0, y: 0, k: 1 });
  const wrapRef = React.useRef(null);
  const drag = React.useRef(null);

  const counts = React.useMemo(() => {
    const c = { high: 0, med: 0, low: 0, ok: 0 };
    roofs.forEach((r) => c[r.bucket]++);
    return c;
  }, [roofs]);

  const q = query.trim().toLowerCase();
  const matches = (r) => filters.has(r.bucket) && (!q || r.address.toLowerCase().includes(q));

  const toggle = (b) => setFilters((prev) => {
    const n = new Set(prev);
    n.has(b) ? n.delete(b) : n.add(b);
    if (n.size === 0) return new Set(['high', 'med', 'low', 'ok']);
    return n;
  });

  // pan
  const onPointerDown = (e) => {
    if (e.target.closest('.roof')) return;
    drag.current = { x: e.clientX, y: e.clientY, vx: view.x, vy: view.y, moved: false };
  };
  const onPointerMove = (e) => {
    if (!drag.current) return;
    const dx = e.clientX - drag.current.x, dy = e.clientY - drag.current.y;
    if (Math.abs(dx) + Math.abs(dy) > 3) drag.current.moved = true;
    setView((v) => ({ ...v, x: drag.current.vx + dx, y: drag.current.vy + dy }));
  };
  const onPointerUp = () => { drag.current = null; };

  const zoomBy = (factor, cx, cy) => {
    setView((v) => {
      const k = Math.max(0.18, Math.min(6, v.k * factor));
      const rect = wrapRef.current.getBoundingClientRect();
      const px = (cx ?? rect.width / 2) - rect.left;
      const py = (cy ?? rect.height / 2) - rect.top;
      const nx = px - (px - v.x) * (k / v.k);
      const ny = py - (py - v.y) * (k / v.k);
      return { x: nx, y: ny, k };
    });
  };
  const onWheel = (e) => {
    // Only zoom the map on pinch (ctrlKey) so normal page scroll passes through.
    if (!e.ctrlKey) return;
    e.preventDefault();
    zoomBy(e.deltaY < 0 ? 1.12 : 0.89, e.clientX, e.clientY);
  };
  // fit the whole tile into the viewport
  const fitView = React.useCallback(() => {
    const el = wrapRef.current;
    if (!el) return;
    const rect = el.getBoundingClientRect();
    if (!rect.width || !rect.height) return;
    const pad = 28;
    const k = Math.min((rect.width - pad * 2) / VW, (rect.height - pad * 2) / VH);
    setView({ x: (rect.width - VW * k) / 2, y: (rect.height - VH * k) / 2, k });
  }, [VW, VH]);
  React.useEffect(() => {
    fitView();
    window.addEventListener('resize', fitView);
    return () => window.removeEventListener('resize', fitView);
  }, [fitView]);
  const reset = () => { fitView(); setSelected(null); };

  return (
    <section className="section" id="map" style={{ scrollMarginTop: 80, overflow: 'hidden' }}>
      <div className="wrap">
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', flexWrap: 'wrap', gap: 24 }}>
          <div style={{ maxWidth: 720 }}>
            <div className="kicker" style={{ marginBottom: 18, display: 'flex', gap: 14 }}>
              <span style={{ color: 'var(--faint)' }}>C.0</span><span>The Map</span>
            </div>
            <h2 className="display" style={{ fontSize: 'clamp(32px, 4.6vw, 56px)', margin: 0, color: 'var(--paper)' }}>Every roof is a job.</h2>
            <p className="lead" style={{ marginTop: 20, maxWidth: 600 }}>
              City-scale roof intelligence — a live tile of Colorado Springs. Every home is scored;
              click any roof for its full property report.
            </p>
          </div>
        </div>
      </div>

      <div className="map-frame">
        <div className="map-embed ticked">
      <MapInner roofs={roofs} streets={streets} parks={parks} VW={VW} VH={VH}
        selected={selected} setSelected={setSelected} filters={filters} setFilters={setFilters}
        query={query} setQuery={setQuery} view={view} setView={setView} wrapRef={wrapRef}
        drag={drag} counts={counts} matches={matches} toggle={toggle}
        onPointerDown={onPointerDown} onPointerMove={onPointerMove} onPointerUp={onPointerUp}
        onWheel={onWheel} zoomBy={zoomBy} reset={reset} />
        </div>
      </div>
    </section>
  );
}

function MapInner({ roofs, streets, parks, VW, VH, selected, setSelected, filters,
  query, setQuery, view, wrapRef, drag, counts, matches, toggle,
  onPointerDown, onPointerMove, onPointerUp, onWheel, zoomBy, reset }) {
  return (
    <>
      {/* LEFT INTEL PANEL */}
      <aside className="intel">
        <div className="intel-top">
        <a href="#top" className="nav-logo" style={{ marginBottom: 4 }}>
            <span className="ring" style={{ width: 26, height: 26 }}><MRing size={26} /></span>
            <span className="wm" style={{ fontSize: 17, letterSpacing: '0.1em' }}>NE&nbsp;ROOF</span>
          </a>
          <div className="kicker" style={{ fontSize: 10.5, marginTop: 18 }}>Active market</div>
          <div className="display" style={{ fontSize: 26, color: 'var(--paper)', marginTop: 8 }}>Colorado Springs</div>
          <div className="mono" style={{ fontSize: 11.5, color: 'var(--faint)', marginTop: 6, letterSpacing: '0.1em' }}>
            38.8339° N · 104.8214° W
          </div>
        </div>

        <div className="intel-search">
          <input value={query} onChange={(e) => setQuery(e.target.value)}
            placeholder="Search address…" className="search-field" />
        </div>

        <div className="intel-block">
          <div className="kicker" style={{ fontSize: 10.5, marginBottom: 16 }}>Score distribution</div>
          <Distribution counts={counts} total={roofs.length} filters={filters} onToggle={toggle} />
        </div>

        <div className="intel-foot mono">
          <div className="spec-row"><span className="k">SCAN DATE</span><span className="v">2026-05-17</span></div>
          <div className="spec-row"><span className="k">RETURN DENSITY</span><span className="v">463 pts/m²</span></div>
          <div className="spec-row"><span className="k">ACCURACY</span><span className="v">1cm RMSE</span></div>
        </div>
      </aside>

      {/* MAP */}
      <div className="map-stage" ref={wrapRef}
           onPointerDown={onPointerDown} onPointerMove={onPointerMove}
           onPointerUp={onPointerUp} onPointerLeave={onPointerUp} onWheel={onWheel}>
        <div className="gridlines" style={{ opacity: 0.22, maskImage: 'none', WebkitMaskImage: 'none' }} />
        <svg width="100%" height="100%" style={{ position: 'absolute', inset: 0, cursor: drag.current ? 'grabbing' : 'grab' }}>
          <g transform={`translate(${view.x} ${view.y}) scale(${view.k})`}>
            <rect x="0" y="0" width={VW} height={VH} fill="#0A0906" />
            {/* parks */}
            {parks.map((p, i) => (
              <g key={'pk' + i}>
                <rect x={p.x} y={p.y} width={p.w} height={p.h} fill="rgba(95,168,106,0.09)"
                  stroke="rgba(95,168,106,0.28)" strokeWidth="1.2" vectorEffect="non-scaling-stroke" />
                <text x={p.x + p.w / 2} y={p.y + p.h / 2} fill="rgba(95,168,106,0.6)"
                  fontFamily="var(--mono)" fontSize="17" textAnchor="middle"
                  style={{ letterSpacing: '2px', textTransform: 'uppercase' }}>{p.name}</text>
              </g>
            ))}
            {/* street casings + surface */}
            {streets.map((s, i) => <path key={'sc' + i} d={s.d} fill="none" stroke="#221d15"
              strokeWidth={s.width + 6} strokeLinecap="round" strokeLinejoin="round" />)}
            {streets.map((s, i) => <path key={'ss' + i} d={s.d} fill="none"
              stroke={s.kind === 'arterial' ? '#3b3324' : '#2c2719'}
              strokeWidth={s.width} strokeLinecap="round" strokeLinejoin="round" />)}
            {/* street name labels */}
            <defs>{streets.map((s, i) => <path key={'lp' + i} id={'lp' + i} d={s.d} />)}</defs>
            {streets.map((s, i) => (
              <text key={'lt' + i} fontFamily="var(--mono)" fontSize="13"
                fill="rgba(241,230,207,0.26)" style={{ letterSpacing: '1.5px' }}>
                <textPath href={'#lp' + i} startOffset="9%">{s.name}</textPath>
              </text>
            ))}
            {/* houses — roof outlined in score color */}
            {roofs.map((r) => {
              const on = matches(r);
              const sel = selected && selected.id === r.id;
              const col = SCORE_COLORS[r.bucket];
              return (
                <g key={r.id} opacity={on ? 1 : 0.07}>
                  <polygon className={'roof' + (sel ? ' sel' : '')}
                    points={window.polyPoints(r.poly)}
                    fill={col} fillOpacity={sel ? 0.5 : 0.24}
                    stroke={col} strokeWidth={sel ? 2.4 : 1.3}
                    vectorEffect="non-scaling-stroke"
                    onClick={(e) => { e.stopPropagation(); if (!drag.current || !drag.current.moved) setSelected(r); }} />
                  {r.ridges.map((ln, k) => (
                    <line key={k} x1={ln[0][0]} y1={ln[0][1]} x2={ln[1][0]} y2={ln[1][1]}
                      stroke={col} strokeOpacity="0.55" strokeWidth="0.8"
                      vectorEffect="non-scaling-stroke" style={{ pointerEvents: 'none' }} />
                  ))}
                </g>
              );
            })}
          </g>
        </svg>

        {/* scan sweep */}
        <div className="map-scan" />

        {/* HUD top */}
        <div className="map-hud-top">
          <span className="mono">COLORADO SPRINGS · TILE 17-N</span>
          <span className="mono">{roofs.filter(matches).length.toLocaleString()} / {roofs.length.toLocaleString()} VISIBLE</span>
        </div>

        {/* legend */}
        <div className="map-legend">
          {[['high', '75–100 · Replace'], ['med', '50–74 · Near-term'], ['low', '25–49 · Monitor'], ['ok', '0–24 · Healthy']].map(([b, l]) => (
            <span key={b} className="mono leg-item"><i className="score-dot" style={{ background: SCORE_COLORS[b] }} />{l}</span>
          ))}
        </div>

        {/* zoom controls */}
        <div className="map-zoom">
          <button onClick={() => zoomBy(1.25)}>+</button>
          <button onClick={() => zoomBy(0.8)}>−</button>
          <button onClick={reset} title="Reset view">⟲</button>
        </div>

        <div className="map-hint mono">DRAG TO PAN · ⌘/PINCH TO ZOOM · CLICK A ROOF</div>
      </div>

      {/* REPORT */}
      <ReportCard roof={selected} onClose={() => setSelected(null)} />
    </>
  );
}

Object.assign(window, { MapSection });
