package packp

import (
	"errors"

	"github.com/go-git/go-git/v6/plumbing"
	"github.com/go-git/go-git/v6/plumbing/protocol/packp/capability"
)

// Errors returned by the updreq package.
var (
	ErrEmptyCommands    = errors.New("commands cannot be empty")
	ErrMalformedCommand = errors.New("malformed command")
)

// UpdateRequests values represent reference upload requests.
// Values from this type are not zero-value safe, use the New function instead.
type UpdateRequests struct {
	Capabilities *capability.List
	Commands     []*Command
	Shallow      *plumbing.Hash
	// TODO: Support push-cert
}

// NewUpdateRequests returns a new UpdateRequests.
func NewUpdateRequests() *UpdateRequests {
	// TODO: Add support for push-cert
	return &UpdateRequests{
		Capabilities: capability.NewList(),
	}
}

func (req *UpdateRequests) validate() error {
	if len(req.Commands) == 0 {
		return ErrEmptyCommands
	}

	for _, c := range req.Commands {
		if err := c.validate(); err != nil {
			return err
		}
	}

	return nil
}

// Action represents the action type of a command.
type Action string

// Action types.
const (
	Create  Action = "create"
	Update  Action = "update"
	Delete  Action = "delete"
	Invalid Action = "invalid"
)

// Command represents a command to be executed on a reference.
type Command struct {
	Name plumbing.ReferenceName
	Old  plumbing.Hash
	New  plumbing.Hash
}

// Action returns the action type of the command.
func (c *Command) Action() Action {
	if c.Old == plumbing.ZeroHash && c.New == plumbing.ZeroHash {
		return Invalid
	}

	if c.Old == plumbing.ZeroHash {
		return Create
	}

	if c.New == plumbing.ZeroHash {
		return Delete
	}

	return Update
}

func (c *Command) validate() error {
	if c.Action() == Invalid {
		return ErrMalformedCommand
	}

	return nil
}
