// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package lunatask_test

import (
	"testing"

	lunatask "git.secluded.site/go-lunatask"
)

// --- Eisenhower Type Constants ---

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

	tests := []struct {
		name  string
		value lunatask.Eisenhower
		want  int
	}{
		{"uncategorized", lunatask.EisenhowerUncategorized, 0},
		{"do_now", lunatask.EisenhowerDoNow, 1},
		{"delegate", lunatask.EisenhowerDelegate, 2},
		{"do_later", lunatask.EisenhowerDoLater, 3},
		{"eliminate", lunatask.EisenhowerEliminate, 4},
	}

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

			if int(tc.value) != tc.want {
				t.Errorf("Eisenhower constant = %d, want %d", tc.value, tc.want)
			}
		})
	}
}

// --- Eisenhower Helper Methods ---

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

	tests := []struct {
		name  string
		value lunatask.Eisenhower
		want  bool
	}{
		{"uncategorized", lunatask.EisenhowerUncategorized, false},
		{"do_now", lunatask.EisenhowerDoNow, true},         // urgent + important
		{"delegate", lunatask.EisenhowerDelegate, true},    // urgent only
		{"do_later", lunatask.EisenhowerDoLater, false},    // important only
		{"eliminate", lunatask.EisenhowerEliminate, false}, // neither
	}

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

			if got := tc.value.IsUrgent(); got != tc.want {
				t.Errorf("Eisenhower(%d).IsUrgent() = %v, want %v", tc.value, got, tc.want)
			}
		})
	}
}

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

	tests := []struct {
		name  string
		value lunatask.Eisenhower
		want  bool
	}{
		{"uncategorized", lunatask.EisenhowerUncategorized, false},
		{"do_now", lunatask.EisenhowerDoNow, true},         // urgent + important
		{"delegate", lunatask.EisenhowerDelegate, false},   // urgent only
		{"do_later", lunatask.EisenhowerDoLater, true},     // important only
		{"eliminate", lunatask.EisenhowerEliminate, false}, // neither
	}

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

			if got := tc.value.IsImportant(); got != tc.want {
				t.Errorf("Eisenhower(%d).IsImportant() = %v, want %v", tc.value, got, tc.want)
			}
		})
	}
}

// --- Eisenhower Helper Function ---

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

	tests := []struct {
		name      string
		important bool
		urgent    bool
		want      lunatask.Eisenhower
	}{
		{"both", true, true, lunatask.EisenhowerDoNow},
		{"urgent_only", false, true, lunatask.EisenhowerDelegate},
		{"important_only", true, false, lunatask.EisenhowerDoLater},
		{"neither", false, false, lunatask.EisenhowerEliminate},
	}

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

			got := lunatask.NewEisenhower(testCase.important, testCase.urgent)
			if got != testCase.want {
				t.Errorf("NewEisenhower(%v, %v) = %d, want %d", testCase.important, testCase.urgent, got, testCase.want)
			}
		})
	}
}

