package taskboard

import (
	"errors"
	"testing"

	"github.com/stretchr/testify/require"
)

func TestParseStatusAcceptsCurrentLifecycle(t *testing.T) {
	t.Parallel()

	tests := []struct {
		input    string
		expected Status
	}{
		{input: "todo", expected: StatusTodo},
		{input: "in_progress", expected: StatusInProgress},
		{input: "in_review", expected: StatusInReview},
		{input: "done", expected: StatusDone},
	}

	for _, test := range tests {
		test := test
		t.Run(test.input, func(t *testing.T) {
			t.Parallel()

			status, err := ParseStatus(test.input)
			require.NoError(t, err)
			require.Equal(t, test.expected, status)
		})
	}
}

func TestParseStatusRejectsValuesOutsideCurrentLifecycle(t *testing.T) {
	t.Parallel()

	for _, input := range []string{"open", "claimed", "completed", "paused"} {
		_, err := ParseStatus(input)
		require.Error(t, err)
		require.True(t, errors.Is(err, ErrBadRequest))
		require.Equal(t, `invalid status "`+input+`"`, err.Error())
	}
}

func TestParseStatusFilterAcceptsKnownValues(t *testing.T) {
	t.Parallel()

	tests := []struct {
		input    string
		expected string
	}{
		{input: "", expected: ""},
		{input: "all", expected: ""},
		{input: "todo", expected: string(StatusTodo)},
		{input: "in_progress", expected: string(StatusInProgress)},
		{input: "in_review", expected: string(StatusInReview)},
		{input: "done", expected: string(StatusDone)},
	}

	for _, test := range tests {
		test := test
		t.Run(test.input, func(t *testing.T) {
			t.Parallel()

			filter, err := ParseStatusFilter(test.input)
			require.NoError(t, err)
			require.Equal(t, test.expected, filter)
		})
	}
}

func TestParseStatusFilterRejectsValuesOutsideKnownVocabulary(t *testing.T) {
	t.Parallel()

	for _, input := range []string{"active", "open", "claimed", "completed", "non_done"} {
		_, err := ParseStatusFilter(input)
		require.Error(t, err)
		require.True(t, errors.Is(err, ErrBadRequest))
		require.Equal(t, "invalid status", err.Error())
	}
}

func TestNormalizeTaskBrowseStatusFilterKeepsKnownVocabulary(t *testing.T) {
	t.Parallel()

	tests := map[string]string{
		"":            "",
		"all":         "",
		"active":      "active",
		"todo":        "todo",
		"in_progress": "in_progress",
		"in_review":   "in_review",
		"done":        "done",
	}
	for input, expected := range tests {
		require.Equal(t, expected, normalizeTaskBrowseStatusFilter(input))
	}
	for _, input := range []string{"open", "claimed", "completed", "non_done"} {
		require.Equal(t, input, normalizeTaskBrowseStatusFilter(input))
	}
}

func TestParseChannelTarget(t *testing.T) {
	t.Parallel()

	t.Run("channel", func(t *testing.T) {
		t.Parallel()

		channelSlug, err := parseChannelTarget("#all")
		require.NoError(t, err)
		require.Equal(t, "all", channelSlug)
	})

	t.Run("reject thread target", func(t *testing.T) {
		t.Parallel()

		_, err := parseChannelTarget("#all:abcd1234")
		require.Error(t, err)
		require.True(t, errors.Is(err, ErrBadRequest))
		require.Equal(t, "threads do not support tasks", err.Error())
	})

	t.Run("reject dm target", func(t *testing.T) {
		t.Parallel()

		_, err := parseChannelTarget("DM:@m8x2ra")
		require.Error(t, err)
		require.True(t, errors.Is(err, ErrInvalidChannelTarget))
		require.Equal(t, "dm does not support tasks", err.Error())
	})

	t.Run("reject invalid target", func(t *testing.T) {
		t.Parallel()

		_, err := parseChannelTarget("general")
		require.Error(t, err)
		require.True(t, errors.Is(err, ErrInvalidChannelTarget))
		require.Equal(t, "invalid channel identifier", err.Error())
	})
}
