// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package gitrepo provides operations on git repos.
package gitrepo

import (
	"context"
	"fmt"
	"io"
	"strings"
	"time"

	"github.com/go-git/go-billy/v5/memfs"
	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing"
	"github.com/go-git/go-git/v5/plumbing/object"
	"github.com/go-git/go-git/v5/storage/memory"
	"golang.org/x/tools/txtar"
	"golang.org/x/vulndb/internal/derrors"
	"golang.org/x/vulndb/internal/observe"
	"golang.org/x/vulndb/internal/worker/log"
)

// Clone returns a bare repo by cloning the repo at repoURL.
func Clone(ctx context.Context, repoURL string) (repo *git.Repository, err error) {
	defer derrors.Wrap(&err, "gitrepo.Clone(%q)", repoURL)
	ctx, span := observe.Start(ctx, "gitrepo.Clone")
	defer span.End()

	return CloneAt(ctx, repoURL, plumbing.HEAD)
}

// Clone returns a bare repo by cloning the repo at repoURL at the given ref.
func CloneAt(ctx context.Context, repoURL string, ref plumbing.ReferenceName) (repo *git.Repository, err error) {
	log.Infof(ctx, "Cloning repo %q at %s", repoURL, ref)
	return git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
		URL:           repoURL,
		ReferenceName: ref,
		SingleBranch:  true,
		Depth:         1,
		Tags:          git.NoTags,
	})
}

// PlainClone returns a (non-bare) repo with its history by cloning the repo at repoURL.
func PlainClone(ctx context.Context, dir, repoURL string) (repo *git.Repository, err error) {
	defer derrors.Wrap(&err, "gitrepo.PlainClone(%q)", repoURL)
	ctx, span := observe.Start(ctx, "gitrepo.PlainClone")
	defer span.End()

	log.Infof(ctx, "Plain cloning repo %q at HEAD", repoURL)
	return git.PlainCloneContext(ctx, dir, false, &git.CloneOptions{
		URL:           repoURL,
		ReferenceName: plumbing.HEAD,
		SingleBranch:  true, // allow branches other than master
		Depth:         0,    // pull in history
		Tags:          git.NoTags,
	})
}

// Open returns a repo by opening the repo at the local path dirpath.
func Open(ctx context.Context, dirpath string) (repo *git.Repository, err error) {
	defer derrors.Wrap(&err, "gitrepo.Open(%q)", dirpath)
	ctx, span := observe.Start(ctx, "gitrepo.Open")
	defer span.End()

	log.Infof(ctx, "Opening repo at %q", dirpath)
	repo, err = git.PlainOpen(dirpath)
	if err != nil {
		return nil, err
	}
	return repo, nil
}

// CloneOrOpen clones repoPath if it is an HTTP(S) URL, or opens it from the
// local disk otherwise.
func CloneOrOpen(ctx context.Context, repoPath string) (*git.Repository, error) {
	if strings.HasPrefix(repoPath, "http://") || strings.HasPrefix(repoPath, "https://") {
		return Clone(ctx, repoPath)
	}
	return Open(ctx, repoPath)
}

// Root returns the root tree of the repo at HEAD.
func Root(repo *git.Repository) (root *object.Tree, err error) {
	refName := plumbing.HEAD
	ref, err := repo.Reference(refName, true)
	if err != nil {
		return nil, err
	}
	commit, err := repo.CommitObject(ref.Hash())
	if err != nil {
		return nil, err
	}
	return repo.TreeObject(commit.TreeHash)
}

// TxtarRepoAndHead reads a txtar repo into a single-commit repository,
// and returns the repo and its head commit.
// Intended for testing.
func TxtarRepoAndHead(file string) (*git.Repository, *object.Commit, error) {
	repo, err := ReadTxtarRepo(file, time.Now())
	if err != nil {
		return nil, nil, err
	}
	commit, err := HeadCommit(repo)
	if err != nil {
		return nil, nil, err
	}
	return repo, commit, nil
}

// HeadCommit returns the commit at the repo HEAD.
func HeadCommit(repo *git.Repository) (*object.Commit, error) {
	h, err := HeadHash(repo)
	if err != nil {
		return nil, err
	}
	commit, err := repo.CommitObject(h)
	if err != nil {
		return nil, err
	}
	return commit, nil
}

