//go:generate ${GOBIN}/mockgen -destination github_client_mock.go -package=githubcli ${GO_MODULE}/pkg/infra/clients/githubcli PullRequestsService,ReleaseService,RepositoryService
package githubcli

import (
	context "context"
	"fmt"
	"os"

	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing"
	"github.com/go-git/go-git/v5/plumbing/transport/http"
	"github.com/google/go-github/v54/github"
	"github.com/shurcooL/githubv4"
	"go.uber.org/mock/gomock"
	"golang.org/x/oauth2"

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

type Pager struct {
	PerPage int
	Cursor  string
}

type PagerResult struct {
	EndCursor   string
	HasNextPage bool
}

// GithubClient wraps `github.Client` to be able to mock it.
type GithubClient struct {
	cliv3 *github.Client
	cliv4 *githubv4.Client
	token string

	PullRequest PullRequestsService
	Release     ReleaseService
	Repository  RepositoryService
}

func NewGithubClient(conf *config.RootConfig) (*GithubClient, error) {
	token := conf.Clients.Github.Token

	src := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: token},
	)
	httpClient := oauth2.NewClient(context.Background(), src)
	cliv3 := github.NewClient(httpClient)
	cliv4 := githubv4.NewClient(httpClient)

	c := &GithubClient{
		cliv3: cliv3,
		cliv4: cliv4,
		token: token,
	}

	c.PullRequest = (*pullRequestsServiceImpl)(c)
	c.Release = (*releaseServiceImpl)(c)
	c.Repository = (*repositoryServiceImpl)(c)

	return c, nil
}

func NewMockGithubClient(ctrl *gomock.Controller) *GithubClient {
	return &GithubClient{
		PullRequest: NewMockPullRequestsService(ctrl),
		Release:     NewMockReleaseService(ctrl),
		Repository:  NewMockRepositoryService(ctrl),
	}
}

func (c *GithubClient) Clone(ctx context.Context, org, name, branch string) (*git.Repository, error) {
	path := fmt.Sprintf("/tmp/github/%s/%s", org, name)
	err := os.RemoveAll(path)
	if err != nil {
		return nil, err
	}
	return git.PlainCloneContext(ctx, path, false, &git.CloneOptions{
		URL: fmt.Sprintf("https://github.com/%s/%s", org, name),
		Auth: &http.BasicAuth{
			Username: "tidbcloud-bot",
			Password: c.token,
		},
		ReferenceName: plumbing.NewBranchReferenceName(branch),
		SingleBranch:  true,
	})
}