// --- TaskBuilder Semantic Methods ---

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

	server, capture := newPOSTServer(t, "/tasks", singleTaskResponseBody)
	defer server.Close()

	client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))

	_, err := client.NewTask("Important task").
		Important().
		Create(ctx())
	if err != nil {
		t.Fatalf("error = %v", err)
	}

	// Important only = 3 (DoLater)
	assertBodyFieldFloat(t, capture.Body, "eisenhower", 3)
}

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

	server, capture := newPOSTServer(t, "/tasks", singleTaskResponseBody)
	defer server.Close()

	client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))

	_, err := client.NewTask("Urgent task").
		Urgent().
		Create(ctx())
	if err != nil {
		t.Fatalf("error = %v", err)
	}

	// Urgent only = 2 (Delegate)
	assertBodyFieldFloat(t, capture.Body, "eisenhower", 2)
}

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

	server, capture := newPOSTServer(t, "/tasks", singleTaskResponseBody)
	defer server.Close()

	client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))

	_, err := client.NewTask("Do now task").
		Important().
		Urgent().
		Create(ctx())
	if err != nil {
		t.Fatalf("error = %v", err)
	}

	// Both = 1 (DoNow)
	assertBodyFieldFloat(t, capture.Body, "eisenhower", 1)
}

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

	server, capture := newPOSTServer(t, "/tasks", singleTaskResponseBody)
	defer server.Close()

	client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))

	_, err := client.NewTask("Do now task").
		Urgent().
		Important().
		Create(ctx())
	if err != nil {
		t.Fatalf("error = %v", err)
	}

	// Both = 1 (DoNow), order shouldn't matter
	assertBodyFieldFloat(t, capture.Body, "eisenhower", 1)
}

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

	server, capture := newPOSTServer(t, "/tasks", singleTaskResponseBody)
	defer server.Close()

	client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))

	// Explicitly set neither - should result in Eliminate (4)
	_, err := client.NewTask("Eliminate task").
		NotImportant().
		NotUrgent().
		Create(ctx())
	if err != nil {
		t.Fatalf("error = %v", err)
	}

	// Neither = 4 (Eliminate)
	assertBodyFieldFloat(t, capture.Body, "eisenhower", 4)
}

// --- TaskUpdateBuilder Semantic Methods ---

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

	server, capture := newPUTServer(t, "/tasks/"+taskID, singleTaskResponseBody)
	defer server.Close()

	client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))

	_, err := client.NewTaskUpdate(taskID).
		Important().
		Update(ctx())
	if err != nil {
		t.Fatalf("error = %v", err)
	}

	// Important only = 3 (DoLater)
	assertBodyFieldFloat(t, capture.Body, "eisenhower", 3)
}

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

	server, capture := newPUTServer(t, "/tasks/"+taskID, singleTaskResponseBody)
	defer server.Close()

	client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))

	_, err := client.NewTaskUpdate(taskID).
		Urgent().
		Update(ctx())
	if err != nil {
		t.Fatalf("error = %v", err)
	}

	// Urgent only = 2 (Delegate)
	assertBodyFieldFloat(t, capture.Body, "eisenhower", 2)
}

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

	server, capture := newPUTServer(t, "/tasks/"+taskID, singleTaskResponseBody)
	defer server.Close()

	client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))

	_, err := client.NewTaskUpdate(taskID).
		Important().
		Urgent().
		Update(ctx())
	if err != nil {
		t.Fatalf("error = %v", err)
	}

	// Both = 1 (DoNow)
	assertBodyFieldFloat(t, capture.Body, "eisenhower", 1)
}

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

	server, capture := newPUTServer(t, "/tasks/"+taskID, singleTaskResponseBody)
	defer server.Close()

	client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))

	_, err := client.NewTaskUpdate(taskID).
		NotImportant().
		NotUrgent().
		Update(ctx())
	if err != nil {
		t.Fatalf("error = %v", err)
	}

	// Neither = 4 (Eliminate)
	assertBodyFieldFloat(t, capture.Body, "eisenhower", 4)
}

// --- WithEisenhower still works with typed constant ---

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

	server, capture := newPOSTServer(t, "/tasks", singleTaskResponseBody)
	defer server.Close()

	client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))

	_, err := client.NewTask("Typed eisenhower").
		WithEisenhower(lunatask.EisenhowerDoNow).
		Create(ctx())
	if err != nil {
		t.Fatalf("error = %v", err)
	}

	assertBodyFieldFloat(t, capture.Body, "eisenhower", 1)
}

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

	server, capture := newPUTServer(t, "/tasks/"+taskID, singleTaskResponseBody)
	defer server.Close()

	client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))

	_, err := client.NewTaskUpdate(taskID).
		WithEisenhower(lunatask.EisenhowerDelegate).
		Update(ctx())
	if err != nil {
		t.Fatalf("error = %v", err)
	}

	assertBodyFieldFloat(t, capture.Body, "eisenhower", 2)
}
