package loader

import (
	"context"
	"fmt"

	"github.com/go-playground/validator/v10"
	"github.com/imdario/mergo"

	"github.com/tidbcloud/devops/pkg/infra/config"
)

var validate = validator.New()

type ConfigurationSource interface {
	Load(ctx context.Context, pre *config.RootConfig) (*config.RootConfig, error)
}

type ConfigurationLoader struct {
	sources      []ConfigurationSource
	skipValidate bool
}

func NewConfigurationLoader(filepath string, skipValidate bool) *ConfigurationLoader {
	loader := &ConfigurationLoader{
		sources: []ConfigurationSource{
			NewConfigurationSourceDefault(),
			NewConfigurationSourceFile(filepath),
			NewConfigurationSourceSecret(),
		},
		skipValidate: skipValidate,
	}
	return loader
}

func (l *ConfigurationLoader) Load(ctx context.Context) (*config.RootConfig, error) {
	finalConf := &config.RootConfig{}

	// merge config from different sources
	for _, source := range l.sources {
		curConf, err := source.Load(ctx, finalConf)
		if err != nil {
			return nil, err
		}

		if curConf == nil {
			continue
		}

		err = mergo.MergeWithOverwrite(finalConf, curConf)
		if err != nil {
			return nil, fmt.Errorf("failed to merge secrets: %w", err)
		}
	}

	// validate final config
	if !l.skipValidate {
		err := validate.Struct(finalConf)
		if err != nil {
			return nil, fmt.Errorf("failed to validate config: %w", err)
		}
	}

	return finalConf, nil
}
