/* map.jsx — LocalMap: illustrated, pannable, zoomable map with clickable pins.
   Props: items[{id,mx,my,...}], selectedId, onSelect, mapStyle, accent, pinIcon(item) */

const MAP_W = 1100, MAP_H = 760;

/* ---- The illustrated base (rivers, parks, roads, contours) ---- */
function MapArt({ style }) {
  const blueprint = style === 'blueprint';
  const minimal = style === 'minimal';

  const bg = blueprint ? '#1d3127' : (minimal ? '#f3ead8' : '#efe4cb');
  const land = blueprint ? '#22382c' : (minimal ? '#f3ead8' : '#ece0c4');
  const river = blueprint ? 'none' : (minimal ? '#cfe0df' : '#9fc3c6');
  const riverStroke = blueprint ? 'rgba(150,205,205,.55)' : 'none';
  const park = blueprint ? '#274232' : (minimal ? '#e3e0c0' : '#bcc99a');
  const parkStroke = blueprint ? 'rgba(150,205,170,.4)' : 'none';
  const road = blueprint ? 'rgba(220,230,225,.16)' : (minimal ? 'rgba(120,105,75,.14)' : 'rgba(120,98,60,.22)');
  const roadMajor = blueprint ? 'rgba(225,180,120,.4)' : 'rgba(150,110,60,.4)';
  const contour = blueprint ? 'rgba(150,205,180,.12)' : 'rgba(120,98,60,.14)';

  // Fraser river: enters top center, curves down & exits bottom-right
  const fraser = "M560 -20 C 600 120, 540 200, 600 300 C 660 400, 720 440, 700 540 C 685 620, 760 700, 820 800";
  // Nechako: enters left, joins around (640,330)
  const nechako = "M-20 230 C 180 250, 320 300, 470 300 C 560 300, 600 310, 640 335";

  const roads = [];
  for (let i = 1; i < 9; i++) roads.push(<line key={'h'+i} x1="0" y1={i*MAP_H/9} x2={MAP_W} y2={i*MAP_H/9} />);
  for (let i = 1; i < 12; i++) roads.push(<line key={'v'+i} x1={i*MAP_W/12} y1="0" x2={i*MAP_W/12} y2={MAP_H} />);

  return (
    <svg width={MAP_W} height={MAP_H} viewBox={`0 0 ${MAP_W} ${MAP_H}`} style={{ display:'block' }}>
      <rect width={MAP_W} height={MAP_H} fill={bg} />
      {/* contour texture, corners */}
      <g fill="none" stroke={contour} strokeWidth="2">
        {[40,80,120,160,200,240].map((r,i)=><circle key={'c1'+i} cx="-30" cy={MAP_H+30} r={r+60}/>)}
        {[40,80,120,160,200].map((r,i)=><circle key={'c2'+i} cx={MAP_W+40} cy="-20" r={r+40}/>)}
      </g>
      {/* parks */}
      <g fill={park} stroke={parkStroke} strokeWidth="2">
        <path d="M300 540 q60 -70 150 -50 q70 20 50 100 q-20 80 -120 70 q-110 -10 -80 -120z" />
        <path d="M360 180 q70 -40 130 10 q40 50 -10 100 q-70 50 -140 0 q-50 -60 20 -110z" />
        <path d="M740 250 q60 -10 80 50 q10 60 -60 70 q-70 0 -60 -70 q5 -45 40 -50z" />
        <path d="M180 360 q40 -50 90 -10 q30 40 -10 80 q-60 30 -90 -20 q-15 -30 10 -50z" />
      </g>
      {/* roads */}
      <g stroke={road} strokeWidth="2">{roads}</g>
      <g stroke={roadMajor} strokeWidth="3.5" fill="none" strokeLinecap="round">
        <path d="M40 120 C 300 160, 520 120, 760 240 S 980 520, 1060 560" />
        <path d="M120 700 C 320 560, 420 520, 620 540 S 900 460, 1020 240" />
      </g>
      {/* rivers */}
      <g fill="none" strokeLinecap="round">
        <path d={fraser} stroke={river === 'none' ? riverStroke : river} strokeWidth={river === 'none' ? 4 : 46} />
        <path d={nechako} stroke={river === 'none' ? riverStroke : river} strokeWidth={river === 'none' ? 4 : 34} />
        {!blueprint && <>
          <path d={fraser} stroke="rgba(255,255,255,.35)" strokeWidth="6" />
          <path d={nechako} stroke="rgba(255,255,255,.3)" strokeWidth="5" />
        </>}
      </g>
    </svg>
  );
}