// ReadTxtarRepo converts a txtar file to a single-commit
// repo. It is intended for testing.
func ReadTxtarRepo(filename string, now time.Time) (_ *git.Repository, err error) {
	defer derrors.Wrap(&err, "readTxtarRepo(%q)", filename)

	mfs := memfs.New()
	ar, err := txtar.ParseFile(filename)
	if err != nil {
		return nil, err
	}
	for _, f := range ar.Files {
		file, err := mfs.Create(f.Name)
		if err != nil {
			return nil, err
		}
		if _, err := file.Write(f.Data); err != nil {
			return nil, err
		}
		if err := file.Close(); err != nil {
			return nil, err
		}
	}

	repo, err := git.Init(memory.NewStorage(), mfs)
	if err != nil {
		return nil, err
	}
	wt, err := repo.Worktree()
	if err != nil {
		return nil, err
	}
	for _, f := range ar.Files {
		if _, err := wt.Add(f.Name); err != nil {
			return nil, err
		}
	}
	_, err = wt.Commit("", &git.CommitOptions{All: true, Author: &object.Signature{
		Name:  "Joe Random",
		Email: "joe@example.com",
		When:  now,
	}})
	if err != nil {
		return nil, err
	}
	return repo, nil
}

// HeadHash returns the hash of the repo's HEAD.
func HeadHash(repo *git.Repository) (plumbing.Hash, error) {
	ref, err := repo.Reference(plumbing.HEAD, true)
	if err != nil {
		return plumbing.ZeroHash, err
	}
	return ref.Hash(), nil
}

// ParseGitHubRepo parses a string of the form owner/repo or
// github.com/owner/repo.
func ParseGitHubRepo(s string) (owner, repoName string, err error) {
	parts := strings.Split(s, "/")
	switch len(parts) {
	case 2:
		return parts[0], parts[1], nil
	case 3:
		if parts[0] != "github.com" {
			return "", "", fmt.Errorf("%q is not in the form {github.com/}owner/repo", s)
		}
		return parts[1], parts[2], nil
	default:
		return "", "", fmt.Errorf("%q is not in the form {github.com/}owner/repo", s)
	}
}

// ReferenceName is a git reference.
type ReferenceName struct{ plumbing.ReferenceName }

var (
	HeadReference = ReferenceName{plumbing.HEAD}                                       // HEAD
	MainReference = ReferenceName{plumbing.NewRemoteReferenceName("origin", "master")} // origin/master
)

// Dates is the oldest and newest commit timestamps for a file.
type Dates struct {
	Oldest, Newest time.Time
}

// AllCommitDates returns the oldest and newest commit timestamps for every
// file in the repo at the given reference, where the filename begins with
// prefix. The supplied prefix should include the trailing /.
func AllCommitDates(repo *git.Repository, refName ReferenceName, prefix string) (dates map[string]Dates, err error) {
	defer derrors.Wrap(&err, "AllCommitDates(%q)", prefix)

	ref, err := repo.Reference(refName.ReferenceName, true)
	if err != nil {
		return nil, err
	}
	commit, err := repo.CommitObject(ref.Hash())
	if err != nil {
		return nil, err
	}
	dates = make(map[string]Dates)
	iter := object.NewCommitPreorderIter(commit, nil, nil)
	commit, err = iter.Next()
	if err != nil {
		return nil, err
	}
	for commit != nil {
		parentCommit, err := iter.Next()
		if err != nil {
			if err != io.EOF {
				return nil, err
			}
			parentCommit = nil
		}

		currentTree, err := commit.Tree()
		if err != nil {
			return nil, err
		}

		var parentTree *object.Tree
		if parentCommit != nil {
			parentTree, err = parentCommit.Tree()
			if err != nil {
				return nil, err
			}
		}

		changes, err := object.DiffTree(currentTree, parentTree)
		if err != nil {
			return nil, err
		}

		for _, change := range changes {
			name := change.To.Name
			if change.From.Name != "" {
				name = change.From.Name
			}
			when := commit.Committer.When.UTC()
			if !strings.HasPrefix(name, prefix) {
				continue
			}
			d := dates[name]
			if d.Oldest.IsZero() || when.Before(d.Oldest) {
				if d.Oldest.After(d.Newest) {
					d.Newest = d.Oldest
				}
				d.Oldest = when
			}
			if when.After(d.Newest) {
				d.Newest = when
			}
			dates[name] = d
		}

		commit = parentCommit
	}
	return dates, nil
}
