package git

import (
	"fmt"
	"path/filepath"
	"time"

	"github.com/ProtonMail/go-crypto/openpgp"
	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing/object"
)

type CommitOption func(*Commit)

func WithAuthor(name, email string) CommitOption {
	return func(c *Commit) {
		c.Author = &object.Signature{
			Name:  name,
			Email: email,
			When:  time.Now(),
		}
	}
}

func WithCommitter(name, email string) CommitOption {
	return func(c *Commit) {
		c.Committer = &object.Signature{
			Name:  name,
			Email: email,
			When:  time.Now(),
		}
	}
}

func WithFileContent(content []byte, filename, folder string) CommitOption {
	return func(c *Commit) {
		c.Content = content
		c.Filename = filepath.Join(folder, fmt.Sprintf("%s.json", filename))
	}
}

func WithSigner(signKey SignKey) CommitOption {
	return func(c *Commit) {
		c.signKey = signKey.entity
	}
}

type Commit struct {
	Author    *object.Signature
	Committer *object.Signature
	Content   []byte
	Filename  string
	KeyFile   string

	project *Project
	signKey *openpgp.Entity
}

func (p *Project) NewCommit(options ...CommitOption) *Commit {
	commit := &Commit{project: p}

	for _, option := range options {
		option(commit)
	}

	return commit
}

func (c *Commit) Create(msg string) error {
	if err := c.addContent(); err != nil {
		return err
	}

	if _, err := c.project.worktree.Add(c.Filename); err != nil {
		return err
	}

	commitOpts := git.CommitOptions{Author: c.Author}

	if c.Committer != nil {
		commitOpts.Committer = c.Committer
	}

	if c.signKey != nil {
		commitOpts.SignKey = c.signKey
	}

	_, err := c.project.worktree.Commit(msg, &commitOpts)
	if err != nil {
		return err
	}

	return nil
}

func (c *Commit) addContent() error {
	file, err := c.project.worktree.Filesystem.Create(c.Filename)
	if err != nil {
		return err
	}
	defer file.Close()

	_, err = file.Write(c.Content)
	return err
}