package inspect

import (
	"context"
	"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/engine"
	"github.com/tidbcloud/infra-provider/infra-inspector/pkg/inspect/lister"

	"github.com/go-logr/logr"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/kubernetes"
)

// GenericInspector inspects resources in a kubernetes cluster.
type GenericInspector struct {
	Target string
	Lister lister.ResourceLister
	Engine engine.Engine
}

func NewGenericInspector(target string, ecfg config.EngineConfig, cli kubernetes.Interface, dcli dynamic.Interface) (*GenericInspector, error) {
	lister, err := lister.NewResourceLister(cli, dcli)
	if err != nil {
		return nil, err
	}

	engine, err := engine.NewEngine(ecfg)
	if err != nil {
		return nil, err
	}

	return &GenericInspector{
		Target: target,
		Lister: lister,
		Engine: engine,
	}, nil
}

func (i *GenericInspector) Inspect(ctx context.Context, listOpt config.ListConfig) ([]*api.Result, error) {
	logger := logr.FromContextOrDiscard(ctx).WithValues("target", i.Target)

	result := &api.Result{
		Target:     i.Target,
		Violations: []api.Violation{},
	}

	for _, match := range listOpt.Resources {
		logger := logger.WithValues("gvk", fmt.Sprintf("%s/%s", match.APIVersion, match.Kind))
		ctx := logr.NewContext(ctx, logger)

		rlist, err := i.Lister.ListResources(ctx, match.APIVersion, match.Kind, match.ResourceMatchOption)
		if err != nil {
			logger.Error(err, "failed to list resources")
			continue
		}

		for _, resources := range rlist {
			for _, resource := range resources.Resources {
				violation, err := i.Engine.Validate(ctx, i.Lister, resource)
				if err != nil {
					logger.Error(err, "failed to validate resource",
						"resource_name", resource.GetName(), "resource_namespace", resource.GetNamespace())
					continue
				}

				result.Violations = append(result.Violations, *violation)
			}
		}
	}

	return []*api.Result{result}, nil
}
