package pair

import (
	"iter"
)

type Pair[T any, K any] struct {
	First  T
	Second K
}

type Pairs[T any, K any] struct {
	list []*Pair[T, K]
}

func NewPairs[T any, K any]() *Pairs[T, K] {
	return &Pairs[T, K]{
		list: []*Pair[T, K]{},
	}
}

func (p *Pairs[T, K]) Len() int {
	return len(p.list)
}

func (p *Pairs[T, K]) Append(first T, second K) {
	p.list = append(p.list, &Pair[T, K]{First: first, Second: second})
}

// Pairs returns an iterator that yields the pair first and second elements.
//
// for example:
//
//	for first, second := range pairs.Pairs() {
//		fmt.Println(first, second)
//	}
func (p *Pairs[T, K]) Pairs() iter.Seq2[T, K] {
	return func(yield func(T, K) bool) {
		for _, pair := range p.list {
			if !yield(pair.First, pair.Second) {
				return
			}
		}
	}
}

// All returns an iterator that yields the pairs.
//
// for example:
//
//	for pair := range pairs.All() {
//		pair.First = 1
//		pair.Second = 2
//	}
func (p *Pairs[T, K]) All() iter.Seq[*Pair[T, K]] {
	return func(yield func(*Pair[T, K]) bool) {
		for _, pair := range p.list {
			if !yield(pair) {
				return
			}
		}
	}
}

// Firsts returns an iterator that yields the pair first elements.
//
// for example:
//
//	for first := range paris.Firsts() {
//		fmt.Println(first)
//	}
func (p *Pairs[T, K]) Firsts() iter.Seq[T] {
	return func(yield func(T) bool) {
		for _, pair := range p.list {
			if !yield(pair.First) {
				return
			}
		}
	}
}

// Seconds returns an iterator that yields the pair second elements.
//
// for example:
//
//	for second := range pairs.Seconds(pairs) {
//		fmt.Println(second)
//	}
func (p *Pairs[T, K]) Seconds() iter.Seq[K] {
	return func(yield func(K) bool) {
		for _, pair := range p.list {
			if !yield(pair.Second) {
				return
			}
		}
	}
}
