package engine

import (
	"context"
	"errors"
	"fmt"

	"github.com/tidbcloud/infra-provider/infra-inspector/api"
	"github.com/tidbcloud/infra-provider/infra-inspector/pkg/config"
	"github.com/tidbcloud/infra-provider/infra-inspector/pkg/inspect/lister"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

type Engine interface {
	Validate(context.Context, lister.ResourceLister, *unstructured.Unstructured) (*api.Violation, error)
}

type engine struct {
	engines []Engine
}

func NewEngine(ecfg config.EngineConfig) (Engine, error) {
	e := &engine{}

	if ecfg.Rego != nil {
		rego, err := NewRegoEngine(*ecfg.Rego)
		if err != nil {
			return nil, fmt.Errorf("create rego engine failed: %v", err)
		}

		e.engines = append(e.engines, rego)
	}
	if ecfg.AlwaysDeny {
		e.engines = append(e.engines, NewAlwaysDenyEngine())
	}

	if len(e.engines) == 0 {
		return nil, fmt.Errorf("no engine configured")
	}

	return e, nil
}

func (e *engine) Validate(ctx context.Context, lister lister.ResourceLister, resource *unstructured.Unstructured) (*api.Violation, error) {
	errs := []error{}

	result := &api.Violation{
		Resource: GetResourceFromUnstructured(resource),
	}

	for _, engine := range e.engines {
		violation, err := engine.Validate(ctx, lister, resource)
		if err != nil {
			errs = append(errs, err)
		}

		if len(violation.ViolatedRules) != 0 {
			result.ViolatedRules = append(result.ViolatedRules, violation.ViolatedRules...)
		}
	}

	if len(errs) == len(e.engines) {
		return nil, errors.Join(errs...)
	}

	if len(errs) != 0 {
		return result, errors.Join(errs...)
	}

	return result, nil
}
