import { Callable, Callable1, InputEvent, LineEdit, Variant } from 'godot'
import { export_, onready } from 'godot.annotations'
import { Enumerable, IEnumerable } from '../enumerable-ts/src/index'
import { Action } from './dev_console'

export default class AutocompleteLine extends LineEdit {
	@export_(Variant.Type.TYPE_BOOL)
	private auto_suggest: boolean = true

	@onready("Suggestion")
	private suggestion!: LineEdit

	autocomplete_list: string[] = []
	current_suggestions: string[] = []
	suggestion_index: number = -1
	suppress_focus_change: boolean = true

	_on_text_changed!: Callable1<string>

	_ready(): void {
		this._on_text_changed = Callable.create(this, this.suggest)

		if (this.auto_suggest) {
			this.text_changed.connect(this._on_text_changed)
		}
	}

	_input(event: InputEvent): void {
		if (this.has_focus() && this.suppress_focus_change)
			if (event.is_action_pressed(Action.FocusPrevious)) {
				this.accept_event()
				this.autocomplete(-1)
			} else if (event.is_action_pressed(Action.FocusNext)) {
				this.accept_event()
				this.autocomplete(1)
			}
	}

	suggest(value: string): boolean {
		this.reset()

		if (value == '') {
			return false
		}

		this.current_suggestions = this.fuzzy_find(value)

		if (this.current_suggestions.length > 0) {
			const suggestion = this.current_suggestions[0]
			if (suggestion != null) {
				// create the illusion that the text is autocompleting
				// by replacing the already typed characters with spaces
				const padded = suggestion.slice(value.length).padStart(suggestion.length, ' ')
				this.suggestion.text = padded
				return true
			}
		}

		this.suggestion.text = ''
		return false
	}

	set_caret_to_end() {
		this.caret_column = this.text.length + 1
	}

	autocomplete(direction: (-1 | 1)) {
		if (this.current_suggestions.length > 0) {
			this.suggestion_index = (this.suggestion_index + direction) % this.current_suggestions.length
			this.text = this.current_suggestions.at(this.suggestion_index) || ''
			this.suggestion.clear()
			this.set_caret_to_end()
		}
	}

	fuzzy_find(value: string): string[] {
		return this.autocomplete_list.filter(text => text != null && text.startsWith(value))
	}

	reset() {
		this.current_suggestions = []
		this.suggestion_index = -1
		this.suggestion.text = ''
	}
}
