#!/usr/bin/env bash

_se_compgen_words(){
	local words="$1"
	local current="$2"
	local matches=()
	mapfile -t matches < <(compgen -W "${words}" -- "${current}")
	COMPREPLY+=("${matches[@]}")
}

_se_compgen_dirs(){
	local exclude="$1"
	local current="${2:-}"
	local matches=()
	if [[ -n ${current} ]]; then
		mapfile -t matches < <(compgen -d -X "${exclude}" -- "${current}")
	else
		mapfile -t matches < <(compgen -d -X "${exclude}")
	fi
	COMPREPLY+=("${matches[@]}")
}

_se_compgen_files(){
	local exclude="$1"
	local current="${2:-}"
	local matches=()
	if [[ -n ${current} ]]; then
		mapfile -t matches < <(compgen -f -X "${exclude}" -- "${current}")
	else
		mapfile -t matches < <(compgen -f -X "${exclude}")
	fi
	COMPREPLY+=("${matches[@]}")
}

_se_option_takes_argument(){
	local command_name="$1"
	local option="$2"

	case "${command_name}:${option}" in
		build:-o|build:--output-dir|extract-ebook:-o|extract-ebook:--output-dir|recompose-epub:-e|recompose-epub:--extra-css-file|recompose-epub:-o|recompose-epub:--output|split-file:-f|split-file:--filename-format|split-file:-s|split-file:--start-at|split-file:-t|split-file:--template-file|hyphenate:-l|hyphenate:--language|shift-endnotes:-a|shift-endnotes:--amount|shift-illustrations:-a|shift-illustrations:--amount|lint:-a|lint:--allow|create-draft:-a|create-draft:--author|create-draft:-e|create-draft:--email|create-draft:-f|create-draft:--fp-id|create-draft:-p|create-draft:--pg-id|create-draft:-r|create-draft:--translator|create-draft:-t|create-draft:--title)
			return 0
			;;
	esac

	return 1
}

_se_has_option(){
	local option=""
	local word=""
	local index=0

	for ((index = 1; index < COMP_CWORD; index++)); do
		word="${COMP_WORDS[index]}"

		for option in "$@"; do
			if [[ ${word} == "${option}" || ${word} == "${option}="* ]]; then
				return 0
			fi
		done
	done

	return 1
}

_se_count_positionals(){
	local command_name="$1"
	local count=0
	local index=0
	local skip_next=0
	local word=""

	for ((index = 2; index < COMP_CWORD; index++)); do
		word="${COMP_WORDS[index]}"

		if [[ ${skip_next} -eq 1 ]]; then
			skip_next=0
			continue
		fi

		if [[ ${word} == --*=* ]]; then
			continue
		fi

		if [[ ${word} == "-"* ]]; then
			if _se_option_takes_argument "${command_name}" "${word}"; then
				skip_next=1
			fi

			continue
		fi

		((count++))
	done

	printf "%s" "${count}"
}

