import React, { useState, useRef, useEffect } from 'react';
import kaboom from "kaboom";
import { Upload, Play, Image as ImageIcon, Copy, Grid, Film, RefreshCw, Scissors } from 'lucide-react';

const STATES = {
  IDLE: 'idle',
  LOADING_VIDEO: 'loading_video',
  VIDEO_READY: 'video_ready',
  EXTRACTING: 'extracting_frames',
  FRAMES_READY: 'frames_ready',
  GENERATING: 'generating_sheet',
  SHEET_READY: 'sheet_ready',
};

const App = () => {
  const [appState, setAppState] = useState(STATES.IDLE);
  const [videoSrc, setVideoSrc] = useState(null);
  const [videoMeta, setVideoMeta] = useState({ duration: 0, width: 0, height: 0 });
  const [thumbnail, setThumbnail] = useState(null);
  const [extractedFrames, setExtractedFrames] = useState([]);
  const [spriteSheetUrl, setSpriteSheetUrl] = useState(null);
  const [sheetMeta, setSheetMeta] = useState({ w: 0, h: 0, cols: 0, rows: 0, frameW: 0, frameH: 0 });
  
  const [config, setConfig] = useState({
    frameCount: 16,
    trimStart: 0,
    trimEnd: 100,
    scale: 1,
  });

  const hiddenVideoRef = useRef(null);
  const kaboomContainerRef = useRef(null);
  const kInstance = useRef(null);

  // 1. INPUT HANDLER
  const handleFileUpload = (e) => {
    const file = e.target.files?.[0];
    if (!file) return;
    setAppState(STATES.LOADING_VIDEO);
    const url = URL.createObjectURL(file);
    setVideoSrc(url);
    setExtractedFrames([]);
    setSpriteSheetUrl(null);
  };

  const onVideoLoaded = (e) => {
    const vid = e.target;
    setVideoMeta({ duration: vid.duration, width: vid.videoWidth, height: vid.videoHeight });
    
    // Thumbnail Capture
    vid.currentTime = 0.5;
    const captureThumb = () => {
        const cvs = document.createElement('canvas');
        cvs.width = vid.videoWidth / 4; cvs.height = vid.videoHeight / 4;
        cvs.getContext('2d').drawImage(vid, 0, 0, cvs.width, cvs.height);
        setThumbnail(cvs.toDataURL());
        setAppState(STATES.VIDEO_READY);
        vid.removeEventListener('seeked', captureThumb);
    };
    vid.addEventListener('seeked', captureThumb);
  };

  // 2. PIPELINE: EXTRACT
  const startExtraction = async () => {
    if (!hiddenVideoRef.current) return;
    setAppState(STATES.EXTRACTING);
    setExtractedFrames([]);

    const vid = hiddenVideoRef.current;
    const { frameCount, trimStart, trimEnd, scale } = config;
    const startTime = (trimStart / 100) * vid.duration;
    const playDuration = ((trimEnd / 100) * vid.duration) - startTime;
    const timeStep = playDuration / frameCount;

    const cvs = document.createElement('canvas');
    cvs.width = vid.videoWidth * scale;
    cvs.height = vid.videoHeight * scale;
    const ctx = cvs.getContext('2d');
    const newFrames = [];

    for (let i = 0; i < frameCount; i++) {
        vid.currentTime = startTime + (i * timeStep);
        await new Promise(resolve => {
            const onSeek = () => {
                vid.removeEventListener('seeked', onSeek);
                ctx.clearRect(0,0,cvs.width,cvs.height);
                ctx.drawImage(vid,0,0,cvs.width,cvs.height);
                cvs.toBlob(blob => {
                    newFrames.push(URL.createObjectURL(blob));
                    setExtractedFrames([...newFrames]);
                    resolve();
                }, 'image/png');
            };
            vid.addEventListener('seeked', onSeek);
        });
    }
    setAppState(STATES.FRAMES_READY);
    generateSpriteSheet(newFrames);
  };

  // 3. PIPELINE: PACK
  const generateSpriteSheet = (frames) => {
    setAppState(STATES.GENERATING);
    const count = frames.length;
    const cols = Math.ceil(Math.sqrt(count));
    const rows = Math.ceil(count / cols);
    const fW = videoMeta.width * config.scale;
    const fH = videoMeta.height * config.scale;
    
    const cvs = document.createElement('canvas');
    cvs.width = cols * fW; cvs.height = rows * fH;
    const ctx = cvs.getContext('2d');

    Promise.all(frames.map((src, i) => new Promise(resolve => {
        const img = new Image();
        img.onload = () => {
            ctx.drawImage(img, (i % cols)*fW, Math.floor(i/cols)*fH, fW, fH);
            resolve();
        };
        img.src = src;
    }))).then(() => {
        setSpriteSheetUrl(cvs.toDataURL('image/png'));
        setSheetMeta({ w: cvs.width, h: cvs.height, cols, rows, frameW: fW, frameH: fH });
        setAppState(STATES.SHEET_READY);
    });
  };

  // 4. KABOOM PREVIEW
  useEffect(() => {
    if (appState === STATES.SHEET_READY && spriteSheetUrl && kaboomContainerRef.current) {
        kaboomContainerRef.current.innerHTML = ''; // Force clear
        try {
            const k = kaboom({
                root: kaboomContainerRef.current,
                width: 300, height: 300,
                background: [0,0,0,0], global: false
            });
            k.loadSprite("anim", spriteSheetUrl, {
                sliceX: sheetMeta.cols, sliceY: sheetMeta.rows,
                anims: { idle: { from: 0, to: config.frameCount - 1, loop: true, speed: 10 } }
            });
            k.scene("main", () => {
                k.add([
                    k.sprite("anim"), k.pos(k.center()), k.anchor("center"),
                    k.scale(Math.min(250/sheetMeta.frameW, 250/sheetMeta.frameH))
                ]).play("idle");
            });
            k.go("main");
            kInstance.current = k;
        } catch(e) { console.error(e); }
    }
  }, [spriteSheetUrl, sheetMeta]);

  // UI HELPERS
  const StepTitle = ({num, text}) => (
    <h2 className="text-[10px] font-bold text-gray-500 uppercase tracking-widest mb-3 flex items-center gap-2">
      <span className="bg-obsidian-border text-gray-300 w-4 h-4 rounded-full flex items-center justify-center">{num}</span> {text}
    </h2>
  );

  return (
    <div className="min-h-screen p-4 lg:p-8 font-sans">
      <video ref={hiddenVideoRef} src={videoSrc} className="hidden" muted playsInline onLoadedData={onVideoLoaded} />

      {/* Header */}
      <header className="mb-8 flex items-center gap-3 border-b border-white/5 pb-6">
        <div className="p-2 bg-obsidian-accent/10 rounded-lg">
            <Film className="text-obsidian-accent w-6 h-6" />
        </div>
        <div>
            <h1 className="text-xl font-bold text-white tracking-tight">Kaboom Pipeline</h1>
            <p className="text-gray-500 text-xs">Docker Edition • Video to Sprite Sheet</p>
        </div>
      </header>

      <div className="grid grid-cols-1 lg:grid-cols-12 gap-6">
        
        {/* === LEFT COLUMN === */}
        <div className="lg:col-span-5 space-y-6">
            
            {/* Upload Card */}
            <div className="glass-panel rounded-2xl p-5 relative overflow-hidden group">
                <StepTitle num="1" text="Source Media" />
                {!videoSrc ? (
                    <label className="border border-dashed border-white/10 rounded-xl h-40 flex flex-col items-center justify-center cursor-pointer hover:bg-white/5 transition-all">
                        <Upload className="w-6 h-6 text-gray-400 mb-2" />
                        <span className="text-sm text-gray-400">Drop Video or GIF</span>
                        <input type="file" onChange={handleFileUpload} className="hidden" accept="video/*,image/gif" />
                    </label>
                ) : (
                    <div className="relative rounded-xl overflow-hidden bg-black/50 aspect-video ring-1 ring-white/10">
                        {thumbnail && <img src={thumbnail} className="w-full h-full object-contain opacity-70" />}
                        <button onClick={() => setVideoSrc(null)} className="absolute top-2 right-2 p-2 bg-black/50 hover:bg-red-500/20 hover:text-red-400 rounded-full text-white/50 backdrop-blur transition-all">
                            <RefreshCw size={14} />
                        </button>
                    </div>
                )}
            </div>

            {/* Controls */}
            <div className={`glass-panel rounded-2xl p-5 transition-opacity ${!videoSrc ? 'opacity-40 pointer-events-none' : 'opacity-100'}`}>
                <StepTitle num="2" text="Extraction Config" />
                <div className="space-y-6">
                    <div className="space-y-4">
                        <div>
                            <div className="flex justify-between text-xs mb-2 text-gray-400">
                                <span>Frame Count</span> <span className="text-obsidian-accent font-mono">{config.frameCount}</span>
                            </div>
                            <input type="range" min="4" max="64" value={config.frameCount} onChange={(e) => setConfig({...config, frameCount: +e.target.value})} className="w-full h-1.5 bg-white/10 rounded-lg appearance-none cursor-pointer accent-obsidian-accent" />
                        </div>
                        <div>
                             <div className="flex justify-between text-xs mb-2 text-gray-400">
                                <span className="flex items-center gap-1"><Scissors size={12}/> Trim</span> <span className="font-mono">{config.trimStart}% - {config.trimEnd}%</span>
                            </div>
                            <div className="flex gap-2">
                                <input type="range" value={config.trimStart} onChange={(e)=>setConfig({...config, trimStart: +e.target.value})} className="w-full h-1 bg-white/10 rounded accent-gray-500"/>
                                <input type="range" value={config.trimEnd} onChange={(e)=>setConfig({...config, trimEnd: +e.target.value})} className="w-full h-1 bg-white/10 rounded accent-gray-500"/>
                            </div>
                        </div>
                    </div>

                    <button onClick={startExtraction} disabled={appState === STATES.EXTRACTING} 
                        className="w-full bg-obsidian-accent hover:bg-obsidian-accent/90 text-white text-sm font-semibold py-3 rounded-xl flex items-center justify-center gap-2 transition-all shadow-lg shadow-obsidian-accent/20 disabled:opacity-50 disabled:cursor-not-allowed">
                        {appState === STATES.EXTRACTING ? "Processing..." : <>Start Extraction <Play size={14} fill="currentColor" /></>}
                    </button>
                </div>
            </div>

            {/* Grid Preview */}
            <div className="glass-panel rounded-2xl p-5 h-64 overflow-y-auto">
                 <StepTitle num="3" text="Frame Buffer" />
                 <div className="grid grid-cols-5 gap-2">
                    {extractedFrames.map((src,i) => (
                        <div key={i} className="aspect-square bg-black/40 rounded border border-white/5 relative overflow-hidden">
                            <img src={src} className="w-full h-full object-contain pixelated" />
                        </div>
                    ))}
                    {appState === STATES.EXTRACTING && [...Array(config.frameCount - extractedFrames.length)].map((_,i) => 
                        <div key={`sk-${i}`} className="aspect-square bg-white/5 rounded animate-pulse" />
                    )}
                 </div>
            </div>
        </div>

        {/* === RIGHT COLUMN === */}
        <div className="lg:col-span-7 space-y-6">
            
            {/* Atlas Viewer */}
            <div className="glass-panel rounded-2xl p-6 min-h-[350px] flex flex-col relative">
                <div className="flex justify-between items-start mb-4">
                    <StepTitle num="4" text="Generated Atlas" />
                    {sheetMeta.w > 0 && <span className="text-[10px] bg-white/5 border border-white/10 px-2 py-1 rounded text-gray-400 font-mono">{sheetMeta.w}x{sheetMeta.h}px</span>}
                </div>
                
                <div className="flex-1 rounded-xl border border-white/10 bg-[#1a1a1a] relative overflow-hidden flex items-center justify-center p-8 bg-[url('https://kaboomjs.com/site/img/checker.png')] bg-repeat">
                    <div className="absolute inset-0 bg-black/20 pointer-events-none" /> 
                    {spriteSheetUrl ? (
                        <div className="relative z-10 shadow-2xl shadow-black">
                            <img src={spriteSheetUrl} className="max-w-full max-h-[300px] object-contain pixelated" />
                            <div className="absolute inset-0 border border-red-500/20 pointer-events-none" style={{
                                backgroundImage: `linear-gradient(to right, rgba(255,50,50,0.2) 1px, transparent 1px), linear-gradient(to bottom, rgba(255,50,50,0.2) 1px, transparent 1px)`,
                                backgroundSize: `${100/sheetMeta.cols}% ${100/sheetMeta.rows}%`
                            }} />
                        </div>
                    ) : (
                        <div className="text-white/10 flex flex-col items-center gap-2 z-10">
                            <Grid size={40} />
                            <span className="text-xs font-mono">Waiting for input...</span>
                        </div>
                    )}
                </div>
            </div>

            <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
                {/* Kaboom */}
                <div className="glass-panel rounded-2xl p-5 flex flex-col">
                    <StepTitle num="5" text="Kaboom Preview" />
                    <div className="bg-black/80 rounded-xl border border-white/10 aspect-square flex items-center justify-center relative overflow-hidden">
                        <div ref={kaboomContainerRef} className="w-full h-full" />
                        {!spriteSheetUrl && <p className="absolute text-white/20 text-xs">No Data</p>}
                    </div>
                </div>

                {/* Export */}
                <div className="glass-panel rounded-2xl p-5 flex flex-col">
                    <StepTitle num="6" text="Export Assets" />
                    <div className="flex-1 flex flex-col gap-3">
                        <a href={spriteSheetUrl} download="sprite.png" className={`flex items-center justify-center gap-2 bg-white/5 hover:bg-white/10 border border-white/10 text-gray-300 text-xs py-3 rounded-lg transition-all ${!spriteSheetUrl && 'opacity-50 pointer-events-none'}`}>
                            <ImageIcon size={14} /> Download PNG
                        </a>
                        
                        <div className="relative bg-black/40 rounded-lg border border-white/5 p-3 flex-1 overflow-hidden group">
                            <pre className="text-[10px] text-green-400/90 font-mono h-full overflow-auto scrollbar-thin">
{spriteSheetUrl ? `loadSpriteAtlas("player", "sprite.png", {
  "idle": {
    x: 0, y: 0,
    width: ${sheetMeta.w}, height: ${sheetMeta.h},
    sliceX: ${sheetMeta.cols}, sliceY: ${sheetMeta.rows},
    anims: {
      run: { from: 0, to: ${config.frameCount-1}, speed: 10, loop: true }
    }
  }
});` : '// Code will appear here'}
                            </pre>
                            <button onClick={() => navigator.clipboard.writeText('...')} className="absolute top-2 right-2 p-1.5 bg-white/10 hover:bg-white/20 rounded text-white opacity-0 group-hover:opacity-100 transition-opacity">
                                <Copy size={12} />
                            </button>
                        </div>
                    </div>
                </div>
            </div>

        </div>
      </div>
    </div>
  );
};

export default App;
