import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

public final class RunJS {
    private RunJS() {
    }

    @SuppressWarnings({"MethodMayBeStatic", "unused"})
    public static class IO {
        private final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));

        private final ScriptEngine engine;
        public IO(final ScriptEngine engine) {
            this.engine = engine;
        }

        public void print(final String message) {
            System.out.print(message);
        }

        public void println(final String message) {
            System.out.println(message);
        }

        public void include(final String file) throws IOException, ScriptException {
            engine.getContext().setAttribute(ScriptEngine.FILENAME, file, ScriptContext.ENGINE_SCOPE);
            engine.eval(new FileReader(file, StandardCharsets.UTF_8));
        }
        
        public String readLine(final String prompt) throws IOException {
            if (prompt != null) {
                System.out.print(prompt);
            }
            return reader.readLine();
        }
    }

    public static void main(final String[] args) throws ScriptException {
        final String script = args.length == 0 ? "examples.js" : args[0];

        System.setProperty("polyglot.engine.WarnInterpreterOnly", "false");
        System.setProperty("polyglot.js.strict", "true");

        final ScriptEngine engine = new ScriptEngineManager().getEngineByName("Graal.js");
        if (engine == null) {
            System.err.println("Graal.js not found");
            System.err.println("Use the following command line to run RunJS:");
            System.err.println("java --module-path=graal -cp . RunJS");
            return;
        }

        engine.put("polyglot.js.allowIO", true);
        engine.put("polyglot.js.allowHostAccess", true);
        engine.put("polyglot.js.ecmascript-version", "2022");
        engine.put("io", new IO(engine));

        engine.eval("var global = this;");
        engine.eval("var println = function() { io.println(Array.prototype.map.call(arguments, String).join(' ')); };");
        engine.eval("var print   = function() { io.print  (Array.prototype.map.call(arguments, String).join(' ')); };");
        engine.eval("var include = function(file) { io.include(file); }");
        engine.eval("var readLine = function(prompt) { return io.readLine(prompt); }");
        engine.eval("io.include('" + script + "')");
    }
}
