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

import (
	"context"

	jiraent "github.com/tidbcloud/devops/entity/jira"
	"github.com/tidbcloud/devops/pkg/infra/asset"
	"github.com/tidbcloud/devops/pkg/infra/utils/repoopt"
	"github.com/tidbcloud/devops/pkg/service/jira/repo/cvt"

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

type Repo interface {
	ListIssues(ctx context.Context, opts ...repoopt.Option) ([]*jiraent.IssueInRepo, error)
	GetIssue(ctx context.Context, key string) (*jiraent.IssueInRepo, error)
	CreateIssue(ctx context.Context, issue *jiraent.IssueInRepo) (*jiraent.IssueInRepo, error)
	CountIssues(ctx context.Context, opts ...repoopt.Option) (int64, error)
	UpdateIssue(ctx context.Context, issue *jiraent.IssueInRepo) (*jiraent.IssueInRepo, error)

	ListIssueTriages(ctx context.Context, opts ...repoopt.Option) ([]*jiraent.IssueTriage, error)
	GetIssueTriage(ctx context.Context, key string) (*jiraent.IssueTriage, error)
	CreateIssueTriage(ctx context.Context, issue *jiraent.IssueTriage) (*jiraent.IssueTriage, error)
	CountIssueTriages(ctx context.Context, opts ...repoopt.Option) (int64, error)
	UpsertIssueTriage(ctx context.Context, issue *jiraent.IssueTriage) (*jiraent.IssueTriage, error)

	GetIssueTimelineSummary(ctx context.Context, key string) (*jiraent.IssueTimelineSummary, error)
	SetIssueTimelineSummary(ctx context.Context, key string, summary *jiraent.IssueTimelineSummary) error
	DeleteIssueTimelineSummary(ctx context.Context, key string) error

	ListIssueTriageTags(ctx context.Context, opts ...repoopt.Option) ([]*jiraent.IssueTriageTagDefinition, error)
	CreateIssueTriageTag(ctx context.Context, tag *jiraent.IssueTriageTagDefinition) (*jiraent.IssueTriageTagDefinition, error)
	DeleteIssueTriageTag(ctx context.Context, name string, typ jiraent.IssueTriageTagType) (*jiraent.IssueTriageTagDefinition, error)
}

func NewRepo(dbp db.Provider, asset asset.Asset) Repo {
	driver := &driver{
		cvter:      cvt.NewConverter(),
		dbProvider: dbp,
		asset:      asset,
	}

	return &repo{
		issue:     (*imD)(driver),
		triage:    (*itD)(driver),
		triageTag: (*ittD)(driver),
		summary:   (*itsD)(driver),
	}
}

type driver struct {
	cvter      *cvt.Converter
	dbProvider db.Provider
	asset      asset.Asset
}

type repo struct {
	issue     IssueDriver
	triage    IssueTriageDriver
	triageTag IssueTriageTagDefinitionDriver
	summary   IssueTimelineSummaryDriver
}

func (r *repo) ListIssues(ctx context.Context, opts ...repoopt.Option) ([]*jiraent.IssueInRepo, error) {
	return r.issue.Query(ctx, opts...)
}

func (r *repo) GetIssue(ctx context.Context, key string) (*jiraent.IssueInRepo, error) {
	return r.issue.Load(ctx, key)
}

func (r *repo) CreateIssue(ctx context.Context, issue *jiraent.IssueInRepo) (*jiraent.IssueInRepo, error) {
	return r.issue.Save(ctx, issue)
}

func (r *repo) UpdateIssue(ctx context.Context, issue *jiraent.IssueInRepo) (*jiraent.IssueInRepo, error) {
	return r.issue.Save(ctx, issue)
}

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

func (r *repo) ListIssueTriages(ctx context.Context, opts ...repoopt.Option) ([]*jiraent.IssueTriage, error) {
	return r.triage.Query(ctx, opts...)
}

func (r *repo) GetIssueTriage(ctx context.Context, key string) (*jiraent.IssueTriage, error) {
	return r.triage.Load(ctx, key)
}

func (r *repo) CreateIssueTriage(ctx context.Context, issue *jiraent.IssueTriage) (*jiraent.IssueTriage, error) {
	return r.triage.Save(ctx, issue)
}

func (r *repo) UpsertIssueTriage(ctx context.Context, issue *jiraent.IssueTriage) (*jiraent.IssueTriage, error) {
	return r.triage.Save(ctx, issue)
}

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

func (r *repo) GetIssueTimelineSummary(ctx context.Context, key string) (*jiraent.IssueTimelineSummary, error) {
	return r.summary.Load(ctx, key)
}

func (r *repo) SetIssueTimelineSummary(ctx context.Context, key string, summary *jiraent.IssueTimelineSummary) error {
	return r.summary.Save(ctx, key, summary)
}

func (r *repo) DeleteIssueTimelineSummary(ctx context.Context, key string) error {
	return r.summary.Delete(ctx, key)
}

func (r *repo) ListIssueTriageTags(ctx context.Context, opts ...repoopt.Option) ([]*jiraent.IssueTriageTagDefinition, error) {
	return r.triageTag.Query(ctx, opts...)
}

func (r *repo) CreateIssueTriageTag(ctx context.Context, tag *jiraent.IssueTriageTagDefinition) (*jiraent.IssueTriageTagDefinition, error) {
	return r.triageTag.Save(ctx, tag)
}

func (r *repo) DeleteIssueTriageTag(ctx context.Context, name string, typ jiraent.IssueTriageTagType) (*jiraent.IssueTriageTagDefinition, error) {
	return r.triageTag.Delete(ctx, name, typ)
}
