// Visual primitives for the radio body — knobs, LEDs, screen, grill, buttons.
// Everything CSS — no SVG art beyond simple shapes.

const { useState, useEffect, useRef, useCallback, useMemo } = React;

function LED({color='red', on=false, size=10, glow=true, blink=false}){
  const c = color === 'red' ? 'var(--led-red)' :
            color === 'green' ? 'var(--led-green)' :
            color === 'amber' ? 'oklch(78% 0.18 80)' : color;
  const style = {
    width: size, height: size, borderRadius:'50%',
    background: on
      ? `radial-gradient(circle at 30% 30%, oklch(95% 0.04 80), ${c} 60%, oklch(20% 0.04 30) 100%)`
      : `radial-gradient(circle at 30% 30%, oklch(30% 0.02 60), oklch(15% 0.01 60))`,
    boxShadow: on && glow ? `0 0 ${size*0.8}px ${c}, 0 0 ${size*1.6}px ${c}66, inset 0 0 2px rgba(0,0,0,.6)` : 'inset 0 0 2px rgba(0,0,0,.8)',
    border: '1px solid rgba(0,0,0,.5)',
    animation: blink && on ? 'led-blink 0.6s infinite' : 'none',
    flex: '0 0 auto',
  };
  return <div style={style} />;
}

