package readline

import (
	

	
)

// Completion represents a completion candidate.
type Completion = completion.Candidate

// Completions holds all completions candidates and their associated data,
// including usage strings, messages, and suffix matchers for autoremoval.
// Some of those additional settings will apply to all contained candidates,
// except when these candidates have their own corresponding settings.
type Completions struct {
	values   completion.RawValues
	messages completion.Messages
	noSpace  completion.SuffixMatcher
	usage    string
	listLong map[string]bool
	noSort   map[string]bool
	listSep  map[string]string
	pad      map[string]bool
	escapes  map[string]bool

	// Initially this will be set to the part of the current word
	// from the beginning of the word up to the position of the cursor.
	// It may be altered to give a prefix for all matches.
	PREFIX string

	// Initially this will be set to the part of the current word,
	// starting from the cursor position up to the end of the word.
	// It may be altered so that inserted completions don't overwrite
	// entirely any suffix when completing in the middle of a word.
	SUFFIX string
}

// CompleteValues completes arbitrary keywords (values).
func ( ...string) Completions {
	 := make([]Completion, 0, len())
	for ,  := range  {
		 = append(, Completion{
			Value:       ,
			Display:     ,
			Description: "",
		})
	}

	return Completions{values: }
}

// CompleteStyledValues is like CompleteValues but also accepts a style.
func ( ...string) Completions {
	if  := len(); %2 != 0 {
		return CompleteMessage("invalid amount of arguments [CompleteStyledValues]: %v", )
	}

	 := make([]Completion, 0, len()/2)
	for  := 0;  < len();  += 2 {
		 = append(, Completion{
			Value:       [],
			Display:     [],
			Description: "",
			Style:       [+1],
		})
	}

	return Completions{values: }
}

// CompleteValuesDescribed completes arbitrary key (values) with an additional description (value, description pairs).
func ( ...string) Completions {
	if  := len(); %2 != 0 {
		return CompleteMessage("invalid amount of arguments [CompleteValuesDescribed]: %v", )
	}

	 := make([]Completion, 0, len()/2)
	for  := 0;  < len();  += 2 {
		 = append(, Completion{
			Value:       [],
			Display:     [],
			Description: [+1],
		})
	}

	return Completions{values: }
}

// CompleteStyledValuesDescribed is like CompleteValues but also accepts a style.
func ( ...string) Completions {
	if  := len(); %3 != 0 {
		return CompleteMessage("invalid amount of arguments [CompleteStyledValuesDescribed]: %v", )
	}

	 := make([]Completion, 0, len()/3)
	for  := 0;  < len();  += 3 {
		 = append(, Completion{
			Value:       [],
			Display:     [],
			Description: [+1],
			Style:       [+2],
		})
	}

	return Completions{values: }
}

// CompleteMessage ads a help message to display along with
// or in places where no completions can be generated.
func ( string,  ...any) Completions {
	 := Completions{}

	if len() > 0 {
		 = fmt.Sprintf(, ...)
	}

	.messages.Add()

	return 
}

// CompleteRaw directly accepts a list of prepared Completion values.
func ( []Completion) Completions {
	return Completions{values: completion.RawValues()}
}

// Message displays a help messages in places where no completions can be generated.
func ( string,  ...any) Completions {
	 := Completions{}

	if len() > 0 {
		 = fmt.Sprintf(, ...)
	}

	.messages.Add()

	return 
}

// Suppress suppresses specific error messages using regular expressions.
func ( Completions) ( ...string) Completions {
	if  := .messages.Suppress(...);  != nil {
		return CompleteMessage(.Error())
	}

	return 
}

// NoSpace disables space suffix for given characters (or all if none are given).
// These suffixes will be used for all completions that have not specified their
// own suffix-matching patterns.
// This is used for slash-autoremoval in path completions, comma-separated completions, etc.
func ( Completions) ( ...rune) Completions {
	if len() == 0 {
		.noSpace.Add('*')
	}

	.noSpace.Add(...)

	return 
}

