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

package lunatask_test

import (
	"encoding/json"
	"testing"

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

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

	statuses := lunatask.AllTaskStatuses()

	// Check count
	if got := len(statuses); got != 5 {
		t.Fatalf("AllTaskStatuses() returned %d values, want 5", got)
	}

	// Check order
	expected := []lunatask.TaskStatus{
		lunatask.StatusLater,
		lunatask.StatusNext,
		lunatask.StatusInProgress,
		lunatask.StatusWaiting,
		lunatask.StatusCompleted,
	}
	for i, want := range expected {
		if statuses[i] != want {
			t.Errorf("AllTaskStatuses()[%d] = %q, want %q", i, statuses[i], want)
		}
	}

	// Check roundtrip: each value should be parseable
	for _, status := range statuses {
		parsed, err := lunatask.ParseTaskStatus(status.String())
		if err != nil {
			t.Errorf("ParseTaskStatus(%q) failed: %v", status.String(), err)
		}

		if parsed != status {
			t.Errorf("ParseTaskStatus(%q) = %q, want %q", status.String(), parsed, status)
		}
	}
}

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

	tests := []struct {
		name    string
		input   string
		want    lunatask.TaskStatus
		wantErr bool
	}{
		{"later_lower", "later", lunatask.StatusLater, false},
		{"later_upper", "LATER", lunatask.StatusLater, false},
		{"later_mixed", "LaTeR", lunatask.StatusLater, false},
		{"next_lower", "next", lunatask.StatusNext, false},
		{"next_upper", "NEXT", lunatask.StatusNext, false},
		{"in_progress_lower", "in-progress", lunatask.StatusInProgress, false},
		{"in_progress_upper", "IN-PROGRESS", lunatask.StatusInProgress, false},
		{"in_progress_mixed", "In-Progress", lunatask.StatusInProgress, false},
		{"waiting_lower", "waiting", lunatask.StatusWaiting, false},
		{"waiting_upper", "WAITING", lunatask.StatusWaiting, false},
		{"completed_lower", "completed", lunatask.StatusCompleted, false},
		{"completed_upper", "COMPLETED", lunatask.StatusCompleted, false},
		{"completed_mixed", "CoMpLeTeD", lunatask.StatusCompleted, false},
		{"invalid", "invalid", "", true},
		{"empty", "", "", true},
		{"numeric", "1", "", true},
		{"typo", "completd", "", true},
	}

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

			got, err := lunatask.ParseTaskStatus(testCase.input)
			if (err != nil) != testCase.wantErr {
				t.Errorf("ParseTaskStatus(%q) error = %v, wantErr %v", testCase.input, err, testCase.wantErr)

				return
			}

			if !testCase.wantErr && got != testCase.want {
				t.Errorf("ParseTaskStatus(%q) = %q, want %q", testCase.input, got, testCase.want)
			}
		})
	}
}

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

	tests := []struct {
		name  string
		value lunatask.TaskStatus
		want  string
	}{
		{"later", lunatask.StatusLater, `"later"`},
		{"next", lunatask.StatusNext, `"next"`},
		{"in_progress_to_started", lunatask.StatusInProgress, `"started"`},
		{"waiting", lunatask.StatusWaiting, `"waiting"`},
		{"completed", lunatask.StatusCompleted, `"completed"`},
	}

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

			got, err := json.Marshal(testCase.value)
			if err != nil {
				t.Fatalf("Marshal error: %v", err)
			}

			if string(got) != testCase.want {
				t.Errorf("json.Marshal(%q) = %s, want %s", testCase.value, got, testCase.want)
			}
		})
	}
}

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

	tests := []struct {
		name    string
		input   string
		want    lunatask.TaskStatus
		wantErr bool
	}{
		{"later", `"later"`, lunatask.StatusLater, false},
		{"next", `"next"`, lunatask.StatusNext, false},
		{"started_to_in_progress", `"started"`, lunatask.StatusInProgress, false},
		{"in_progress", `"in-progress"`, lunatask.StatusInProgress, false},
		{"waiting", `"waiting"`, lunatask.StatusWaiting, false},
		{"completed", `"completed"`, lunatask.StatusCompleted, false},
		{"invalid_type", `123`, "", true},
	}

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

			var got lunatask.TaskStatus

			err := json.Unmarshal([]byte(testCase.input), &got)

			if (err != nil) != testCase.wantErr {
				t.Errorf("Unmarshal error = %v, wantErr %v", err, testCase.wantErr)

				return
			}

			if !testCase.wantErr && got != testCase.want {
				t.Errorf("Unmarshal(%s) = %q, want %q", testCase.input, got, testCase.want)
			}
		})
	}
}
