"use client";

import React, { useState, useEffect, useMemo, useRef } from 'react';
import { DEFAULT_SCRIPT, parseScript, Statement } from '@/lib/vn-parser';
import { VNOutline } from '@/components/VNOutline';
import { VNEditor } from '@/components/VNEditor';
import { VNPreview } from '@/components/VNPreview';
import { INITIAL_SPRITE_BANK, Sprite } from '@/lib/sprite-bank';

const STORAGE_KEY_SCRIPT = 'vn_editor_script';
const STORAGE_KEY_FILENAME = 'vn_editor_filename';

export default function VisualNovelEditorPage() {
  const [scriptText, setScriptText] = useState(DEFAULT_SCRIPT);
  const [fileName, setFileName] = useState("scene_01.vns");
  const [statements, setStatements] = useState<Statement[]>([]);
  const [spriteBank, setSpriteBank] = useState<Record<string, Sprite[]>>(INITIAL_SPRITE_BANK);
  const [currentSayIndex, setCurrentSayIndex] = useState(0);
  const [isParsing, setIsParsing] = useState(false);
  const editorRef = useRef<HTMLTextAreaElement>(null);

  // Load from LocalStorage
  useEffect(() => {
    const savedScript = localStorage.getItem(STORAGE_KEY_SCRIPT);
    const savedFileName = localStorage.getItem(STORAGE_KEY_FILENAME);
    if (savedScript) setScriptText(savedScript);
    if (savedFileName) setFileName(savedFileName);
  }, []);

  // Save to LocalStorage
  useEffect(() => {
    localStorage.setItem(STORAGE_KEY_SCRIPT, scriptText);
    localStorage.setItem(STORAGE_KEY_FILENAME, fileName);
  }, [scriptText, fileName]);

  const updateSpriteBank = (newBank: Record<string, Sprite[]>) => {
    setSpriteBank(newBank);
  };

  const addSpriteToScript = (char: string, id: string, url: string) => {
    // Add to the top of the script or after existing defines
    setScriptText(prev => `define_sprite ${char} ${id} "${url}"\n${prev}`);
  };

  // Parse Debounce
  useEffect(() => {
    const timer = setTimeout(() => {
      setIsParsing(true);
      const parsed = parseScript(scriptText);
      setStatements(parsed);

      // Sync Sprite Bank from define_sprite commands in script
      const newScriptBank: Record<string, Sprite[]> = {};
      parsed.forEach(s => {
        if (s.type === 'comment' && s.text?.startsWith('DEF_SPRITE')) {
          const parts = s.text.split(' ');
          const char = parts[1];
          const id = parts[2];
          const url = parts[3]?.replace(/^"(.*)"$/, '$1'); 
          if (char && id && url) {
            if (!newScriptBank[char]) newScriptBank[char] = [];
            if (!newScriptBank[char].some(sp => sp.id === id)) {
              newScriptBank[char].push({ id, name: id, url });
            }
          }
        }
      });

      if (Object.keys(newScriptBank).length > 0) {
        setSpriteBank(prev => {
          const merged = { ...prev };
          Object.entries(newScriptBank).forEach(([char, sprites]) => {
            if (!merged[char]) {
              merged[char] = sprites;
            } else {
              const existingIds = new Set(sprites.map(s => s.id));
              merged[char] = [
                ...merged[char].filter(s => !existingIds.has(s.id)),
                ...sprites
              ];
            }
          });
          return merged;
        });
      }

      setIsParsing(false);
    }, 300);
    return () => clearTimeout(timer);
  }, [scriptText]);

  const previewStatements = useMemo(() => 
    statements.filter(s => s.type === 'say' || s.type === 'choice'), 
    [statements]
  );

  const currentStatement = previewStatements[currentSayIndex] || null;

  const handleChoiceSelect = (jumpLabel: string) => {
    const labelIdx = statements.findIndex(s => s.type === 'label' && s.label === jumpLabel);
    if (labelIdx !== -1) {
      // Find the first 'previewable' statement at or after the label
      const nextPreviewIdx = previewStatements.findIndex(s => s.lineNumber >= statements[labelIdx].lineNumber);
      if (nextPreviewIdx !== -1) {
        setCurrentSayIndex(nextPreviewIdx);
      }
    }
  };

  const handleSave = () => {
    const blob = new Blob([scriptText], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = fileName;
    link.click();
    URL.revokeObjectURL(url);
  };

  const handleLoad = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = (e) => {
      if (typeof e.target?.result === 'string') {
        setScriptText(e.target.result);
        setFileName(file.name);
      }
    };
    reader.readAsText(file);
  };

  const scrollToLine = (line: number) => {
    if (!editorRef.current) return;
    const lines = scriptText.split('\n');
    let pos = 0;
    for (let i = 0; i < line - 1; i++) {
      pos += lines[i].length + 1;
    }
    editorRef.current.focus();
    editorRef.current.setSelectionRange(pos, pos + (lines[line-1]?.length || 0));
    
    const lineHeight = 24;
    editorRef.current.scrollTop = (line - 5) * lineHeight;

    const previewIdx = previewStatements.findIndex(s => s.lineNumber === line);
    if (previewIdx !== -1) {
      setCurrentSayIndex(previewIdx);
    }
  };

  return (
    <div className="flex h-screen w-full bg-[#0d1117] text-gray-300 font-sans overflow-hidden">
      <VNOutline 
        statements={statements}
        currentSay={currentStatement}
        onSelectLine={scrollToLine}
        isParsing={isParsing}
        spriteBank={spriteBank}
        onUpdateSpriteBank={updateSpriteBank}
        onAddSpriteToScript={addSpriteToScript}
      />

      <div className="flex-1 flex flex-col">
        {/* Header */}
        <div className="h-14 border-b border-gray-800 flex items-center px-6 justify-between bg-[#0d1117]">
          <div className="flex items-center gap-4">
            <input 
              value={fileName}
              onChange={e => setFileName(e.target.value)}
              className="bg-transparent border-b border-gray-700 focus:border-cyan-400 outline-none px-2 py-1 text-sm font-mono text-cyan-400"
            />
          </div>
          <div className="flex items-center gap-3">
            <label className="cursor-pointer bg-gray-800 hover:bg-gray-700 px-4 py-1.5 rounded text-xs font-bold transition-all border border-gray-700">
              LOAD
              <input type="file" className="hidden" onChange={handleLoad} accept=".vns,.txt" />
            </label>
            <button 
              onClick={handleSave}
              className="bg-cyan-500 hover:bg-cyan-400 text-black px-4 py-1.5 rounded text-xs font-bold transition-all shadow-[0_0_15px_rgba(0,229,255,0.3)]"
            >
              SAVE SCRIPT
            </button>
          </div>
        </div>

        <div className="flex-1 flex overflow-hidden">
          <VNEditor 
            ref={editorRef}
            scriptText={scriptText}
            onScriptChange={setScriptText}
          />

          <VNPreview 
            currentStatement={currentStatement}
            currentSayIndex={currentSayIndex}
            totalPreviewSteps={previewStatements.length}
            onPrev={() => setCurrentSayIndex(prev => Math.max(0, prev - 1))}
            onNext={() => setCurrentSayIndex(prev => Math.min(previewStatements.length - 1, prev + 1))}
            statements={statements}
            spriteBank={spriteBank}
            onChoiceSelect={handleChoiceSelect}
          />
        </div>
      </div>

      <style jsx global>{`
        @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap');
        
        .custom-scrollbar::-webkit-scrollbar {
          width: 8px;
          height: 8px;
        }
        .custom-scrollbar::-webkit-scrollbar-track {
          background: #0d1117;
        }
        .custom-scrollbar::-webkit-scrollbar-thumb {
          background: #21262d;
          border-radius: 4px;
        }
        .custom-scrollbar::-webkit-scrollbar-thumb:hover {
          background: #30363d;
        }
      `}</style>
    </div>
  );
}