function Knob({label, value, onChange, min=0, max=10, step=1, size=78, showValue=true, marks=null}){
  // value in [min,max]; rotation -135deg .. +135deg
  const ref = useRef(null);
  const pct = (value-min)/(max-min);
  const angle = -135 + pct*270;

  // Detect touch — on touch, use rotational gesture (drag around the knob like a real one).
  // On mouse/desktop, use vertical drag (more precise with cursor).
  const isTouchEvent = (e) => !!(e.touches && e.touches.length);

  const onDown = (e) => {
    e.preventDefault();
    const touch = isTouchEvent(e);
    const rect = ref.current.getBoundingClientRect();
    const cx = rect.left + rect.width/2;
    const cy = rect.top + rect.height/2;
    const getPt = (ev) => ev.touches ? ev.touches[0] : ev;

    if(touch){
      // ----- ROTATIONAL gesture for touch -----
      const p0 = getPt(e);
      const startAng = Math.atan2(p0.clientY - cy, p0.clientX - cx) * 180/Math.PI;
      let lastAng = startAng;
      let accumDeg = 0;
      const startVal = value;
      // 270° of knob travel = full range
      const degPerUnit = 270 / (max - min);

      const move = (ev) => {
        ev.preventDefault?.();
        const p = getPt(ev);
        let a = Math.atan2(p.clientY - cy, p.clientX - cx) * 180/Math.PI;
        // unwrap so crossing ±180° doesn't jump
        let delta = a - lastAng;
        if(delta > 180) delta -= 360;
        if(delta < -180) delta += 360;
        accumDeg += delta;
        lastAng = a;
        let nv = startVal + accumDeg / degPerUnit;
        nv = Math.round(nv/step)*step;
        nv = Math.max(min, Math.min(max, nv));
        if(nv !== value) onChange(nv);
      };
      const up = () => {
        window.removeEventListener('touchmove', move);
        window.removeEventListener('touchend', up);
        window.removeEventListener('touchcancel', up);
      };
      window.addEventListener('touchmove', move, {passive:false});
      window.addEventListener('touchend', up);
      window.addEventListener('touchcancel', up);
    } else {
      // ----- VERTICAL drag for mouse -----
      const startY = e.clientY;
      const startVal = value;
      const move = (ev) => {
        const dy = startY - ev.clientY;
        const range = max - min;
        let nv = startVal + (dy/120) * range;
        nv = Math.round(nv/step)*step;
        nv = Math.max(min, Math.min(max, nv));
        if(nv !== value) onChange(nv);
      };
      const up = () => {
        window.removeEventListener('mousemove', move);
        window.removeEventListener('mouseup', up);
      };
      window.addEventListener('mousemove', move);
      window.addEventListener('mouseup', up);
    }
  };



  const onWheel = (e) => {
    e.preventDefault();
    const dir = e.deltaY < 0 ? 1 : -1;
    let nv = value + dir*step;
    nv = Math.max(min, Math.min(max, nv));
    if(nv !== value) onChange(nv);
  };

  return (
    <div style={{display:'flex', flexDirection:'column', alignItems:'center', gap:6}}>
      <div
        ref={ref}
        onMouseDown={onDown}
        onTouchStart={onDown}
        onWheel={onWheel}
        style={{
          width:size, height:size, borderRadius:'50%',
          background: 'radial-gradient(circle at 35% 28%, oklch(38% 0.008 80), oklch(15% 0.006 80) 70%, oklch(8% 0.005 80))',
          boxShadow: 'inset 0 2px 4px rgba(255,255,255,.08), inset 0 -3px 6px rgba(0,0,0,.6), 0 6px 14px rgba(0,0,0,.55), 0 1px 0 rgba(255,255,255,.06)',
          position:'relative', cursor:'grab',
          border: '1px solid oklch(10% 0 0)',
          touchAction:'none',
        }}
      >
        {/* knurled edge ticks */}
        {Array.from({length:24}).map((_,i)=>(
          <div key={i} style={{
            position:'absolute', left:'50%', top:'50%',
            width:1, height:size*0.46,
            background:'linear-gradient(to top, transparent 75%, rgba(255,255,255,.07) 80%, rgba(0,0,0,.5) 90%, transparent)',
            transform:`translate(-50%, -100%) rotate(${i*15}deg)`,
            transformOrigin:'50% 100%',
            pointerEvents:'none',
          }}/>
        ))}
        {/* center disk */}
        <div style={{
          position:'absolute', inset:'18%',
          borderRadius:'50%',
          background:'radial-gradient(circle at 35% 30%, oklch(30% 0.006 80), oklch(12% 0.004 80) 75%)',
          boxShadow:'inset 0 2px 3px rgba(255,255,255,.05), inset 0 -2px 4px rgba(0,0,0,.6)',
          transform:`rotate(${angle}deg)`,
          transition: 'transform 80ms ease-out',
        }}>
          <div style={{
            position:'absolute', left:'50%', top:6, width:3, height:'30%',
            background:'oklch(85% 0.12 70)',
            borderRadius:2, transform:'translateX(-50%)',
            boxShadow:'0 0 4px oklch(85% 0.12 70 / .6)',
          }}/>
        </div>
        {/* marks */}
        {marks && marks.map((m,i)=>{
          const a = -135 + (i/(marks.length-1))*270;
          const rad = a * Math.PI/180;
          const r = size*0.62;
          const x = size/2 + Math.sin(rad)*r;
          const y = size/2 - Math.cos(rad)*r;
          return <div key={i} style={{
            position:'absolute', left:x, top:y, transform:'translate(-50%,-50%)',
            fontSize:9, color:'var(--txt-dim)', fontFamily:'JetBrains Mono, monospace',
            letterSpacing:0.5,
          }}>{m}</div>;
        })}
      </div>
      <div style={{textAlign:'center'}}>
        <div style={{fontSize:10, color:'oklch(70% 0.01 80)', textTransform:'uppercase', letterSpacing:1.5, fontWeight:600}}>{label}</div>
        {showValue && <div style={{fontSize:11, color:'var(--txt-dim)', fontFamily:'JetBrains Mono, monospace'}}>{value}</div>}
      </div>
    </div>
  );
}

function SpeakerGrill({rows=10, cols=14}){
  return (
    <div style={{
      display:'grid',
      gridTemplateColumns:`repeat(${cols}, 1fr)`,
      gridTemplateRows:`repeat(${rows}, 1fr)`,
      gap: 4,
      padding: 10,
      borderRadius: 8,
      background:'linear-gradient(180deg, oklch(8% 0.004 80), oklch(12% 0.004 80))',
      boxShadow:'inset 0 2px 6px rgba(0,0,0,.8), inset 0 -1px 2px rgba(255,255,255,.04)',
      border:'1px solid oklch(8% 0 0)',
    }}>
      {Array.from({length: rows*cols}).map((_,i)=>(
        <div key={i} style={{
          width:'100%', aspectRatio:'1', borderRadius:'50%',
          background:'radial-gradient(circle at 30% 30%, oklch(20% 0.004 80), oklch(5% 0.002 80) 70%)',
          boxShadow:'inset 0 1px 1px rgba(0,0,0,.8), inset 0 -1px 1px rgba(255,255,255,.03)',
        }}/>
      ))}
    </div>
  );
}

