package file

import (
	"sort"

	"github.com/mitchellh/hashstructure/v2"
	"github.com/scylladb/go-set/strset"
)

type CoordinateSet struct {
	set map[Coordinates]struct{}
}

func NewCoordinateSet(coordinates ...Coordinates) (s CoordinateSet) {
	for _, l := range coordinates {
		s.Add(l)
	}

	return s
}

func (s *CoordinateSet) Add(coordinates ...Coordinates) {
	if s.set == nil {
		s.set = make(map[Coordinates]struct{})
	}
	for _, l := range coordinates {
		s.set[l] = struct{}{}
	}
}

func (s CoordinateSet) Remove(coordinates ...Coordinates) {
	if s.set == nil {
		return
	}
	for _, l := range coordinates {
		delete(s.set, l)
	}
}

func (s CoordinateSet) Contains(l Coordinates) bool {
	if s.set == nil {
		return false
	}
	_, ok := s.set[l]
	return ok
}

func (s CoordinateSet) Paths() []string {
	if s.set == nil {
		return nil
	}

	paths := strset.New()
	for _, c := range s.ToSlice() {
		paths.Add(c.RealPath)
	}
	pathSlice := paths.List()
	sort.Strings(pathSlice)
	return pathSlice
}

func (s CoordinateSet) ToSlice() []Coordinates {
	if s.set == nil {
		return nil
	}
	coordinates := make([]Coordinates, len(s.set))
	idx := 0
	for v := range s.set {
		coordinates[idx] = v
		idx++
	}
	sort.SliceStable(coordinates, func(i, j int) bool {
		if coordinates[i].RealPath == coordinates[j].RealPath {
			return coordinates[i].FileSystemID < coordinates[j].FileSystemID
		}
		return coordinates[i].RealPath < coordinates[j].RealPath
	})
	return coordinates
}

func (s CoordinateSet) Hash() (uint64, error) {
	return hashstructure.Hash(s.ToSlice(), hashstructure.FormatV2, &hashstructure.HashOptions{
		ZeroNil:      true,
		SlicesAsSets: true,
	})
}
