package value_objects

import (
	"errors"
	"fmt"
)

var (
	ErrInvalidThreshold   = errors.New("invalid threshold")
	ErrThresholdTooLarge  = errors.New("threshold t cannot exceed n")
	ErrThresholdTooSmall  = errors.New("threshold t must be at least 1")
	ErrNTooSmall          = errors.New("n must be at least 2")
	ErrNTooLarge          = errors.New("n cannot exceed maximum allowed")
)

const (
	MinN = 2
	MaxN = 10
	MinT = 1
)

// Threshold represents the t-of-n threshold configuration
type Threshold struct {
	t int // Minimum number of parties required
	n int // Total number of parties
}

// NewThreshold creates a new Threshold value object
func NewThreshold(t, n int) (Threshold, error) {
	if n < MinN {
		return Threshold{}, ErrNTooSmall
	}
	if n > MaxN {
		return Threshold{}, ErrNTooLarge
	}
	if t < MinT {
		return Threshold{}, ErrThresholdTooSmall
	}
	if t > n {
		return Threshold{}, ErrThresholdTooLarge
	}
	return Threshold{t: t, n: n}, nil
}

// MustNewThreshold creates a new Threshold, panics on error
func MustNewThreshold(t, n int) Threshold {
	threshold, err := NewThreshold(t, n)
	if err != nil {
		panic(err)
	}
	return threshold
}

// T returns the minimum required parties
func (th Threshold) T() int {
	return th.t
}

// N returns the total parties
func (th Threshold) N() int {
	return th.n
}

// IsZero checks if the Threshold is zero
func (th Threshold) IsZero() bool {
	return th.t == 0 && th.n == 0
}

// Equals checks if two Thresholds are equal
func (th Threshold) Equals(other Threshold) bool {
	return th.t == other.t && th.n == other.n
}

// String returns the string representation
func (th Threshold) String() string {
	return fmt.Sprintf("%d-of-%d", th.t, th.n)
}

// CanSign checks if the given number of parties can sign
func (th Threshold) CanSign(availableParties int) bool {
	return availableParties >= th.t
}

// RequiresAllParties checks if all parties are required
func (th Threshold) RequiresAllParties() bool {
	return th.t == th.n
}