// Push-to-talk side button — chunky rubberized
function PTTButton({pressed, onDown, onUp, label='PTT'}){
  return (
    <button
      onMouseDown={onDown}
      onMouseUp={onUp}
      onMouseLeave={(e)=>{ if(pressed) onUp(e); }}
      onTouchStart={(e)=>{ e.preventDefault(); onDown(e); }}
      onTouchEnd={(e)=>{ e.preventDefault(); onUp(e); }}
      style={{
        width:'100%',
        padding:'22px 0',
        borderRadius:10,
        border:'1px solid oklch(8% 0 0)',
        background: pressed
          ? 'linear-gradient(180deg, oklch(20% 0.04 27), oklch(28% 0.10 27))'
          : 'linear-gradient(180deg, oklch(32% 0.004 80), oklch(18% 0.004 80))',
        boxShadow: pressed
          ? 'inset 0 4px 8px rgba(0,0,0,.6), 0 0 14px oklch(60% 0.24 27 / .55)'
          : 'inset 0 1px 0 rgba(255,255,255,.06), 0 4px 10px rgba(0,0,0,.5)',
        color: pressed ? 'oklch(95% 0.10 60)' : 'oklch(78% 0.01 80)',
        fontFamily:'JetBrains Mono, monospace',
        fontWeight:800,
        letterSpacing:3,
        fontSize:14,
        cursor:'pointer',
        transition: 'background 60ms, box-shadow 60ms, color 60ms',
        WebkitTapHighlightColor:'transparent',
      }}
    >{label}</button>
  );
}

function KeypadButton({children, onClick, small=false}){
  const [down, setDown] = useState(false);
  return (
    <button
      onMouseDown={()=>setDown(true)}
      onMouseUp={()=>setDown(false)}
      onMouseLeave={()=>setDown(false)}
      onTouchStart={()=>setDown(true)}
      onTouchEnd={()=>setDown(false)}
      onClick={onClick}
      style={{
        height: small? 30 : 38,
        borderRadius: 6,
        border:'1px solid oklch(8% 0 0)',
        background: down
          ? 'linear-gradient(180deg, oklch(12% 0.004 80), oklch(20% 0.004 80))'
          : 'linear-gradient(180deg, oklch(28% 0.006 80), oklch(15% 0.004 80))',
        boxShadow: down
          ? 'inset 0 2px 3px rgba(0,0,0,.7)'
          : 'inset 0 1px 0 rgba(255,255,255,.07), 0 2px 4px rgba(0,0,0,.5)',
        color: 'oklch(82% 0.01 80)',
        fontFamily:'JetBrains Mono, monospace',
        fontSize: small? 10 : 12,
        fontWeight:700,
        cursor:'pointer',
        letterSpacing:0.5,
        WebkitTapHighlightColor:'transparent',
        padding:0,
      }}
    >{children}</button>
  );
}

