package interceptor

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/mattn/anko/env"
	"github.com/mattn/anko/vm"
)

type Ankointerceptor struct {
	importMap  map[string]interface{}
	libMap     map[string]interface{}
	libhabdles []uintptr
	ankoEnv    *env.Env
}

func NewAnkointerceptor(ankoEnv *env.Env) *Ankointerceptor {

	a := &Ankointerceptor{
		importMap:  make(map[string]interface{}),
		libMap:     make(map[string]interface{}),
		libhabdles: make([]uintptr, 0),
		ankoEnv:    ankoEnv,
	}
	a.ankoEnv.Define("println", fmt.Println)
	a.ankoEnv.Define("loadLibrary", func(libPath string, libFuncMap map[string]funcType) interface{} {
		return a.loadLibrary(libPath, libFuncMap)
	})
	a.importMap["fs"] = &FileModule{}
	a.importMap["net"] = &NetModule{}
	a.importMap["process"] = &ProcessModule{}
	a.importMap["shell"] = &ShellModule{}
	return a
}

func (a *Ankointerceptor) Exec(script string) (interface{}, error) {
	e := a.ankoEnv.Copy()
	e.Define("Require", a.genRequireMethod(script))
	e.Define("__filename", script)
	e.Define("__dirname", filepath.Dir(script))
	scriptbytes, frr := os.ReadFile(script)
	if frr != nil {
		return nil, frr
	}
	scriptcode := string(scriptbytes)
	result, err := vm.Execute(e, nil, scriptcode)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	return result, nil
}

func (a *Ankointerceptor) genRequireMethod(basePath string) interface{} {
	return func(s string) interface{} {
		if r, ok := a.importMap[s]; ok {
			return r
		}
		if !filepath.IsAbs(s) {
			s = filepath.Join(filepath.Dir(basePath), s)
		}
		if _, ok := a.importMap[s]; ok {
			return a.importMap[s]
		}
		result, err := a.Exec(s)
		if err != nil {
			panic(err)
		}
		a.importMap[s] = result
		return result
	}
}
