/* PluginShell.jsx — faithful port of the shipped plugin UI (v1.6.2).
   Zones: Start Here / Creative / Clean Up / End Here. */

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

const PEAK_ZONE_START = 0.9375;

const Meter = ({ level = 0, peak = 0, segments = 26, optimal = [0.55, 0.85], live = false, seed = 0 }) => {
  const [lo] = optimal;
  const [tick, setTick] = useState(0);

  // When live, animate a vocal-like envelope around `level`
  useEffect(() => {
    if (!live) return;
    let raf;
    const loop = () => {
      setTick(t => t + 1);
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, [live]);

  let displayLevel = level;
  let displayPeak = peak;
  if (live && level > 0) {
    const now = performance.now() / 1000;
    // Composite waveform: syllable rhythm (~3Hz) + fast speech (~11Hz) + tiny jitter
    const syllable = 0.55 + 0.45 * Math.abs(Math.sin(now * 3.1 + seed * 1.7));
    const fast = 0.85 + 0.15 * Math.sin(now * 11 + seed * 0.4);
    const env = Math.min(1.1, syllable * fast);
    displayLevel = Math.max(0.55, Math.min(0.85, level * env));
    displayPeak = Math.max(displayLevel, Math.min(0.85, level * 0.95));
  }

  const peakIdx = displayPeak > 0 ? Math.min(segments - 1, Math.floor(displayPeak * segments)) : -1;
  const cells = [];
  for (let i = 0; i < segments; i++) {
    const top = (i + 1) / segments;
    const lit = displayLevel > 0 && top <= displayLevel + 1e-6;
    let zone;
    if (top > PEAK_ZONE_START) zone = 'peak';
    else if (top > lo) zone = 'on';
    else zone = 'hot';
    const cls = ['mv-meter-seg'];
    if (lit) { cls.push('on'); if (zone !== 'on') cls.push(zone); }
    if (i === peakIdx) { cls.push('peak-hold'); if (!lit) cls.push(zone); }
    cells.push(<div key={i} className={cls.join(' ')} />);
  }
  return <div className="mv-meter">{cells}</div>;
};

const Slider = ({ value, onChange, color = 'var(--primary)', resetValue = 0 }) => {
  const ref = useRef(null);
  const [drag, setDrag] = useState(false);
  useEffect(() => {
    if (!drag) return;
    const el = ref.current; if (!el) return;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      onChange(1 - Math.min(Math.max((e.clientY - r.top) / r.height, 0), 1));
    };
    const onUp = () => setDrag(false);
    window.addEventListener('pointermove', onMove);
    window.addEventListener('pointerup', onUp);
    return () => { window.removeEventListener('pointermove', onMove); window.removeEventListener('pointerup', onUp); };
  }, [drag, onChange]);
  const onPointerDown = (e) => {
    if (e.altKey) { onChange(resetValue); return; }
    const el = ref.current; if (!el) return;
    setDrag(true);
    const r = el.getBoundingClientRect();
    onChange(1 - Math.min(Math.max((e.clientY - r.top) / r.height, 0), 1));
  };
  return (
    <div className="mv-slider" ref={ref} onPointerDown={onPointerDown}
         onDoubleClick={() => onChange(resetValue)}
         style={{ '--fill': color, '--g': value }}>
      <div className="mv-slider-track">
        <div className="mv-slider-fill" style={{ height: `${value * 100}%` }} />
        <div className="mv-slider-knob" style={{ bottom: `${value * 100}%` }} />
      </div>
    </div>
  );
};

const formatValue = (v, unit) => {
  if (unit === 'dB') {
    const db = (v - 0.5) * 24;
    const r = Math.round(db * 10) / 10;
    return `${r > 0 ? '+' : ''}${r.toFixed(1)} dB`;
  }
  return `${Math.round(v * 100)}%`;
};
const ValueDisplay = ({ value, unit = '%' }) => (
  <div className="mv-value">{formatValue(value, unit)}</div>
);

const iconGlow = (color, v) => {
  const alpha = Math.round((0.1 + v * 0.45) * 100);
  const radius = 2 + v * 6;
  return {
    color: `color-mix(in srgb, ${color} ${20 + v * 80}%, #8a8a9a)`,
    filter: `saturate(${60 + v * 140}%) drop-shadow(0 0 ${radius}px color-mix(in srgb, ${color} ${alpha}%, transparent))`,
  };
};

const Control = ({ label, icon, footIcon, value, setValue, color, bypassed, onBypassToggle, solo, dim }) => {
  const cls = ['mv-control'];
  if (bypassed) cls.push('is-bypassed');
  if (solo) cls.push('is-solo');
  if (dim) cls.push('is-dim');
  const iStyle = bypassed ? { color: '#4a4a52', filter: 'none' } : iconGlow(color, value);
  return (
    <div className={cls.join(' ')}>
      <div className="mv-control-label">{label}</div>
      <div className={`mv-control-icon mv-control-icon--top ${onBypassToggle ? 'is-clickable' : ''}`}
           style={iStyle} onClick={onBypassToggle}>
        <Icon name={icon} />
      </div>
      <div className="mv-slider-cluster">
        <Slider value={value} onChange={setValue} color={bypassed ? '#4a4a52' : color} />
      </div>
      <ValueDisplay value={value} />
      <div className="mv-control-icon mv-control-icon--foot" style={{ opacity: 0.5 }}>
        <Icon name={footIcon || icon} />
      </div>
    </div>
  );
};

const OptimalArrow = ({ side, label }) => (
  <>
    <div className={`mv-optimal-bracket mv-optimal-bracket--${side}`} style={{ bottom: '55%', height: '30%' }} />
    <div className={`mv-optimal-arrow mv-optimal-arrow--${side}`} style={{ bottom: '55%', height: '30%' }}>
      <div className="mv-optimal-arrow-label">
        {label.split(' ').map((w, i) => <div key={i}>{w}</div>)}
      </div>
    </div>
  </>
);

const RotaryKnob = ({ value, onChange, resetValue = 0.5 }) => {
  const onDown = useCallback((e) => {
    if (e.altKey) { onChange(resetValue); return; }
    const startY = e.clientY, startV = value;
    const onMove = (ev) => {
      const delta = (startY - ev.clientY) / 160;
      onChange(Math.max(0, Math.min(1, startV + delta)));
    };
    const onUp = () => { window.removeEventListener('pointermove', onMove); window.removeEventListener('pointerup', onUp); };
    window.addEventListener('pointermove', onMove);
    window.addEventListener('pointerup', onUp);
  }, [value, onChange, resetValue]);
  return (
    <div className="mv-output-knob" style={{ '--rot': `${value * 270 - 135}deg` }}
         onPointerDown={onDown} onDoubleClick={() => onChange(resetValue)} />
  );
};

const VoicePills = ({ voice, onChange }) => {
  const modes = [
    { v: 'off', icon: 'powerOff', title: 'Off' },
    { v: 'male', icon: 'userMas', title: 'Male' },
    { v: 'female', icon: 'userFem', title: 'Female' },
  ];
  return (
    <div className="mv-voicetype">
      {modes.map(m => (
        <button key={m.v} className={`mv-voice-pill ${voice === m.v ? 'on' : ''}`}
                title={m.title} onClick={() => onChange(m.v)}>
          <Icon name={m.icon} />
        </button>
      ))}
    </div>
  );
};

// Defaults match the shipped plugin: all effects at 0.3, voice Off,
// gains 0.5, auto-gain off. autoGain is a bool stored as 0|1 to mirror
// the MVPresets.json schema field.
const defaultState = {
  voice: 'off',
  input: 0.5, output: 0.5,
  power: 0.3, focus: 0.3, fat: 0.3, doubler: 0.3, reverb: 0.3, delay: 0.3, clarity: 0.3, deess: 0.3,
  autoGain: 0,
  bypass: {},
  solo: null,
};

const ZONE_GROUPS = {
  1: ['power'],
  2: ['focus', 'fat', 'doubler', 'reverb', 'delay'],
  3: ['clarity', 'deess'],
};

const PluginShell = React.forwardRef(({ state, setState, preset = 'INIT', onPresetNudge, onPresetClick, globalBypass, onGlobalBypass, hintPreset = false, hintBypass = false, isPlaying = false, locked = false }, ref) => {
  const s = state;
  const set = (k) => (v) => { if (locked) return; setState(st => ({ ...st, [k]: v })); };
  const toggleBypass = (k) => () => { if (locked) return; setState(st => ({ ...st, bypass: { ...st.bypass, [k]: !st.bypass[k] } })); };
  const toggleZone = (n) => () => {
    if (locked) return;
    const keys = ZONE_GROUPS[n];
    const allBypassed = keys.every(k => s.bypass[k]);
    setState(st => {
      const nb = { ...st.bypass };
      keys.forEach(k => { nb[k] = !allBypassed; });
      return { ...st, bypass: nb };
    });
  };
  const zoneAllBypassed = (n) => ZONE_GROUPS[n].every(k => s.bypass[k]);
  const dim = (k) => s.solo && s.solo !== k;
  const isSolo = (k) => s.solo === k;

  return (
    <div ref={ref} className={`mv-shell ${globalBypass ? 'is-bypass-global' : ''}`}>
      <div className="mv-header">
        <div className="mv-wordmark">
          Magic Vocals
          <small>Vocal Processing Suite</small>
        </div>
        <div className={`mv-preset-row ${hintPreset ? 'mv-preset-row--hint' : ''}`}>
          <div className="mv-preset-wrap">
            <button className="mv-preset-big" onClick={onPresetClick}>
              <span style={{ flex: 1, textAlign: 'left' }}>{preset}</span>
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><polyline points="6,9 12,15 18,9"/></svg>
            </button>
          </div>
          <button className="mv-nudge" onClick={() => onPresetNudge && onPresetNudge(-1)}>
            <svg viewBox="0 0 24 24"><polyline points="14,6 8,12 14,18"/></svg>
          </button>
          <button className="mv-nudge" onClick={() => onPresetNudge && onPresetNudge(1)}>
            <svg viewBox="0 0 24 24"><polyline points="10,6 16,12 10,18"/></svg>
          </button>
          <button className="mv-chip">Save</button>
          <button className="mv-chip mv-chip--disabled" disabled>Delete</button>
          <button className={`mv-chip mv-chip--bypass ${hintBypass ? 'mv-chip--hint' : ''} ${globalBypass ? 'mv-chip--bypass-on' : ''}`} onClick={onGlobalBypass}>
            {globalBypass ? 'BYPASSED' : 'Bypass'}
          </button>
        </div>
        <div className="mv-sig">
          <img src="kv/chrys-logo-cropped.svg" alt="Chrys Gringo"
               onError={(e) => { e.target.style.display = 'none'; }}/>
        </div>
      </div>

      <div className={`mv-main ${globalBypass ? 'is-bypassed' : ''} ${locked ? 'is-locked' : ''}`}>
        {/* ① START HERE */}
        <div className="mv-zone">
          <div className={`mv-zone-head is-clickable ${zoneAllBypassed(1) ? 'is-all-bypassed' : ''}`}
               onClick={toggleZone(1)}>
            <div className="mv-zone-num">1</div>
            <div className="mv-zone-title">Start Here</div>
          </div>
          <div className="mv-controls">
            <div className="mv-control mv-control--narrow">
              <div className="mv-control-label">Voice<br/>Type</div>
              <VoicePills voice={s.voice} onChange={set('voice')} />
              <div style={{ flex: 1 }} />
            </div>
            <div className="mv-control mv-control--meter">
              <div className="mv-control-label">Input</div>
              <div className="mv-control-icon mv-control-icon--top" style={iconGlow('var(--primary)', s.input)}>
                <Icon name="mic"/>
              </div>
              <div className="mv-slider-cluster mv-stereo" style={{ position: 'relative' }}>
                <Meter level={0.62 + s.input * 0.18} peak={0.65 + s.input * 0.18} live={isPlaying} seed={0.1}/>
                <Meter level={0.58 + s.input * 0.2} peak={0.63 + s.input * 0.18} live={isPlaying} seed={0.7}/>
                <OptimalArrow side="left" label="OPTIMAL INPUT"/>
              </div>
              <ValueDisplay value={s.input} unit="dB"/>
              <div style={{ display: 'flex', justifyContent: 'center' }}>
                <RotaryKnob value={s.input} onChange={set('input')}/>
              </div>
            </div>
            <div className={`mv-control mv-control--meter ${s.bypass.power ? 'is-bypassed' : ''} ${isSolo('power') ? 'is-solo' : ''} ${dim('power') ? 'is-dim' : ''}`}>
              <div className="mv-control-label">Power</div>
              <div className="mv-control-icon mv-control-icon--top is-clickable"
                   style={s.bypass.power ? { color: '#4a4a52' } : iconGlow('#ef4444', s.power)}
                   onClick={toggleBypass('power')}>
                <Icon name="bars"/>
              </div>
              <div className="mv-slider-cluster">
                <Slider value={s.power} onChange={set('power')} color={s.bypass.power ? '#4a4a52' : '#ef4444'}/>
              </div>
              <ValueDisplay value={s.power}/>
              <div className="mv-control-icon mv-control-icon--foot" style={{ opacity: 0.5 }}>
                <Icon name="bars"/>
              </div>
            </div>
          </div>
        </div>

        {/* ② CREATIVE */}
        <div className="mv-zone">
          <div className={`mv-zone-head is-clickable ${zoneAllBypassed(2) ? 'is-all-bypassed' : ''}`}
               onClick={toggleZone(2)}>
            <div className="mv-zone-num">2</div>
            <div className="mv-zone-title">Creative</div>
          </div>
          <div className="mv-controls">
            <Control label="Focus"   icon="target" value={s.focus}   setValue={set('focus')}   color="#ff7ca8" bypassed={!!s.bypass.focus}   onBypassToggle={toggleBypass('focus')}   solo={isSolo('focus')}   dim={dim('focus')}/>
            <Control label="Fat"     icon="cat"    value={s.fat}     setValue={set('fat')}     color="#ff7ca8" bypassed={!!s.bypass.fat}     onBypassToggle={toggleBypass('fat')}     solo={isSolo('fat')}     dim={dim('fat')}/>
            <Control label="Doubler" icon="user"   value={s.doubler} setValue={set('doubler')} color="#f5c518" bypassed={!!s.bypass.doubler} onBypassToggle={toggleBypass('doubler')} solo={isSolo('doubler')} dim={dim('doubler')}/>
            <Control label="Reverb"  icon="reverb" value={s.reverb}  setValue={set('reverb')}  color="#f5c518" bypassed={!!s.bypass.reverb}  onBypassToggle={toggleBypass('reverb')}  solo={isSolo('reverb')}  dim={dim('reverb')}/>
            <Control label="Delay"   icon="group"  value={s.delay}   setValue={set('delay')}   color="#f5c518" bypassed={!!s.bypass.delay}   onBypassToggle={toggleBypass('delay')}   solo={isSolo('delay')}   dim={dim('delay')}/>
          </div>
        </div>

        {/* ③ CLEAN UP */}
        <div className="mv-zone">
          <div className={`mv-zone-head is-clickable ${zoneAllBypassed(3) ? 'is-all-bypassed' : ''}`}
               onClick={toggleZone(3)}>
            <div className="mv-zone-num">3</div>
            <div className="mv-zone-title">Clean Up</div>
          </div>
          <div className="mv-controls">
            <Control label="Clarity" icon="diamond" value={s.clarity} setValue={set('clarity')} color="#a7a5ff" bypassed={!!s.bypass.clarity} onBypassToggle={toggleBypass('clarity')} solo={isSolo('clarity')} dim={dim('clarity')}/>
            <Control label="De-Ess"  icon="deess"   value={s.deess}   setValue={set('deess')}   color="#a7a5ff" bypassed={!!s.bypass.deess}   onBypassToggle={toggleBypass('deess')}   solo={isSolo('deess')}   dim={dim('deess')}/>
          </div>
        </div>

        {/* ④ END HERE */}
        <div className="mv-zone">
          <div className="mv-zone-head">
            <div className="mv-zone-num">4</div>
            <div className="mv-zone-title">End Here</div>
          </div>
          <div className="mv-controls">
            <div className="mv-control mv-control--meter">
              <div className="mv-control-label">Output</div>
              <div className="mv-control-icon mv-control-icon--top" style={iconGlow('var(--primary)', s.output)}>
                <Icon name="output"/>
              </div>
              <div className="mv-slider-cluster mv-stereo" style={{ position: 'relative' }}>
                <Meter level={0.60 + s.output * 0.2} peak={0.64 + s.output * 0.18} live={isPlaying} seed={1.3}/>
                <Meter level={0.57 + s.output * 0.22} peak={0.62 + s.output * 0.2} live={isPlaying} seed={1.9}/>
                <OptimalArrow side="right" label="OPTIMAL OUTPUT"/>
              </div>
              <ValueDisplay value={s.output} unit="dB"/>
              <div style={{ display: 'flex', justifyContent: 'center' }}>
                <RotaryKnob value={s.output} onChange={set('output')}/>
              </div>
              {/* Auto Gain toggle — matches output loudness to input so EQ
                  / comp moves are heard as shape, not as level. Ported
                  directly from the plugin's End Here zone. */}
              <button
                type="button"
                className={`mv-auto-toggle ${s.autoGain ? 'on' : ''}`}
                onClick={() => { if (locked) return; setState(st => ({ ...st, autoGain: st.autoGain ? 0 : 1 })); }}
                aria-pressed={!!s.autoGain}
                aria-label={s.autoGain ? 'Disable Auto Gain' : 'Enable Auto Gain'}
                title="Auto Gain — matches output loudness to input so EQ/comp moves are heard as shape, not level.">
                <span className="mv-auto-led"/>
                <span className="mv-auto-label">AUTO</span>
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
});

Object.assign(window, { PluginShell, defaultPluginState: defaultState, Control });
