//go:build js && wasm

package main

import (
	"context"
	"errors"
	"github.com/alecthomas/participle/v2"
	"strings"
	"syscall/js"
	"ucl.lmika.dev/repl"
	"ucl.lmika.dev/ucl"
	"ucl.lmika.dev/ucl/builtins"
)

func invokeUCLCallback(name string, args ...any) {
	if onLine := js.Global().Get("ucl").Get(name); !onLine.IsNull() {
		onLine.Invoke(args...)
	}
}

func initJS(ctx context.Context) {
	uclObj := make(map[string]any)

	replInst := repl.New(
		ucl.WithModule(builtins.Log(nil)),
		ucl.WithModule(builtins.Strs()),
		ucl.WithModule(builtins.Time()),
		ucl.WithOut(ucl.LineHandler(func(line string) {
			invokeUCLCallback("onOutLine", line)
		})),
	)

	uclObj["eval"] = js.FuncOf(func(this js.Value, args []js.Value) any {
		if len(args) != 2 {
			return nil
		}

		cmdLine := args[0].String()
		if strings.TrimSpace(cmdLine) == "" {
			invokeUCLCallback("onNewCommand")
			return nil
		}

		wantContinue := args[1].Bool()
		if err := replInst.EvalAndDisplay(ctx, cmdLine); err != nil {
			var p participle.Error
			if errors.As(err, &p) && wantContinue {
				invokeUCLCallback("onContinue")
				return nil
			}

			invokeUCLCallback("onError", err.Error())
		}
		invokeUCLCallback("onNewCommand")
		return nil
	})
	js.Global().Set("ucl", uclObj)
}