_se(){
	COMPREPLY=()
	local cur="${COMP_WORDS[COMP_CWORD]}"
	local prev="${COMP_WORDS[COMP_CWORD-1]}"
	local positional_count=0
	local commands="--help --version add-file british2american build build-ids build-images build-loi build-manifest build-spine build-svg-titles build-title build-toc clean compare-versions create-draft css-select dec2roman extract-ebook find-mismatched-dashes find-mismatched-diacritics find-unusual-characters help hyphenate interactive-replace lint make-url-safe modernize-spelling prepare-release recompose-epub renumber-endnotes roman2dec semanticate shift-endnotes shift-illustrations split-file titlecase typogrify unicode-names word-count xpath"
	if ! _se_has_option "--color" "-p" "--plain"; then
		commands="--color --plain ${commands}"
	fi
	if [[ $COMP_CWORD -gt 1 ]]; then
		positional_count="$(_se_count_positionals "${COMP_WORDS[1]}")"

		case "${COMP_WORDS[1]}" in
			add-file)
				_se_compgen_words "-f --force -h --help" "${cur}"
				_se_compgen_words "dedication dramatis-personae endnotes epigraph glossary halftitlepage ignore" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			british2american)
				_se_compgen_words "-f --force -h --help -v --verbose" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				_se_compgen_files "!*.xhtml" "${cur}"
				;;
			build)
				# Complete directory names after -o= --output-dir=
				if [[ ${prev} == "-"* && ${cur} == "=" ]] ; then
					_se_compgen_dirs ".*"
					return 0
				fi
				_se_compgen_words "-b --kobo -c --check -h --help -k --kindle -o --output-dir= -p --proof -v --verbose -y --check-only" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			build-ids)
				_se_compgen_words "-h --help -n --no-endnotes -v --verbose" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			build-images)
				_se_compgen_words "-g --no-generate -h --help -v --verbose" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			build-loi)
				_se_compgen_words "-h --help -s --stdout" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			build-manifest)
				_se_compgen_words "-h --help -s --stdout" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			build-spine)
				_se_compgen_words "-h --help -s --stdout" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			build-svg-titles)
				_se_compgen_words "-h --help -v --verbose" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			build-title)
				_se_compgen_words "-h --help -n --no-newline -s --stdout" "${cur}"
				_se_compgen_dirs "!*.xhtml" "${cur}"
				;;
			build-toc)
				_se_compgen_words "-h --help -s --stdout" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			clean)
				_se_compgen_words "-h --help -v --verbose" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				_se_compgen_files "!*.xhtml" "${cur}"
				_se_compgen_files "!*.svg" "${cur}"
				_se_compgen_files "!*.css" "${cur}"
				;;
			compare-versions)
				_se_compgen_words "-h --help -i --include-se-files -n --no-images -v --verbose" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			create-draft)
				local options="-a --author= -e --email= -h --help -r --translator= -t --title= -v --verbose -w --white-label"
				if ! _se_has_option "-f" "--fp-id" "-o" "--offline" "-p" "--pg-id"; then
					options="${options} -f --fp-id= -o --offline -p --pg-id="
				fi
				_se_compgen_words "${options}" "${cur}"
				;;
			css-select)
				local options="-h --help"
				if ! _se_has_option "-f" "--only-filenames" "-q" "--quiet"; then
					options="${options} -f --only-filenames -q --quiet"
				fi
				_se_compgen_words "${options}" "${cur}"
				if [[ ${positional_count} -ge 1 ]]; then
					_se_compgen_dirs ".*" "${cur}"
					_se_compgen_files "!*.xhtml" "${cur}"
				fi
				;;
			dec2roman)
				_se_compgen_words "-h --help -n --no-newline" "${cur}"
				;;
			extract-ebook)
				# Complete directory names after -o= --output-dir=
				if [[ ${prev} == "-"* && ${cur} == "=" ]] ; then
					_se_compgen_dirs ".*"
					return 0
				fi
				_se_compgen_words "-h --help -o --output-dir= -v --verbose" "${cur}"
				_se_compgen_files "!*.mobi" "${cur}"
				_se_compgen_files "!*.azw3" "${cur}"
				_se_compgen_files "!*.epub" "${cur}"
				;;
			find-mismatched-dashes)
				_se_compgen_words "-h --help" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				_se_compgen_files "!*.xhtml" "${cur}"
				;;
			find-mismatched-diacritics)
				_se_compgen_words "-h --help" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				_se_compgen_files "!*.xhtml" "${cur}"
				;;
			find-unusual-characters)
				_se_compgen_words "-h --help" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				_se_compgen_files "!*.xhtml" "${cur}"
				;;
			help)
				;;
			hyphenate)
				_se_compgen_words "-h --help -i --ignore-h-tags -l --language= -v --verbose" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				_se_compgen_files "!*.xhtml" "${cur}"
				;;
			interactive-replace)
				_se_compgen_words "-d --dot-all -h --help -i --ignore-case -m --multiline -v --vim" "${cur}"
				if [[ ${positional_count} -ge 2 ]]; then
					_se_compgen_dirs ".*" "${cur}"
					_se_compgen_files ".*" "${cur}"
				fi
				;;
			lint)
				local options="-h --help -v --verbose"
				if ! _se_has_option "-a" "--allow" "-s" "--skip-lint-ignore"; then
					options="${options} -a --allow= -s --skip-lint-ignore"
				fi
				_se_compgen_words "${options}" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			make-url-safe)
				_se_compgen_words "-h --help -n --no-newline" "${cur}"
				;;
			modernize-spelling)
				_se_compgen_words "-h --help -n --no-hyphens -v --verbose" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				_se_compgen_files "!*.xhtml" "${cur}"
				;;
			prepare-release)
				_se_compgen_words "-h --help -r --no-revision -v --verbose -w --no-word-count" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			recompose-epub)
				# Complete file names after -o= --output=
				if [[ ${prev} == "-"* && ${cur} == "=" ]] ; then
					_se_compgen_files ".*"
					return 0
				fi
				_se_compgen_words "-e --extra-css-file= -h --help -i --image-files -o --output= -x --xhtml" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			renumber-endnotes)
				_se_compgen_words "-b --brute-force -h --help -v --verbose" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				;;
			roman2dec)
				_se_compgen_words "-h --help -n --no-newline" "${cur}"
				;;
			semanticate)
				_se_compgen_words "-h --help -v --verbose" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				_se_compgen_files "!*.xhtml" "${cur}"
				;;
			shift-endnotes)
				_se_compgen_words "-a --amount= -d --decrement -h --help -i --increment" "${cur}"
				if [[ ${positional_count} -ge 1 ]]; then
					_se_compgen_dirs ".*" "${cur}"
				fi
				;;
			shift-illustrations)
				_se_compgen_words "-a --amount= -d --decrement -h --help -i --increment" "${cur}"
				if [[ ${positional_count} -ge 1 ]]; then
					_se_compgen_dirs ".*" "${cur}"
				fi
				;;
			split-file)
				_se_compgen_words "-f --filename-format= -h --help -s --start-at= -t --template-file=" "${cur}"
				_se_compgen_files "!*.htm" "${cur}"
				_se_compgen_files "!*.html" "${cur}"
				_se_compgen_files "!*.xhtml" "${cur}"
				;;
			titlecase)
				_se_compgen_words "-h --help -n --no-newline" "${cur}"
				;;
			typogrify)
				_se_compgen_words "-h --help -n --no-quotes -v --verbose" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				_se_compgen_files "!*.xhtml" "${cur}"
				;;
			unicode-names)
				_se_compgen_words "-h --help" "${cur}"
				;;
			word-count)
				_se_compgen_words "-c --categorize -h --help -p --ignore-pg-boilerplate -x --exclude-se-files" "${cur}"
				_se_compgen_dirs ".*" "${cur}"
				_se_compgen_files "!*.htm" "${cur}"
				_se_compgen_files "!*.html" "${cur}"
				_se_compgen_files "!*.xhtml" "${cur}"
				;;
			xpath)
				local options="-h --help"
				if ! _se_has_option "-f" "--only-filenames" "-q" "--quiet"; then
					options="${options} -f --only-filenames -q --quiet"
				fi
				_se_compgen_words "${options}" "${cur}"
				if [[ ${positional_count} -ge 1 ]]; then
					_se_compgen_dirs ".*" "${cur}"
					_se_compgen_files "!*.xhtml" "${cur}"
				fi
				;;
		esac
	else
		_se_compgen_words "${commands}" "${cur}"
	fi
}

complete -F _se se