// LCD-style screen
function Screen({channel, channelName, mode, signal, battery, txing, rxing, callsign, lastFrom, scanning, vuLevel, lastLine, squelch, log}){
  const bars = Math.round((signal/5)*5);
  return (
    <div style={{
      position:'relative',
      borderRadius:8,
      padding: 14,
      background:'linear-gradient(180deg, var(--screen-bg-2), var(--screen-bg))',
      boxShadow:'inset 0 3px 8px rgba(0,0,0,.55), inset 0 -1px 2px rgba(255,255,255,.08), 0 1px 0 rgba(255,255,255,.05)',
      border:'2px solid oklch(8% 0 0)',
      color:'oklch(20% 0.03 70)',
      fontFamily:'JetBrains Mono, monospace',
      minHeight: 168,
      overflow:'hidden',
    }}>
      {/* scanline overlay */}
      <div style={{
        position:'absolute', inset:0, pointerEvents:'none',
        backgroundImage:'repeating-linear-gradient(0deg, rgba(0,0,0,.05) 0 1px, transparent 1px 3px)',
      }}/>
      {/* top status bar */}
      <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', fontSize:10, fontWeight:700, letterSpacing:1.5}}>
        <span>{txing ? '◉ TX' : rxing ? '◉ RX' : scanning ? 'SCN' : 'STBY'}</span>
        <span>{mode}</span>
        <span style={{display:'flex', alignItems:'center', gap:3}}>
          {[1,2,3,4,5].map(i=>(
            <span key={i} style={{
              display:'inline-block', width:3, height:3+i*2,
              background: i<=bars ? 'oklch(20% 0.03 70)' : 'oklch(20% 0.03 70 / .25)',
            }}/>
          ))}
        </span>
        <span>{Math.round(battery)}%</span>
      </div>

      {/* channel display — big 7-segment style */}
      <div style={{display:'flex', alignItems:'baseline', justifyContent:'center', marginTop:6, gap:8}}>
        <span style={{
          fontFamily:'"DSEG7 Classic", "JetBrains Mono", monospace',
          fontSize: 56, fontWeight: 800, letterSpacing: 2,
          color: 'oklch(22% 0.06 80)',
          textShadow:'0 1px 0 rgba(255,255,255,.18), 0 -1px 0 rgba(0,0,0,.15)',
          lineHeight:1,
        }}>{String(channel).padStart(2,'0')}</span>
        <span style={{fontSize:10, fontWeight:700, letterSpacing:1.5, marginBottom:6}}>CH</span>
      </div>
      <div style={{textAlign:'center', fontSize:11, fontWeight:700, letterSpacing:2, marginTop:-2}}>
        {channelName}
      </div>

      {/* VU meter */}
      <div style={{display:'flex', alignItems:'center', gap:4, marginTop:10, fontSize:9, fontWeight:700}}>
        <span style={{width:18}}>VU</span>
        <div style={{flex:1, height:8, background:'oklch(30% 0.05 85)', borderRadius:2, overflow:'hidden', position:'relative'}}>
          <div style={{
            position:'absolute', left:0, top:0, bottom:0,
            width: `${Math.round(vuLevel*100)}%`,
            background:'linear-gradient(90deg, oklch(28% 0.10 145), oklch(40% 0.12 85), oklch(45% 0.18 27))',
            transition:'width 50ms linear',
          }}/>
          {/* tick marks */}
          {[20,40,60,80].map(p=>(
            <div key={p} style={{position:'absolute', left:`${p}%`, top:0, bottom:0, width:1, background:'rgba(0,0,0,.25)'}}/>
          ))}
        </div>
      </div>

      {/* squelch + callsign */}
      <div style={{display:'flex', justifyContent:'space-between', fontSize:10, marginTop:8, fontWeight:700, letterSpacing:1}}>
        <span>SQ:{squelch}</span>
        <span>ID:{callsign}</span>
      </div>

      {/* last message line */}
      <div style={{fontSize:10, marginTop:4, fontWeight:700, letterSpacing:0.5, minHeight:14, opacity:0.85}}>
        {lastLine}
      </div>
    </div>
  );
}

// Antenna (top-left protrusion)
function Antenna(){
  return (
    <div style={{position:'absolute', top:-58, left:30, width:18, height:70, pointerEvents:'none'}}>
      <div style={{
        position:'absolute', left:0, top:0, width:'100%', height:14,
        background:'linear-gradient(180deg, oklch(18% 0.005 80), oklch(8% 0.003 80))',
        borderRadius:'6px 6px 2px 2px',
        boxShadow:'inset 0 1px 0 rgba(255,255,255,.05), 0 2px 4px rgba(0,0,0,.5)',
      }}/>
      <div style={{
        position:'absolute', left:'50%', top:8, width:5, height:58,
        background:'linear-gradient(180deg, oklch(15% 0.003 80), oklch(25% 0.005 80))',
        transform:'translateX(-50%)',
        borderRadius:'3px 3px 0 0',
        boxShadow:'inset 1px 0 0 rgba(255,255,255,.06), 0 2px 3px rgba(0,0,0,.4)',
      }}/>
      <div style={{
        position:'absolute', left:'50%', top:-3, width:7, height:7,
        background:'radial-gradient(circle at 35% 30%, oklch(35% 0.006 80), oklch(10% 0.003 80))',
        transform:'translateX(-50%)',
        borderRadius:'50%',
      }}/>
    </div>
  );
}

Object.assign(window, { LED, Knob, SpeakerGrill, PTTButton, KeypadButton, Screen, Antenna });
