// Shared helpers: cursor, audio, crosses bg
// Exports to window: Cursor, useAudio, CrossesBg, Chrome, FloatingCross

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

// ==== AUDIO ENGINE ====
let _audioCtx = null;
function getCtx() {
  if (!_audioCtx) {
    _audioCtx = new (window.AudioContext || window.webkitAudioContext)();
  }
  if (_audioCtx.state === 'suspended') _audioCtx.resume();
  return _audioCtx;
}

function play808(freq = 55, dur = 0.35, vol = 0.25) {
  try {
    const ctx = getCtx();
    const osc = ctx.createOscillator();
    const gain = ctx.createGain();
    osc.type = 'sine';
    osc.frequency.setValueAtTime(freq * 3, ctx.currentTime);
    osc.frequency.exponentialRampToValueAtTime(freq, ctx.currentTime + 0.08);
    gain.gain.setValueAtTime(vol, ctx.currentTime);
    gain.gain.exponentialRampToValueAtTime(0.0001, ctx.currentTime + dur);
    osc.connect(gain).connect(ctx.destination);
    osc.start();
    osc.stop(ctx.currentTime + dur);
  } catch (e) {}
}

function playClick() {
  try {
    const ctx = getCtx();
    // short noise burst
    const buffer = ctx.createBuffer(1, ctx.sampleRate * 0.08, ctx.sampleRate);
    const data = buffer.getChannelData(0);
    for (let i = 0; i < data.length; i++) {
      data[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / data.length, 3);
    }
    const src = ctx.createBufferSource();
    src.buffer = buffer;
    const gain = ctx.createGain();
    gain.gain.value = 0.12;
    const filter = ctx.createBiquadFilter();
    filter.type = 'highpass';
    filter.frequency.value = 2000;
    src.connect(filter).connect(gain).connect(ctx.destination);
    src.start();
  } catch (e) {}
}

function playCrackle() {
  try {
    const ctx = getCtx();
    const buffer = ctx.createBuffer(1, ctx.sampleRate * 0.3, ctx.sampleRate);
    const data = buffer.getChannelData(0);
    for (let i = 0; i < data.length; i++) {
      data[i] = (Math.random() > 0.985) ? (Math.random() * 2 - 1) * 0.7 : 0;
    }
    const src = ctx.createBufferSource();
    src.buffer = buffer;
    const gain = ctx.createGain();
    gain.gain.value = 0.18;
    src.connect(gain).connect(ctx.destination);
    src.start();
  } catch (e) {}
}

function playHover() {
  try {
    const ctx = getCtx();
    const osc = ctx.createOscillator();
    const gain = ctx.createGain();
    osc.type = 'square';
    osc.frequency.value = 1800;
    gain.gain.setValueAtTime(0.03, ctx.currentTime);
    gain.gain.exponentialRampToValueAtTime(0.0001, ctx.currentTime + 0.04);
    osc.connect(gain).connect(ctx.destination);
    osc.start();
    osc.stop(ctx.currentTime + 0.04);
  } catch (e) {}
}

window.TP_Audio = { play808, playClick, playCrackle, playHover, getCtx };

