#!/bin/sh
set -eu

. aux/utils.sh
. tests/lib.sh

export XDG_DATA_HOME="$PWD/tests/test-profiles"

test_picking_first_makes_it_be_always_first() {
	testing 'picking first makes it be always first'
	OUT="$(mktemp)"
	ERR="$(mktemp)"
	PROFILE="always-picks-first-$(uuid)"
	for _ in $(seq 10); do
		printf 'always-picked\nnever-picked\n' | \
			./remembering \
				-p "$PROFILE" \
				-c 'head -n1' \
				1>"$OUT" 2>"$ERR"
		STATUS=$?
		assert_status 0
		assert_empty_stderr
		assert_stdout 'always-picked'
	done
	test_ok
}

INPUT='a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
w
x
y
z'

pick_x() {
	OUT="$(mktemp)"
	ERR="$(mktemp)"
	PICK="$1"

	echo "${2:-$INPUT}" | \
		./remembering \
			-p "$PROFILE" \
			-c "tee -a /dev/stderr | grep \"$PICK\"" \
			1>"$OUT" 2>"$ERR"
	STATUS=$?
	assert_status 0
	assert_stdout "$PICK"
}

assert_first() {
	FIRST="$(head -n1 "$ERR")"
	if [ "$FIRST" != "$1" ]; then
		printf '\nERR: Previous choice did not appear at the beginning of the list:\n\nexpected: %s\ngot:      %s\n' \
			"$1" "$FIRST" >&2
		exit 1
	fi
}

test_promoting_values() {
	testing 'promoting values'
	PROFILE="promoting-$(uuid)"

	pick_x h
	pick_x z # just to get the new STDIN
	assert_first h

	pick_x h
	pick_x z
	assert_first h
	test_ok
}

test_higher_values_loose_tie() {
	testing 'higher values loose tie'
	PROFILE="higher-loose-tie-$(uuid)"

	pick_x f
	pick_x f
	pick_x g
	pick_x g
	pick_x z
	assert_first f
	test_ok
}

test_smaller_values_win_tie() {
	testing 'smaller values win tie'
	PROFILE="smaller-win-tie-$(uuid)"

	pick_x d
	pick_x d
	pick_x c
	pick_x c
	pick_x z
	assert_first c
	test_ok
}

test_many_sequential_picks() {
	testing 'many sequential pick'
	PROFILE="many-sequential-picks-$(uuid)"

	pick_x b
	pick_x r
	pick_x l
	pick_x r
	pick_x s
	pick_x a
	pick_x d
	pick_x m
	pick_x g
	pick_x g
	pick_x l
	pick_x l
	pick_x f
	pick_x f
	pick_x f
	pick_x l
	pick_x a

	pick_x z
	assert_first l

	EXPECTED='l
f
a
g
r
b
d
m
s'
	ACTUAL="$(head -n9 "$ERR")"
	if [ "$ACTUAL" != "$EXPECTED" ]; then
		printf '\nERR: Bad order!\n\nexpected: %s\ngot:      %s\n' \
			"$(echo "$EXPECTED" | tr '\n' ' ')" \
			"$(echo "$ACTUAL"   | tr '\n' ' ')" \
			>&2
		exit 1
	fi
	test_ok
}

test_stdin_profile_merging() {
	testing 'STDIN/profile merging'
	PROFILE="stdin-profile-merging-$(uuid)"
	echo '0:a
0:b
0:c
0:z' > "$XDG_DATA_HOME/$PROFILE"
	INPUT='a
b
c
d
e'
	pick_x a "$INPUT"
	if [ "$(cat "$ERR")" != "$INPUT" ]; then
		printf '\nERR: Bad profile merge.\n\nExpected:\n%s\nGot:\n%s\n' \
			"$INPUT" "$(cat "$ERR")" >&2
		exit 1
	fi
	test_ok
}

BASE_PROFILE='0:a
0:b
0:c
0:d
0:e'
BASE_PROFILE_A_PICKED='1:a
0:b
0:c
0:d
0:e'
assert_profile() {
	if [ "$(cat "$XDG_DATA_HOME/$1")" != "$2" ]; then
		printf '\nERR: Bad profile merge (%s).\n\nExpected:\n%s\nGot\n%s\n' \
			"$PROFILE" "$2" "$(cat "$XDG_DATA_HOME/$1")" >&2
		exit 1
	fi
}

test_stdin_is_larger_than_profile() {
	testing 'STDIN is larger than profile'
	PROFILE="stdin-is-larger-than-profile-$(uuid)"
	echo '0:a' > "$XDG_DATA_HOME/$PROFILE"
	INPUT='a
b
c
d
e'
	pick_x a "$INPUT"
	assert_profile "$PROFILE" "$BASE_PROFILE_A_PICKED"
	test_ok
}

test_stdin_is_smaller_than_profile() {
	testing 'STDIN is smaller than profile'
	PROFILE="stdin-is-smaller-than-profile-$(uuid)"
	echo "$BASE_PROFILE" > "$XDG_DATA_HOME/$PROFILE"
	INPUT='a'
	pick_x a "$INPUT"
	assert_profile "$PROFILE" "$BASE_PROFILE_A_PICKED"
	test_ok
}

test_stdin_is_empty() {
	testing 'STDIN is empty'
	PROFILE="stdin-is-empty-$(uuid)"
	echo "$BASE_PROFILE" > "$XDG_DATA_HOME/$PROFILE"
	OUT="$(mktemp)"
	ERR="$(mktemp)"

	printf '' | \
		./remembering \
			-p "$PROFILE" \
			-c 'tee -a /dev/stderr | head -n1' \
			1>"$OUT" 2>"$ERR"

	STATUS=$?
	assert_status 0
	assert_stdout ''
	assert_profile "$PROFILE" "$BASE_PROFILE"
	test_ok
}

test_profile_does_not_exist() {
	testing 'profile does not exist'
	PROFILE="profile-does-not-exist-$(uuid)"
	INPUT='a
b
c
d
e'
	pick_x a "$INPUT"
	assert_profile "$PROFILE" "$BASE_PROFILE_A_PICKED"
	test_ok
}

test_profile_is_empty() {
	testing 'profile is empty'
	PROFILE="profile-is-empty-$(uuid)"
	printf '' > "$XDG_DATA_HOME/$PROFILE"
	INPUT='a
b
c
d
e'
	pick_x a "$INPUT"
	assert_profile "$PROFILE" "$BASE_PROFILE_A_PICKED"
	test_ok
}

test_names_with_spaces() {
	testing 'Names with spaces'
	PROFILE="names-with-spaces-$(uuid)"
	INPUT='a b c
d e f'
	EXPECTED='1:a b c
0:d e f'
	pick_x 'a b c' "$INPUT"
	assert_profile "$PROFILE" "$EXPECTED"
	test_ok
}

test_really_long_list() {
	testing 'really long list'
	OUT="$(mktemp)"
	ERR="$(mktemp)"
	PROFILE="really-long-list-$(uuid)"
	seq 999999 | \
		./remembering \
			-p "$PROFILE" \
			-c 'head -n1' \
			1>"$OUT" 2>"$ERR"
	STATUS=$?
	assert_status 0
	assert_empty_stderr
	assert_stdout '1'
	test_ok
}

test_picking_first_makes_it_be_always_first
test_promoting_values
test_higher_values_loose_tie
test_smaller_values_win_tie
test_many_sequential_picks
test_stdin_profile_merging
test_stdin_is_larger_than_profile
test_stdin_is_smaller_than_profile
test_stdin_is_empty
test_profile_does_not_exist
test_profile_is_empty
test_names_with_spaces
# test_really_long_list