package collections

import (
	"errors"
)

type (
	Namespace struct{}

	seq struct {
		first     int
		increment int
		last      int
	}
)

func New() *Namespace {
	return &Namespace{}
}

var (
	ErrSeqFew    error = errors.New("seq must have at least one argument")
	ErrSeqMany   error = errors.New("seq must have no more than three arguments")
	ErrSeqZero   error = errors.New("seq increment must be not zero")
	ErrSeqLess   error = errors.New("seq increment must be less than zero")
	ErrSeqMore   error = errors.New("seq increment must be more than zero")
	ErrIndexLess error = errors.New("index is less than zero")
	ErrIndexMore error = errors.New("index is more than provided collection size")
)

func (ns *Namespace) Slice(items ...any) []any {
	return items
}

func (ns *Namespace) Seq(args ...int) ([]int, error) {
	if len(args) < 1 {
		return nil, ErrSeqFew
	}

	if 3 < len(args) {
		return nil, ErrSeqMany
	}

	opts := seq{
		first:     1,
		increment: 1,
		last:      args[len(args)-1],
	}

	switch len(args) {
	case 3: // NOTE(toby3d): first, increment, last
		opts.increment = args[1]

		switch {
		case opts.increment == 0:
			return nil, ErrSeqZero
		case opts.first < opts.last && opts.increment < 0:
			return nil, ErrSeqMore
		case opts.last < opts.first && 0 < opts.increment:
			return nil, ErrSeqMore
		}

		fallthrough
	case 2: // NOTE(toby3d): first, last
		opts.first = args[0]
	case 1: // NOTE(toby3d): last
		if opts.last < 0 {
			opts.first = opts.last
			opts.last = -1
		}
	}

	out := make([]int, 0)

	if opts.first < opts.last {
		for i := opts.first; i <= opts.last; i += opts.increment {
			out = append(out, i)
		}
	} else {
		for i := opts.first; opts.last <= i; i -= opts.increment {
			out = append(out, i)
		}
	}

	return out, nil
}

func (ns *Namespace) Index(collection []any, index int) (any, error) {
	if index < 0 {
		return nil, ErrIndexLess
	} else if len(collection) < index {
		return nil, ErrIndexMore
	}

	return collection[index], nil
}