// ==== CURSOR ====
function Cursor() {
  const cursorRef = useRef(null);
  const trailRef = useRef(null);
  const posRef = useRef({ x: 0, y: 0 });
  const trailPosRef = useRef({ x: 0, y: 0 });
  const [clicking, setClicking] = useState(false);

  useEffect(() => {
    const onMove = (e) => {
      posRef.current = { x: e.clientX, y: e.clientY };
      if (cursorRef.current) {
        cursorRef.current.style.transform = `translate(${e.clientX}px, ${e.clientY}px) translate(-50%, -50%)`;
      }
    };
    const onDown = () => { setClicking(true); TP_Audio.playClick(); };
    const onUp = () => setClicking(false);

    window.addEventListener('mousemove', onMove);
    window.addEventListener('mousedown', onDown);
    window.addEventListener('mouseup', onUp);

    let raf;
    const loop = () => {
      trailPosRef.current.x += (posRef.current.x - trailPosRef.current.x) * 0.18;
      trailPosRef.current.y += (posRef.current.y - trailPosRef.current.y) * 0.18;
      if (trailRef.current) {
        trailRef.current.style.transform = `translate(${trailPosRef.current.x}px, ${trailPosRef.current.y}px) translate(-50%, -50%)`;
      }
      raf = requestAnimationFrame(loop);
    };
    loop();
    return () => {
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mousedown', onDown);
      window.removeEventListener('mouseup', onUp);
      cancelAnimationFrame(raf);
    };
  }, []);

  const crossSvg = (
    <svg viewBox="0 0 24 32" fill="none" stroke="currentColor" strokeWidth="2.5">
      <path d="M12 2 L12 30 M4 10 L20 10" strokeLinecap="square" />
    </svg>
  );

  return (
    <>
      <div ref={trailRef} className="cursor-trail" style={{
        transform: clicking ? 'translate(-50%, -50%) rotate(15deg) scale(1.4)' : undefined
      }}>
        {crossSvg}
      </div>
      <div ref={cursorRef} className="cursor" style={{
        transform: clicking ? 'translate(-50%, -50%) scale(0.7)' : undefined
      }}>
        {crossSvg}
      </div>
    </>
  );
}

// ==== CHROME (top bar) ====
function Chrome({ nicheScore, screen }) {
  const [time, setTime] = useState('');
  useEffect(() => {
    const upd = () => {
      const d = new Date();
      const pad = (n) => String(n).padStart(2, '0');
      setTime(`${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`);
    };
    upd();
    const t = setInterval(upd, 1000);
    return () => clearInterval(t);
  }, []);

  return (
    <div className="chrome">
      <div>
        <span className="rec">REC</span>
        <span style={{ marginLeft: 16 }}>ТЕМНЫЙ.ПРИНЦ.EXE</span>
      </div>
      <div style={{ display: 'flex', gap: 24 }}>
        <span>SCR / {screen}</span>
        <span>NICHE {String(nicheScore).padStart(3, '0')}%</span>
        <span>{time}</span>
      </div>
    </div>
  );
}

// ==== FLOATING CROSSES BG ====
function CrossesBg({ count = 24, seed = 0 }) {
  const crosses = useMemo(() => {
    const arr = [];
    let s = seed || 1;
    const rnd = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };
    for (let i = 0; i < count; i++) {
      arr.push({
        left: rnd() * 100,
        top: rnd() * 100,
        size: 10 + rnd() * 40,
        rot: (rnd() - 0.5) * 40,
        opacity: 0.08 + rnd() * 0.35,
        char: rnd() > 0.7 ? '†︎' : (rnd() > 0.5 ? '✟︎' : '✝︎'),
      });
    }
    return arr;
  }, [count, seed]);

  return (
    <div style={{ position: 'absolute', inset: 0, overflow: 'hidden', pointerEvents: 'none' }}>
      {crosses.map((c, i) => (
        <span key={i} className="floating-cross" style={{
          left: `${c.left}%`,
          top: `${c.top}%`,
          fontSize: `${c.size}px`,
          transform: `rotate(${c.rot}deg)`,
          opacity: c.opacity,
        }}>{c.char}</span>
      ))}
    </div>
  );
}

Object.assign(window, { Cursor, Chrome, CrossesBg, play808, playClick, playCrackle, playHover });

// ==== BG VIDEO ====
function BgVideo({ src = 'assets/overdose.mp4', opacity = 0.35, blur = 0 }) {
  const ref = useRef(null);
  useEffect(() => {
    const v = ref.current;
    if (!v) return;
    v.muted = true; // ensure muted for autoplay policy
    v.play().catch(() => {});
  }, []);
  return (
    <video
      ref={ref}
      src={src}
      autoPlay
      muted
      loop
      playsInline
      preload="auto"
      style={{
        position: 'fixed',
        inset: 0,
        width: '100%',
        height: '100%',
        objectFit: 'cover',
        zIndex: 0,
        opacity,
        filter: `grayscale(0.3) contrast(1.1) brightness(0.55) hue-rotate(260deg) saturate(1.4) blur(${blur}px)`,
        mixBlendMode: 'screen',
        pointerEvents: 'none',
      }}
    />
  );
}
window.BgVideo = BgVideo;