// Prefix adds a prefix to values (only the ones inserted, not the display values)
//
//	a := CompleteValues("melon", "drop", "fall").Invoke(c)
//	b := a.Prefix("water") // ["watermelon", "waterdrop", "waterfall"] but display still ["melon", "drop", "fall"]
func ( Completions) ( string) Completions {
	for ,  := range .values {
		.values[].Value =  + .Value
	}

	return 
}

// Suffix adds a suffx to values (only the ones inserted, not the display values)
//
//	a := CompleteValues("apple", "melon", "orange").Invoke(c)
//	b := a.Suffix("juice") // ["applejuice", "melonjuice", "orangejuice"] but display still ["apple", "melon", "orange"]
func ( Completions) ( string) Completions {
	for ,  := range .values {
		.values[].Value = .Value + 
	}

	return 
}

// Usage sets the usage.
func ( Completions) ( string,  ...any) Completions {
	return .UsageF(func() string {
		return fmt.Sprintf(, ...)
	})
}

// UsageF sets the usage using a function.
func ( Completions) ( func() string) Completions {
	if  := ();  != "" {
		.usage = 
	}

	return 
}

// Style sets the style, accepting cterm color codes, eg. 255, 30, etc.
//
//	CompleteValues("yes").Style("35")
//	CompleteValues("no").Style("255")
func ( Completions) ( string) Completions {
	return .StyleF(func( string) string {
		return 
	})
}

// StyleR sets the style using a reference
//
//	CompleteValues("value").StyleR(&style.Value)
//	CompleteValues("description").StyleR(&style.Value)
func ( Completions) ( *string) Completions {
	if  != nil {
		return .Style(*)
	}

	return 
}

// StyleF sets the style using a function
//
//	CompleteValues("dir/", "test.txt").StyleF(myStyleFunc)
//	CompleteValues("true", "false").StyleF(styleForKeyword)
func ( Completions) ( func( string) string) Completions {
	for ,  := range .values {
		.values[].Style = (.Value)
	}

	return 
}

// Tag sets the tag.
//
//	CompleteValues("192.168.1.1", "127.0.0.1").Tag("interfaces").
func ( Completions) ( string) Completions {
	return .TagF(func( string) string {
		return 
	})
}

// TagF sets the tag using a function.
//
//	CompleteValues("192.168.1.1", "127.0.0.1").TagF(func(value string) string {
//		return "interfaces"
//	})
func ( Completions) ( func( string) string) Completions {
	for ,  := range .values {
		.values[].Tag = (.Value)
	}

	return 
}

// DisplayList forces the completions to be list below each other as a list.
// A series of tags can be passed to restrict this to these tags. If empty,
// will be applied to all completions.
func ( Completions) ( ...string) Completions {
	if .listLong == nil {
		.listLong = make(map[string]bool)
	}

	if len() == 0 {
		.listLong["*"] = true
	}

	for ,  := range  {
		.listLong[] = true
	}

	return 
}

// ListSeparator accepts a custom separator to use between the candidates and their descriptions.
// If more than one separator is given, the list is considered to be a map of tag:separators, in
// which case it will fail if the list has an odd number of values.
//
// If one only one value is given, will apply to all completions (and their tags if any).
// If no value is given, no modifications will be made.
func ( Completions) ( ...string) Completions {
	if .listSep == nil {
		.listSep = make(map[string]string)
	}

	if  := len(); len() > 1 && %2 != 0 {
		return CompleteMessage("invalid amount of arguments (ListSeparator): %v", )
	}

	if len() == 1 {
		if len(.listSep) == 0 {
			.listSep["*"] = [0]
		} else {
			for  := range .listSep {
				.listSep[] = [0]
			}
		}
	} else {
		for  := 0;  < len();  += 2 {
			.listSep[[]] = [+1]
		}
	}

	return 
}

