import React, { useState, useRef, useCallback, useEffect } from 'react';
import ReactDOM from 'react-dom/client';

// --- TYPES ---
interface GlitchParams {
  frequency: number;
  amplitude: number;
  speed: number;
  blockiness: number;
  rgbSplit: number;
  scanlineOpacity: number;
  colorDepth: number;
  datamosh: number;
  zoom: number;
  panX: number;
  panY: number;
  echo: number;
  timeDisplacement: number;
  colorInvert: boolean;
  hueShift: number;
  mirrorHorizontal: number;
  mirrorVertical: number;
  crtEffect: number;
  pixelSort: number;
  waveDistortion: number;
  waveFrequency: number;
  lumaGlitch: number;
  noise: number;
  slitScan: number;
  fractalFeedback: number;
  feedbackRotate: number;
  lumaDisplacement: number;
  strobe: number;
}

// --- PIXEL SKULL LOGO ---
const SkullLogo = (props: React.SVGProps<SVGSVGElement>) => (
  <svg viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
    <path d="M30 20h40v30h-5v15H35V50h-5V20z" fill="currentColor"/>
    <path d="M35 65h10v15h10V65h10v20H35V65z" fill="currentColor"/>
    <rect x="38" y="32" width="8" height="8" fill="black"/>
    <rect x="54" y="32" width="8" height="8" fill="black"/>
    <rect x="47" y="46" width="6" height="4" fill="black"/>
    <rect x="20" y="20" width="4" height="4" fill="currentColor" className="animate-pulse opacity-50" />
    <rect x="76" y="76" width="4" height="4" fill="currentColor" className="animate-pulse opacity-50" />
  </svg>
);

