package repo

import (
	"context"

	"github.com/tidbcloud/devops/entity"
	"github.com/tidbcloud/devops/pkg/infra/utils/repoopt"
	"github.com/tidbcloud/devops/pkg/service/configcenter/repo/cvt"
	"github.com/tidbcloud/pkgv2/db"
)

type Patch func(current *entity.ConfigAttributes) error

func WithParamName(param string) repoopt.Option {
	return &repoopt.Filter[string]{
		Column: "param_name",
		Value:  &param,
	}
}

func WithVersion(version int64) repoopt.Option {
	return &repoopt.Filter[int64]{
		Column: "version",
		Value:  &version,
	}
}

func WithComponent(component string) repoopt.Option {
	like := component + `%`
	return &repoopt.Filter[string]{
		Column: "param_name",
		Like:   &like,
	}
}

type ConfigCenterRepo interface {
	GetConfigWithNameNVersion(ctx context.Context, name string, version int64) (*entity.ConfigAttributes, error)
	ListAttributes(ctx context.Context, opts ...repoopt.Option) ([]*entity.ConfigAttributes, error)
	AddParam(ctx context.Context, paramInfo *entity.ConfigAttributes) error
	CreateAttributes(ctx context.Context, attributes []*entity.ConfigAttributes) error
	PatchAttribute(ctx context.Context, paramName string, version int64, patch Patch) error
}

type configCenterRepo struct {
	driver Driver
}

func NewConfigCenterReop(dbp db.Provider) ConfigCenterRepo {
	driver := &configCenterRepoDriver{
		cvter:      cvt.NewConverter(),
		dbProvider: dbp,
	}
	return &configCenterRepo{
		driver: driver,
	}
}

func (c *configCenterRepo) GetConfigWithNameNVersion(ctx context.Context, name string, version int64) (*entity.ConfigAttributes, error) {
	return c.driver.Load(ctx, name, version)
}

func (c *configCenterRepo) ListAttributes(ctx context.Context, opts ...repoopt.Option) ([]*entity.ConfigAttributes, error) {
	return c.driver.Query(ctx, opts...)
}

func (s *configCenterRepo) AddParam(ctx context.Context, paramInfo *entity.ConfigAttributes) error {
	_, err := s.driver.Save(ctx, paramInfo)
	return err
}

func (s *configCenterRepo) CreateAttributes(ctx context.Context, attributes []*entity.ConfigAttributes) error {
	err := s.driver.Create(ctx, attributes)
	return err
}

func (s *configCenterRepo) PatchAttribute(ctx context.Context, paramName string, version int64, patch Patch) error {
	current, err := s.driver.Load(ctx, paramName, version)
	if err != nil {
		return err
	}

	err = patch(current)
	if err != nil {
		return err
	}

	_, err = s.driver.Save(ctx, current)
	return err
}
