package dehub

import (
	"dehub.dev/src/dehub.git/yamlutil"
	"encoding/base64"
	"fmt"
	"strings"

	"gopkg.in/src-d/go-git.v4/plumbing/object"
)

// CommitCredential describes the structure of a credential commit message.
type CommitCredential struct {
	CredentialedHash yamlutil.Blob `yaml:"credentialed_hash"`

	// CommitHashes represents the commits which this credential is accrediting.
	// It is only present for informational purposes, as commits don't not have
	// any bearing on the CredentialedHash itself.
	CommitHashes []string `yaml:"commits,omitempty"`
}

var _ CommitInterface = CommitCredential{}

// NewCommitCredential constructs and returns a Commit populated with a
// CommitCredential encompassing the given hash. The Credentials of the returned
// Commit will _not_ be filled in.
func (r *Repo) NewCommitCredential(hash []byte) (Commit, error) {
	return Commit{
		Credential: &CommitCredential{
			CredentialedHash: hash,
		},
	}, nil
}

// NewCommitCredentialFromChanges constructs and returns a Comit populated with
// a CommitCredential for all changes in the given range of GitCommits. The
// message of the last change commit in the range is used when generating the
// hash.
func (r *Repo) NewCommitCredentialFromChanges(commits []GitCommit) (Commit, error) {
	info, err := r.changeRangeInfo(commits)
	if err != nil {
		return Commit{}, err
	}

	commitCred, err := r.NewCommitCredential(info.changeHash)
	if err != nil {
		return Commit{}, err
	}

	for _, commit := range info.changeCommits {
		commitCred.Credential.CommitHashes = append(
			commitCred.Credential.CommitHashes,
			commit.GitCommit.Hash.String(),
		)
	}
	return commitCred, nil
}

// MessageHead implements the method for the CommitInterface interface.
func (cc CommitCredential) MessageHead(common CommitCommon) (string, error) {
	hash64 := base64.StdEncoding.EncodeToString(cc.CredentialedHash)
	if len(hash64) > 6 {
		hash64 = hash64[:6] + "..."
	}

	credAccounts := strings.Join(common.credAccountIDs(), ", ")
	return fmt.Sprintf("Credential of hash %s by %s", hash64, credAccounts), nil
}

// Hash implements the method for the CommitInterface.
func (cc CommitCredential) Hash(_, _ *object.Tree) ([]byte, error) {
	return cc.CredentialedHash, nil
}

// GetHash implements the method for the CommitInterface.
func (cc CommitCredential) GetHash() []byte {
	return cc.CredentialedHash
}