// --- THE ENGINE ---
const useGlitch = ({
  videoRef,
  canvasRef,
  glitchParams,
  isPlaying,
}: {
  videoRef: React.RefObject<HTMLVideoElement | null>;
  canvasRef: React.RefObject<HTMLCanvasElement | null>;
  glitchParams: GlitchParams;
  isPlaying: boolean;
}): void => {
  const animationFrameId = useRef<number | null>(null);
  const feedbackCanvas = useRef<HTMLCanvasElement | null>(null);
  const time = useRef(0);

  useEffect(() => {
    const video = videoRef.current;
    const canvas = canvasRef.current;
    if (!video || !canvas) return;

    const ctx = canvas.getContext('2d', { willReadFrequently: true });
    if (!ctx) return;

    if (!feedbackCanvas.current) {
      feedbackCanvas.current = document.createElement('canvas');
    }

    const render = () => {
      if (!video || !canvas || !ctx || !isPlaying || video.videoWidth === 0) {
        if (animationFrameId.current) cancelAnimationFrame(animationFrameId.current);
        return;
      }

      time.current += glitchParams.speed / 5;
      
      if (canvas.width !== video.videoWidth || canvas.height !== video.videoHeight) {
        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;
        feedbackCanvas.current!.width = canvas.width;
        feedbackCanvas.current!.height = canvas.height;
      }

      const {
        frequency, amplitude, blockiness, rgbSplit, scanlineOpacity, 
        colorDepth, datamosh, zoom, panX, panY, echo, 
        colorInvert, hueShift, mirrorHorizontal, mirrorVertical, crtEffect,
        pixelSort, waveDistortion, waveFrequency, lumaGlitch, noise,
        slitScan, fractalFeedback, feedbackRotate, lumaDisplacement, strobe
      } = glitchParams;

      // 1. STROBE GATE
      if (strobe > 0 && Math.random() < strobe) {
        ctx.fillStyle = colorInvert ? 'black' : 'white';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        animationFrameId.current = requestAnimationFrame(render);
        return;
      }

      // 2. FEEDBACK SYSTEM
      if (fractalFeedback > 0 || echo > 0) {
        ctx.save();
        ctx.globalAlpha = Math.max(fractalFeedback, echo);
        ctx.translate(canvas.width / 2, canvas.height / 2);
        ctx.rotate(feedbackRotate * Math.PI / 180);
        ctx.scale(1.005, 1.005);
        ctx.translate(-canvas.width / 2, -canvas.height / 2);
        ctx.drawImage(feedbackCanvas.current!, 0, 0);
        ctx.restore();
      } else {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
      }

      // 3. TRANSFORM & DRAW VIDEO
      let filter = '';
      if (colorInvert) filter += 'invert(1) ';
      if (hueShift > 0) filter += `hue-rotate(${hueShift}deg) `;
      ctx.filter = filter;

      ctx.save();
      if (mirrorHorizontal > 0.5) {
        ctx.translate(canvas.width, 0);
        ctx.scale(-1, 1);
      }
      
      const sW = video.videoWidth / zoom;
      const sH = video.videoHeight / zoom;
      const sX = (video.videoWidth - sW) / 2 - panX;
      const sY = (video.videoHeight - sH) / 2 - panY;

      // SLIT SCAN
      if (slitScan > 0) {
        const rows = 24;
        const rh = canvas.height / rows;
        for (let i = 0; i < rows; i++) {
          const off = Math.sin(time.current * 0.5 + i * 0.2) * slitScan * 100;
          ctx.drawImage(video, sX, sY + i * (sH/rows), sW, sH/rows, off, i * rh, canvas.width, rh);
        }
      } else {
        ctx.drawImage(video, sX, sY, sW, sH, 0, 0, canvas.width, canvas.height);
      }
      ctx.restore();
      ctx.filter = 'none';

      // 4. DATA BENDING (PIXEL LEVEL)
      let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
      const data = imageData.data;
      const len = data.length;
      const step = Math.pow(2, 8 - colorDepth);

      for (let i = 0; i < len; i += 4) {
        const luma = (data[i] * 0.3 + data[i+1] * 0.59 + data[i+2] * 0.11);

        // LUMA DISPLACEMENT
        if (lumaDisplacement > 0) {
          const shift = Math.floor((luma / 255) * lumaDisplacement * 80) * 4;
          if (i + shift < len) {
            data[i] = data[i+shift];
            data[i+1] = data[i+shift+1];
            data[i+2] = data[i+shift+2];
          }
        }

        // NOISE & BITCRUSH
        if (noise > 0) {
          const n = (Math.random() - 0.5) * noise * 255;
          data[i] += n; data[i+1] += n; data[i+2] += n;
        }

        if (colorDepth < 8) {
          data[i] = Math.floor(data[i] / step) * step;
          data[i+1] = Math.floor(data[i+1] / step) * step;
          data[i+2] = Math.floor(data[i+2] / step) * step;
        }

        // LUMA GLITCH (CLIPPING)
        if (lumaGlitch > 0 && luma > (255 - lumaGlitch * 255)) {
          data[i] = 255; data[i+2] = 255;
        }
      }

      // PIXEL SORTING (Horizontal)
      if (pixelSort > 0) {
        for (let y = 0; y < canvas.height; y += Math.floor(1 / pixelSort + 2)) {
          if (Math.random() < pixelSort) {
            const row = y * canvas.width * 4;
            const start = Math.floor(Math.random() * (canvas.width - 50)) * 4;
            const size = 100 * 4;
            const segment = [];
            for(let x=0; x<size; x+=4) {
              const idx = row + start + x;
              segment.push({r: data[idx], g: data[idx+1], b: data[idx+2], v: data[idx]+data[idx+1]+data[idx+2]});
            }
            segment.sort((a,b) => b.v - a.v);
            for(let x=0; x<size; x+=4) {
              const idx = row + start + x;
              data[idx] = segment[x/4].r;
              data[idx+1] = segment[x/4].g;
              data[idx+2] = segment[x/4].b;
            }
          }
        }
      }

      ctx.putImageData(imageData, 0, 0);

      // SCANLINES & CRT
      if (crtEffect > 0) {
        ctx.fillStyle = `rgba(0,0,0,${crtEffect * 0.3})`;
        for(let l=0; l<canvas.height; l+=4) ctx.fillRect(0, l, canvas.width, 2);
      }

      // UPDATE FEEDBACK
      const fbCtx = feedbackCanvas.current!.getContext('2d');
      fbCtx!.drawImage(canvas, 0, 0);

      animationFrameId.current = requestAnimationFrame(render);
    };

    if (isPlaying) render();
    return () => { if (animationFrameId.current) cancelAnimationFrame(animationFrameId.current); };
  }, [videoRef, canvasRef, glitchParams, isPlaying]);
};

// --- APP COMPONENT ---
const Slider = ({ label, min, max, step, value, onChange }: any) => (
  <div className="flex flex-col mb-4 group">
    <div className="flex justify-between items-center mb-1">
      <label className="text-[10px] font-black text-gray-500 uppercase tracking-[0.2em] group-hover:text-red-600 transition-colors">{label}</label>
      <span className="text-[10px] font-black text-white tabular-nums bg-white/5 px-1 rounded">{value.toFixed(step < 1 ? 2 : 0)}</span>
    </div>
    <input type="range" min={min} max={max} step={step} value={value} onChange={onChange} className="w-full h-1 bg-gray-900 rounded-lg appearance-none cursor-pointer accent-red-600 transition-all" />
  </div>
);

