//go:generate ${GOBIN}/mockgen -destination repo_mock.go -package=ops_execution_window ${GO_MODULE}/pkg/service/clustermaintenance/repo/ops_execution_window Repo
package ops_execution_window

import (
	"context"
	"fmt"

	maintent "github.com/tidbcloud/devops/entity/maintenance"

	"github.com/tidbcloud/devops/entity/validation"
	"github.com/tidbcloud/devops/pkg/infra/utils/repoopt"
	"github.com/tidbcloud/devops/pkg/service/clustermaintenance/repo/cvt"

	"github.com/tidbcloud/pkgv2/db"
)

type Repo interface {
	List(ctx context.Context, opts ...repoopt.Option) ([]*maintent.OpsExecutionWindow, error)
	Get(ctx context.Context, id uint64) (*maintent.OpsExecutionWindow, error)
	Create(ctx context.Context, spec *maintent.OpsExecutionWindow) (*maintent.OpsExecutionWindow, error)
	Update(ctx context.Context, spec *maintent.OpsExecutionWindow) (*maintent.OpsExecutionWindow, error)
	Delete(ctx context.Context, id uint64) error
	Count(ctx context.Context, opts ...repoopt.Option) (int64, error)
	Options() opts
}

func NewRepo(dbp db.Provider) Repo {
	return &repo{
		driver: &driver{
			cvter:      cvt.NewConverter(),
			dbProvider: dbp,
		},
	}
}

type repo struct {
	driver Driver
}

func (r *repo) List(
	ctx context.Context,
	opts ...repoopt.Option,
) ([]*maintent.OpsExecutionWindow, error) {
	return r.driver.Query(ctx, opts...)
}

func (r *repo) Get(
	ctx context.Context,
	id uint64,
) (*maintent.OpsExecutionWindow, error) {
	if id == 0 {
		return nil, fmt.Errorf("id must not be 0")
	}

	return r.driver.Load(ctx, id)
}

func (r *repo) Create(
	ctx context.Context,
	spec *maintent.OpsExecutionWindow,
) (*maintent.OpsExecutionWindow, error) {
	if spec.ID != 0 {
		return nil, fmt.Errorf("id must be 0")
	}
	if err := validation.ClusterMaintenance.OpsExecutionWindow(spec); err != nil {
		return nil, err
	}

	return r.driver.Save(ctx, spec)
}

func (r *repo) Update(
	ctx context.Context,
	spec *maintent.OpsExecutionWindow,
) (*maintent.OpsExecutionWindow, error) {
	if spec.ID == 0 {
		return nil, fmt.Errorf("id must not be 0")
	}
	if err := validation.ClusterMaintenance.OpsExecutionWindow(spec); err != nil {
		return nil, err
	}

	return r.driver.Save(ctx, spec)
}

func (r *repo) Delete(ctx context.Context, id uint64) error {
	if id == 0 {
		return fmt.Errorf("id must not be 0")
	}

	return r.driver.Delete(ctx, id)
}

func (r *repo) Count(ctx context.Context, opts ...repoopt.Option) (int64, error) {
	return r.driver.Count(ctx, opts...)
}

func (r *repo) Options() opts {
	return opts{}
}
