import React, { useEffect, useRef, useState } from 'react';
import type * as Monaco from 'monaco-editor';
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';

const configureMonacoWorkers = () => {
  // @ts-ignore
  self.MonacoEnvironment = {
    getWorker(_: string, label: string) {
      if (label === 'typescript' || label === 'javascript') {
        return new tsWorker();
      }
      if (label === 'json') {
        return new jsonWorker();
      }
      return new editorWorker();
    }
  };
};

interface TaskCodeEditorProps {
  source: string;
  className?: string;
  onCodeChange: (value: string) => void;
  schema?: any;
}

const configureTypeScript = async (monacoInstance: typeof Monaco) => {
  // 1. Configure TypeScript compiler options
  monacoInstance.languages.typescript.typescriptDefaults.setCompilerOptions({
    target: monacoInstance.languages.typescript.ScriptTarget.ESNext,
    moduleResolution: monacoInstance.languages.typescript.ModuleResolutionKind.NodeJs,
    module: monacoInstance.languages.typescript.ModuleKind.ESNext,
    allowNonTsExtensions: true,
    allowJs: true,
    strict: false,
    noImplicitAny: false,
    jsx: monacoInstance.languages.typescript.JsxEmit.React,
    esModuleInterop: true
  });

  // 2. Load and add type definitions
  let moduleDefinitions: string;
  
  try {
    const response = await fetch('/index.d.ts');
    moduleDefinitions = await response.text();

    // Register the module
    monacoInstance.languages.typescript.typescriptDefaults.addExtraLib(
      moduleDefinitions,
      'file:///node_modules/l33t-lib/index.d.ts'
    );
    
  } catch (error) {
    console.error('Failed to load type definitions:', error);
    alert('Failed to load type definitions: '+ error)
  }

 
};

const TaskCodeEditor: React.FC<TaskCodeEditorProps> = ({
  source,
  className,
  onCodeChange,
  schema
}) => {
  const editorRef = useRef<Monaco.editor.IStandaloneCodeEditor | null>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const disposablesRef = useRef<Monaco.IDisposable[]>([]);
  const [monacoInstance, setMonacoInstance] = useState<typeof Monaco | null>(null);

  useEffect(() => {
    if (typeof window === 'undefined') return;
    
    let mounted = true;
    const loadMonaco = async () => {
      configureMonacoWorkers();
      try {
        const monaco = await import('monaco-editor');
        if (mounted) {
          setMonacoInstance(monaco);
        }
      } catch (error) {
        console.error('Failed to load Monaco Editor:', error);
      }
    };

    loadMonaco();
    return () => { mounted = false; };
  }, []);

  useEffect(() => {
    if (!containerRef.current || !monacoInstance) return;

    const initializeEditor = async () => {
      if (!containerRef.current) return;
      // Configure TypeScript
      await configureTypeScript(monacoInstance);

      // Create the model for user script
      const scriptUri = monacoInstance.Uri.parse('file:///src/script.ts');
      let model = monacoInstance.editor.getModel(scriptUri);
      
      if (!model) {
        model = monacoInstance.editor.createModel(
          source, 
          'typescript',
          scriptUri
        );
      } else {
        model.setValue(source);
      }

      // Create editor
      if (!containerRef.current) return;
      editorRef.current = monacoInstance.editor.create(containerRef.current, {
        model: model,
        language: 'typescript',
        theme: 'vs-dark',
        automaticLayout: true,
        minimap: { enabled: false },
        scrollBeyondLastLine: false,
        fontSize: 14,
        lineNumbers: 'on',
        folding: true,
        glyphMargin: true,
        lineDecorationsWidth: 0,
        lineNumbersMinChars: 3,
      });

      // Handle changes
      const changeDisposable = editorRef.current.onDidChangeModelContent(() => {
        if (editorRef.current) {
          onCodeChange(editorRef.current.getValue());
        }
      });
      disposablesRef.current.push(changeDisposable);
    };

    initializeEditor();

    return () => {
      disposablesRef.current.forEach(d => d.dispose());
      if (editorRef.current) {
        editorRef.current.dispose();
      }
    };
  }, [monacoInstance, source]);

  if (!monacoInstance) {
    return (
      <div className={`flex items-center justify-center h-full w-full min-h-[400px] ${className || ''}`}>
        Loading editor...
      </div>
    );
  }

  return (
    <div 
      ref={containerRef} 
      className={`h-full w-full min-h-[400px] ${className || ''}`}
    />
  );
};

export default TaskCodeEditor;