package consumer

import (
	"fmt"
)

// Strategy for partition to consumer assignement
type Strategy string

const (
	// StrategyRange is the default and assigns partition ranges to consumers.
	// Example with six partitions and two consumers:
	//   C1: [0, 1, 2]
	//   C2: [3, 4, 5]
	StrategyRange Strategy = "range"

	// StrategyRoundRobin assigns partitions by alternating over consumers.
	// Example with six partitions and two consumers:
	//   C1: [0, 2, 4]
	//   C2: [1, 3, 5]
	StrategyRoundRobin Strategy = "roundrobin"
)

// Error instances are wrappers for internal errors with a context and
// may be returned through the consumer's Errors() channel
type Error struct {
	Ctx string
	error
}

// --------------------------------------------------------------------

type none struct{}

type topicPartition struct {
	Topic     string
	Partition int32
}

func (tp *topicPartition) String() string {
	return fmt.Sprintf("%s-%d", tp.Topic, tp.Partition)
}

type offsetInfo struct {
	Offset   int64
	Metadata string
}

func (i offsetInfo) NextOffset(fallback int64) int64 {
	if i.Offset > -1 {
		return i.Offset
	}
	return fallback
}

type int32Slice []int32

func (p int32Slice) Len() int           { return len(p) }
func (p int32Slice) Less(i, j int) bool { return p[i] < p[j] }
func (p int32Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

// p, o should be sorted asc firstly.
func (p int32Slice) Diff(o int32Slice) (difference []int32) {
	if len(o) == 0 {
		return p
	}
	var i, j int

	for i < p.Len() && j < o.Len() {
		if p[i] == o[j] {
			i++
			if j < o.Len()-1 {
				j++
			}
		} else if p[i] < o[j] {
			difference = append(difference, p[i])
			i++
		} else if p[i] > o[j] {
			j++
		}
		// i not reach end. j reach end.
		if i < p.Len() && j >= o.Len() {
			difference = append(difference, p[i:p.Len()]...)
		}
	}
	return difference
}
