// Copyright 2021 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package opa

import (
	"context"
)

// ErrEngineNotFound is returned by LookupEngine if no wasm engine was
// registered by that name.
var ErrEngineNotFound error = &errEngineNotFound{}

type errEngineNotFound struct{}

func (*errEngineNotFound) Error() string { return "engine not found" }
func (*errEngineNotFound) Lines() []string {
	return []string{
		`WebAssembly runtime not supported in this build.`,
		`----------------------------------------------------------------------------------`,
		`Please download an OPA binary with Wasm enabled from`,
		`https://www.openpolicyagent.org/docs/latest/#running-opa`,
		`or build it yourself (with Wasm enabled).`,
		`----------------------------------------------------------------------------------`,
	}
}

// Engine repesents a factory for instances of EvalEngine implementations
type Engine interface {
	New() EvalEngine
}

// EvalEngine is the interface implemented by an engine used to eval a policy
type EvalEngine interface {
	Init() (EvalEngine, error)
	Entrypoints(context.Context) (map[string]int32, error)
	WithPolicyBytes([]byte) EvalEngine
	WithDataJSON(interface{}) EvalEngine
	Eval(context.Context, EvalOpts) (*Result, error)
	SetData(context.Context, interface{}) error
	SetDataPath(context.Context, []string, interface{}) error
	RemoveDataPath(context.Context, []string) error
	Close()
}

var engines = map[string]Engine{}

// RegisterEngine registers an evaluation engine by its target name.
// Note that the "rego" target is always available.
func RegisterEngine(name string, e Engine) {
	if engines[name] != nil {
		panic("duplicate engine registration")
	}
	engines[name] = e
}

// LookupEngine allows retrieving an engine registered by name
func LookupEngine(name string) (Engine, error) {
	e, ok := engines[name]
	if !ok {
		return nil, ErrEngineNotFound
	}
	return e, nil
}
