/**
 * @fileoverview React component for CodeEditor.jsx
 * 
 * @module components.game.editors.CodeEditor
 */


import React, { useState, useEffect, useMemo } from "react";
import PropTypes from "prop-types";
import CodeMirror from "@uiw/react-codemirror";
import { javascript } from "@codemirror/lang-javascript";
import { autocompletion } from "@codemirror/autocomplete";
import { indentWithTab, insertTab } from "@codemirror/commands";
import { keymap } from "@codemirror/view";
import { indentOnInput, indentUnit } from "@codemirror/language";
import { useGameState } from "../../../contexts/GameStateContext";
import { useEditor } from "../../../contexts/EditorContext";
import {
  loadCode,
  createDebouncedCodeSave,
} from "../../../services/codestorage";

const createGameCompletion = (gameConfig) => {
  return autocompletion({
    override: [
      (context) => {
        const word = context.matchBefore(/\w*/);
        if (!word || (word.from === word.to && !context.explicit)) return null;

        const allowedFunctions = gameConfig?.allowedFunctions || [];
        const functionDocs = gameConfig?.functionDocumentation || {};
        const allowedStructures = gameConfig?.allowedControlStructures || [];

        const functionOptions = allowedFunctions.map((funcName) => {
          const doc = functionDocs[funcName] || {};
          return {
            label: funcName,
            type: "function",
            info: doc.description || `Função ${funcName}`,
            detail: doc.syntax || `${funcName}()`,
            apply: doc.example || `${funcName}()`,
          };
        });

        const structureOptions = allowedStructures.map((structure) => {
          const templates = {
            if: "if (${condition}) {\n  ${code}\n}",
            else: "else {\n  ${code}\n}",
            while: "while (${condition}) {\n  ${code}\n}",
            for: "for (${init}; ${condition}; ${update}) {\n  ${code}\n}",
            var: "var ${name} = ${value};",
            function: "function ${name}() {\n  ${code}\n}",
          };

          return {
            label: structure,
            type: "keyword",
            info: `Estrutura de controle ${structure}`,
            detail: templates[structure] || structure,
            apply: templates[structure] || structure,
          };
        });

        return {
          from: word.from,
          options: [...functionOptions, ...structureOptions],
        };
      },
    ],
  });
};

export default function CodeEditor() {
  const {
    registerCodeEditorFunction,
    onCodeEditorChange,
    gameConfig,
    currentPhase,
  } = useGameState();
  const { gameNameKey } = useEditor();

  const phases = gameConfig?.fases ?? gameConfig?.phases; // support English alias
  const phaseConfig = phases?.find((phase) => phase.id === currentPhase);
  const initialCode = phaseConfig?.initialCode || "// Digite seu código aqui";

  const [code, setCode] = useState(initialCode);
  const [isLoading, setIsLoading] = useState(true);

  const debouncedCodeSave = useMemo(() => createDebouncedCodeSave(1000), []);
  const codeStorageKey = `${gameNameKey}-code`;

  useEffect(() => {
    setIsLoading(true);

    const savedCode = loadCode(codeStorageKey);
    if (savedCode !== null) {
      setCode(savedCode);
    } else {
      setCode(initialCode);
    }

    setIsLoading(false);
  }, [codeStorageKey, initialCode]);

  useEffect(() => {
    const getCodeFromEditor = () => {
      return code;
    };

    registerCodeEditorFunction(getCodeFromEditor);



    return () => {
      registerCodeEditorFunction(null);
    };
  }, [code, registerCodeEditorFunction]);

  useEffect(() => {
    if (!isLoading) {
      onCodeEditorChange(code);
    }
  }, [code, onCodeEditorChange, isLoading]);

  const handleChange = (value) => {
    setCode(value);

    if (!isLoading) {
      debouncedCodeSave(codeStorageKey, value);
    }
  };

  useEffect(() => {
    return () => {
      debouncedCodeSave.cancel();
    };
  }, [debouncedCodeSave]);

  return (
    <div className="w-full h-full">
      <CodeMirror
        value={code}
        height="100%"
        extensions={[
          javascript(),
          createGameCompletion(gameConfig),
          indentOnInput(),
          indentUnit.of("  "), // 2 espaços para indentação
          keymap.of([
            indentWithTab,
            {
              key: "Enter",
              run: ({ state, dispatch }) => {
                const { from } = state.selection.main;
                const line = state.doc.lineAt(from);
                const lineText = line.text;
                const indent = lineText.match(/^\s*/)[0];

                let newIndent = indent;
                if (lineText.trim().endsWith("{")) {
                  newIndent += "  ";
                }

                dispatch(
                  state.update({
                    changes: {
                      from,
                      insert: "\n" + newIndent,
                    },
                    selection: { anchor: from + newIndent.length + 1 },
                  }),
                );

                return true;
              },
            },
          ]),
        ]}
        onChange={handleChange}
        basicSetup={{
          lineNumbers: true,
          highlightActiveLineGutter: true,
          highlightSpecialChars: true,
          history: true,
          foldGutter: true,
          drawSelection: true,
          dropCursor: true,
          allowMultipleSelections: true,
          indentOnInput: true,
          bracketMatching: true,
          closeBrackets: true,
          autocompletion: true,
          highlightSelectionMatches: false,
        }}
        className="h-full"
      />
    </div>
  );
}

CodeEditor.propTypes = {};