// NoSort forces the completions not to sort the completions in alphabetical order.
// A series of tags can be passed to restrict this to these tags. If empty, will be
// applied to all completions.
func ( Completions) ( ...string) Completions {
	if .noSort == nil {
		.noSort = make(map[string]bool)
	}

	if len() == 0 {
		.noSort["*"] = true
	}

	for ,  := range  {
		.noSort[] = true
	}

	return 
}

// Filter filters given values (this should be done before any call
// to Prefix/Suffix as those alter the values being filtered)
//
//	a := CompleteValues("A", "B", "C").Invoke(c)
//	b := a.Filter([]string{"B"}) // ["A", "C"]
func ( Completions) ( []string) Completions {
	.values = .values.Filter(...)
	return 
}

// JustifyDescriptions accepts a list of tags for which descriptions (if any), will be left justified.
// If no arguments are given, description justification (padding) will apply to all tags.
func ( Completions) ( ...string) Completions {
	if .pad == nil {
		.pad = make(map[string]bool)
	}

	if len() == 0 {
		.pad["*"] = true
	}

	for ,  := range  {
		.pad[] = true
	}

	return 
}

// PreserveEscapes forces the completion engine to keep all escaped characters in
// the inserted completion (c.Value of the Completion type). By default, those are
// stripped out and only kept in the completion.Display. If no arguments are given,
// escape sequence preservation will apply to all tags.
//
// This has very few use cases: one of them might be when you want to read a string
// from the readline shell that might include color sequences to be preserved.
// In such cases, this function gives a double advantage: the resulting completion
// is still "color-displayed" in the input line, and returned to the readline with
// them. A classic example is where you want to read a prompt string configuration.
//
// Note that this option might have various undefined behaviors when it comes to
// completion prefix matching, insertion, removal and related things.
func ( Completions) ( ...string) Completions {
	if .escapes == nil {
		.escapes = make(map[string]bool)
	}

	if len() == 0 {
		.escapes["*"] = true
	}

	for ,  := range  {
		.escapes[] = true
	}

	return 
}

// Merge merges Completions (existing values are overwritten)
//
//	a := CompleteValues("A", "B").Invoke(c)
//	b := CompleteValues("B", "C").Invoke(c)
//	c := a.Merge(b) // ["A", "B", "C"]
func ( Completions) ( ...Completions) Completions {
	 := make(map[string]Completion)

	for ,  := range append([]Completions{}, ...) {
		for ,  := range .values {
			[.Value] = 
		}
	}

	for ,  := range  {
		.merge()
	}

	 := make([]Completion, 0, len())
	for ,  := range  {
		 = append(, )
	}

	.values = 

	return 
}

// EachValue runs a function on each value, overwriting with the returned one.
func ( *Completions) ( func( Completion) Completion) {
	for ,  := range .values {
		.values[] = ()
	}
}

func ( *Completions) ( Completions) {
	if .usage != "" {
		.usage = .usage
	}

	.noSpace.Merge(.noSpace)
	.messages.Merge(.messages)

	for  := range .listLong {
		if ,  := .listLong[]; ! {
			.listLong[] = true
		}
	}

	for  := range .noSort {
		if ,  := .noSort[]; ! {
			.noSort[] = true
		}
	}

	for  := range .listSep {
		if ,  := .listSep[]; ! {
			.listSep[] = .listSep[]
		}
	}

	for  := range .pad {
		if ,  := .pad[]; ! {
			.pad[] = .pad[]
		}
	}
}

func ( *Completions) () completion.Values {
	 := completion.AddRaw(.values)

	.Messages = .messages
	.NoSpace = .noSpace
	.Usage = .usage
	.ListLong = .listLong
	.NoSort = .noSort
	.ListSep = .listSep
	.Pad = .pad
	.Escapes = .escapes

	.PREFIX = .PREFIX
	.SUFFIX = .SUFFIX

	return 
}