const App: React.FC = () => {
  const [videoSrc, setVideoSrc] = useState<string | null>(null);
  const [isPlaying, setIsPlaying] = useState(false);
  const [isRecording, setIsRecording] = useState(false);
  const [recTime, setRecTime] = useState(0);
  
  const videoRef = useRef<HTMLVideoElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const chunks = useRef<Blob[]>([]);
  const timer = useRef<any>(null);

  const [params, setParams] = useState<GlitchParams>({
    frequency: 0.1, amplitude: 10, speed: 0.2, blockiness: 1, rgbSplit: 0,
    scanlineOpacity: 0.1, colorDepth: 8, datamosh: 0, zoom: 1, panX: 0, panY: 0,
    echo: 0.1, timeDisplacement: 0, colorInvert: false, hueShift: 0,
    mirrorHorizontal: 0, mirrorVertical: 0, crtEffect: 0.1,
    pixelSort: 0, waveDistortion: 0, waveFrequency: 0.5, lumaGlitch: 0, noise: 0.05,
    slitScan: 0, fractalFeedback: 0, feedbackRotate: 0, lumaDisplacement: 0, strobe: 0
  });

  useGlitch({ videoRef, canvasRef, glitchParams: params, isPlaying });

  useEffect(() => {
    if (isRecording) {
      setRecTime(0);
      timer.current = setInterval(() => setRecTime(t => t + 1), 1000);
    } else clearInterval(timer.current);
    return () => clearInterval(timer.current);
  }, [isRecording]);

  const toggleRecording = useCallback(() => {
    if (isRecording) {
      mediaRecorderRef.current?.stop();
    } else {
      if (!canvasRef.current) return;
      setIsRecording(true);
      chunks.current = [];
      const stream = canvasRef.current.captureStream(60);
      const recorder = new MediaRecorder(stream, { mimeType: 'video/webm' });
      mediaRecorderRef.current = recorder;
      recorder.ondataavailable = e => chunks.current.push(e.data);
      recorder.onstop = () => {
        const blob = new Blob(chunks.current, { type: 'video/webm' });
        const a = document.createElement('a'); a.href = URL.createObjectURL(blob);
        a.download = `pixel-skull-${Date.now()}.webm`; a.click();
        setIsRecording(false);
      };
      recorder.start();
    }
  }, [isRecording]);

  const fmt = (s: number) => `${Math.floor(s/60).toString().padStart(2,'0')}:${(s%60).toString().padStart(2,'0')}`;

  return (
    <div className="h-screen bg-black text-white flex flex-col font-mono overflow-hidden">
      <div className="flex-1 flex flex-col lg:flex-row overflow-hidden">
        
        {/* VIEWPORT */}
        <div className="flex-1 relative flex items-center justify-center bg-[#020202] p-8">
          {!videoSrc ? (
            <div className="text-center flex flex-col items-center gap-12">
              <SkullLogo className="w-40 h-40 text-red-600/20 animate-pulse" />
              <label className="px-16 py-6 bg-white text-black font-black hover:bg-red-600 hover:text-white transition-all cursor-pointer uppercase tracking-[0.4em] shadow-2xl active:scale-95">
                LOAD SIGNAL
                <input type="file" accept="video/*" className="hidden" onChange={e => e.target.files?.[0] && setVideoSrc(URL.createObjectURL(e.target.files[0]))} />
              </label>
            </div>
          ) : (
            <div className={`relative w-full h-full flex items-center justify-center ${isRecording ? 'border-4 border-red-600' : ''}`}>
              <canvas ref={canvasRef} className="max-w-full max-h-full object-contain shadow-2xl cursor-crosshair" onClick={() => setIsPlaying(!isPlaying)} />
              
              {isRecording && (
                <div className="absolute inset-0 p-10 flex flex-col justify-between pointer-events-none">
                  <div className="flex justify-between items-start">
                    <div className="bg-black/90 border border-red-600 px-6 py-3 flex items-center gap-4">
                      <div className="w-3 h-3 bg-red-600 rounded-full animate-ping" />
                      <span className="text-[10px] font-black italic tracking-widest text-red-600 uppercase">CAPTURE EXPO // ACTIVE</span>
                      <div className="w-px h-3 bg-white/20" />
                      <span className="text-[11px] font-black tabular-nums">{fmt(recTime)}</span>
                    </div>
                  </div>
                </div>
              )}
            </div>
          )}
        </div>

        {/* SIDEBAR */}
        <div className="w-full lg:w-[400px] bg-[#050505] border-l border-white/5 flex flex-col shadow-2xl">
          <header className="p-8 border-b border-white/5 flex items-center justify-between bg-red-600/[0.02]">
            <div className="flex items-center gap-4">
              <SkullLogo className="w-10 h-10 text-red-600" />
              <h1 className="text-[11px] font-black tracking-tight leading-none uppercase">PIXEL SKULL<br/><span className="text-red-600">BENDER</span> V5</h1>
            </div>
          </header>

          <div className="flex-1 overflow-y-auto p-8 space-y-12 custom-scrollbar">
            <section className="space-y-6">
              <h3 className="text-[8px] font-black text-gray-700 tracking-[0.5em] uppercase border-b border-white/5 pb-2">Vector Signal</h3>
              <Slider label="Clock Speed" min={0} max={1} step={0.01} value={params.speed} onChange={(e:any)=>setParams({...params, speed:+e.target.value})} />
              <Slider label="Bit Crush" min={1} max={8} step={1} value={params.colorDepth} onChange={(e:any)=>setParams({...params, colorDepth:+e.target.value})} />
              <Slider label="Strobe Gate" min={0} max={0.5} step={0.01} value={params.strobe} onChange={(e:any)=>setParams({...params, strobe:+e.target.value})} />
            </section>

            <section className="space-y-6">
              <h3 className="text-[8px] font-black text-red-900 tracking-[0.5em] uppercase border-b border-red-900/20 pb-2">Data Bending</h3>
              <Slider label="Luma Displace" min={0} max={2} step={0.01} value={params.lumaDisplacement} onChange={(e:any)=>setParams({...params, lumaDisplacement:+e.target.value})} />
              <Slider label="Slit Scan" min={0} max={1} step={0.01} value={params.slitScan} onChange={(e:any)=>setParams({...params, slitScan:+e.target.value})} />
              <Slider label="Pixel Sort" min={0} max={0.5} step={0.01} value={params.pixelSort} onChange={(e:any)=>setParams({...params, pixelSort:+e.target.value})} />
              <Slider label="Mosaic" min={1} max={50} step={1} value={params.blockiness} onChange={(e:any)=>setParams({...params, blockiness:+e.target.value})} />
            </section>

            <section className="space-y-6">
              <h3 className="text-[8px] font-black text-blue-900 tracking-[0.5em] uppercase border-b border-blue-900/20 pb-2">Feedback Loop</h3>
              <Slider label="Fractal Depth" min={0} max={0.99} step={0.01} value={params.fractalFeedback} onChange={(e:any)=>setParams({...params, fractalFeedback:+e.target.value})} />
              <Slider label="Vector Spin" min={-20} max={20} step={0.1} value={params.feedbackRotate} onChange={(e:any)=>setParams({...params, feedbackRotate:+e.target.value})} />
              <Slider label="CRT Warp" min={0} max={1} step={0.01} value={params.crtEffect} onChange={(e:any)=>setParams({...params, crtEffect:+e.target.value})} />
            </section>
          </div>

          <footer className="p-8 bg-black border-t border-white/5 space-y-4">
            <button onClick={() => {setVideoSrc(null); setIsPlaying(false);}} className="w-full py-3 text-[9px] font-black border border-white/10 hover:bg-red-900 hover:text-white transition-all uppercase tracking-[0.3em]">Purge Memory</button>
            <button onClick={toggleRecording} disabled={!videoSrc} className={`w-full py-6 text-[10px] font-black tracking-[0.5em] transition-all shadow-2xl active:scale-[0.97] disabled:opacity-5 ${isRecording ? 'bg-red-900 text-white animate-pulse' : 'bg-red-600 hover:bg-red-500 text-white'}`}>
              {isRecording ? 'HALT TRANSMISSION' : 'INITIALIZE CAPTURE'}
            </button>
          </footer>
        </div>
      </div>
      <video ref={videoRef} src={videoSrc || ''} loop muted crossOrigin="anonymous" className="hidden" onPlay={()=>setIsPlaying(true)} onPause={()=>setIsPlaying(false)} />
    </div>
  );
};

const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(<App />);