function LocalMap({ items = [], selectedId, onSelect, mapStyle = 'illustrated', accent = '#c4612e', pinIcon }) {
  const vpRef = React.useRef(null);
  const [vp, setVp] = React.useState({ w: 800, h: 520 });
  const [t, setT] = React.useState({ s: 0.78, x: 0, y: 0 });
  const drag = React.useRef(null);
  const [hover, setHover] = React.useState(null);

  // fit on mount / resize
  React.useEffect(() => {
    const el = vpRef.current; if (!el) return;
    const ro = new ResizeObserver(() => {
      const r = el.getBoundingClientRect();
      setVp({ w: r.width, h: r.height });
    });
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  React.useEffect(() => {
    // center the map within viewport at current scale
    setT(prev => {
      const s = prev.s;
      return { s, x: (vp.w - MAP_W * s) / 2, y: (vp.h - MAP_H * s) / 2 };
    });
  // eslint-disable-next-line
  }, [vp.w, vp.h]);

  const clamp = (s) => Math.min(2.6, Math.max(0.5, s));

  const zoomAt = (cx, cy, factor) => {
    setT(prev => {
      const s2 = clamp(prev.s * factor);
      const k = s2 / prev.s;
      return { s: s2, x: cx - (cx - prev.x) * k, y: cy - (cy - prev.y) * k };
    });
  };

  const onWheel = (e) => {
    e.preventDefault();
    const r = vpRef.current.getBoundingClientRect();
    zoomAt(e.clientX - r.left, e.clientY - r.top, e.deltaY < 0 ? 1.12 : 0.89);
  };
  const onDown = (e) => {
    drag.current = { x: e.clientX, y: e.clientY, tx: t.x, ty: t.y, moved: 0 };
    e.currentTarget.setPointerCapture(e.pointerId);
  };
  const onMove = (e) => {
    if (!drag.current) return;
    const dx = e.clientX - drag.current.x, dy = e.clientY - drag.current.y;
    drag.current.moved += Math.abs(dx) + Math.abs(dy);
    setT(prev => ({ ...prev, x: drag.current.tx + dx, y: drag.current.ty + dy }));
  };
  const onUp = (e) => { drag.current = null; };

  const screen = (it) => ({
    x: t.x + (it.mx / 100) * MAP_W * t.s,
    y: t.y + (it.my / 100) * MAP_H * t.s,
  });

  const blueprint = mapStyle === 'blueprint';

  return (
    <div className="ff-map" ref={vpRef}
      style={{ position:'relative', width:'100%', height:'100%', overflow:'hidden',
        background: blueprint ? '#1d3127' : '#efe4cb', cursor: drag.current ? 'grabbing':'grab',
        borderRadius:'inherit', touchAction:'none' }}
      onWheel={onWheel} onPointerDown={onDown} onPointerMove={onMove} onPointerUp={onUp} onPointerLeave={onUp}>

      {/* transformed art */}
      <div style={{ position:'absolute', left:0, top:0, width:MAP_W, height:MAP_H,
        transform:`translate(${t.x}px,${t.y}px) scale(${t.s})`, transformOrigin:'0 0', willChange:'transform' }}>
        <MapArt style={mapStyle} />
      </div>

      {/* pins (constant size, computed) */}
      {items.map(it => {
        const p = screen(it);
        if (p.x < -40 || p.x > vp.w + 40 || p.y < -60 || p.y > vp.h + 40) return null;
        const sel = it.id === selectedId, hov = it.id === hover;
        return (
          <button key={it.id} className="ff-pin"
            onPointerDown={(e)=>e.stopPropagation()}
            onClick={(e)=>{ e.stopPropagation(); onSelect && onSelect(it); }}
            onMouseEnter={()=>setHover(it.id)} onMouseLeave={()=>setHover(null)}
            style={{ position:'absolute', left:p.x, top:p.y, transform:'translate(-50%,-100%)',
              border:'none', background:'none', padding:0, zIndex: sel?40:(hov?30:10) }}>
            <span style={{ position:'relative', display:'block', width:38, height:48,
              transition:'transform .15s', transform: sel?'scale(1.15)':(hov?'scale(1.08)':'scale(1)') }}>
              <svg width="38" height="48" viewBox="0 0 38 48" style={{ filter:'drop-shadow(0 4px 5px rgba(40,30,15,.35))' }}>
                <path d="M19 47C11 38 4 31 4 19a15 15 0 0 1 30 0c0 12-7 19-15 28z"
                  fill={sel?accent:(blueprint?'#2d4a3a':'#fffaf0')} stroke={sel?'#fff':accent} strokeWidth="2.5"/>
                <circle cx="19" cy="18.5" r="7.5" fill={sel?'#fffaf0':accent}/>
              </svg>
              {pinIcon && <span style={{ position:'absolute', left:'50%', top:18, transform:'translate(-50%,-50%)',
                color: sel?accent:'#fffaf0', display:'flex' }}>{pinIcon(it)}</span>}
            </span>
            {(hov||sel) && it.name &&
              <span style={{ position:'absolute', left:'50%', top:50, transform:'translateX(-50%)',
                whiteSpace:'nowrap', fontFamily:'var(--display)', fontWeight:700, fontSize:13,
                background:'#2c2519', color:'#f6efe0', padding:'4px 9px', borderRadius:7, pointerEvents:'none' }}>
                {it.name || it.addr}
              </span>}
          </button>
        );
      })}

      {/* zoom controls */}
      <div style={{ position:'absolute', right:14, bottom:14, display:'flex', flexDirection:'column', gap:7, zIndex:60 }}>
        {[['+',1.25],['−',0.8]].map(([lbl,f])=>(
          <button key={lbl} onClick={()=>zoomAt(vp.w/2, vp.h/2, f)} aria-label={lbl==='+'?'Zoom in':'Zoom out'}
            style={{ width:40, height:40, borderRadius:11, border:'1.5px solid var(--line)', background:'#fffdf6',
              fontSize:22, fontWeight:600, color:'var(--ink)', lineHeight:1, display:'grid', placeItems:'center',
              boxShadow:'0 4px 10px -6px rgba(40,30,15,.4)' }}>{lbl}</button>
        ))}
      </div>

      {/* compass */}
      <div style={{ position:'absolute', left:14, top:14, zIndex:60, fontFamily:'var(--display)', fontWeight:800,
        fontSize:12, letterSpacing:'.1em', color: blueprint?'rgba(246,239,224,.7)':'var(--ink-soft)',
        display:'flex', alignItems:'center', gap:6 }}>
        <svg width="26" height="26" viewBox="0 0 26 26" fill="none" stroke="currentColor" strokeWidth="1.4">
          <circle cx="13" cy="13" r="11"/><path d="M13 3 L16 13 L13 23 L10 13 Z" fill="currentColor" stroke="none" opacity=".8"/>
        </svg>N
      </div>
    </div>
  );
}

Object.assign(window, { LocalMap, MapArt, MAP_W, MAP_H });
