package coverage

import (
	"context"
	"errors"
	"fmt"
	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing/filemode"
	"github.com/go-git/go-git/v5/plumbing/object"
	"github.com/go-git/go-git/v5/storage/memory"
	"os"
	"regexp"
	"strings"
)

var (
	fileNil = errors.New("file pointer is nil")
)

func GetTreeFromGit(ctx context.Context, url string) (*Tree, error) {
	cloneOpts := &git.CloneOptions{
		URL:      url,
		Progress: os.Stdout,
	}

	repo, err := git.CloneContext(ctx, memory.NewStorage(), nil, cloneOpts)
	if err != nil {
		return nil, err
	}

	ref, err := repo.Head()
	if err != nil {
		return nil, fmt.Errorf("failed to get head: %v", err)
	}

	commit, err := repo.CommitObject(ref.Hash())
	if err != nil {
		return nil, fmt.Errorf("failed to get commit: %v", err)
	}

	tree, err := commit.Tree()

	return &Tree{tree}, err
}

type Tree struct {
	*object.Tree
}

func (t Tree) GoFileList(pattern string) ([]string, error) {
	matcher, err := regexp.Compile(pattern)
	if err != nil {
		return nil, err
	}

	var list []string
	err = t.Files().ForEach(func(file *object.File) error {
		if file == nil {
			return fileNil
		}
		if file.Mode == filemode.Regular && strings.HasSuffix(file.Name, ".go") && !strings.HasSuffix(file.Name, "_test.go") && matcher.MatchString(file.Name) {
			list = append(list, file.Name)
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return list, err
}