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

package lunatask_test

import (
	"context"
	"errors"
	"net/http"
	"net/http/httptest"
	"testing"

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

type pingTestCase struct {
	name           string
	statusCode     int
	responseBody   string
	wantMessage    string
	wantErr        error
	checkAuthToken string
}

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

	tests := []pingTestCase{
		{
			name:           "success",
			statusCode:     http.StatusOK,
			responseBody:   `{"message": "pong"}`,
			wantMessage:    "pong",
			wantErr:        nil,
			checkAuthToken: "test-token",
		},
		{
			name:           "unauthorized",
			statusCode:     http.StatusUnauthorized,
			responseBody:   `{"error": "unauthorized"}`,
			wantMessage:    "",
			wantErr:        lunatask.ErrUnauthorized,
			checkAuthToken: "bad-token",
		},
		{
			name:           "server_error",
			statusCode:     http.StatusInternalServerError,
			responseBody:   `{"error": "internal server error"}`,
			wantMessage:    "",
			wantErr:        lunatask.ErrServerError,
			checkAuthToken: "test-token",
		},
	}

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

func runPingTest(t *testing.T, testCase pingTestCase) {
	t.Helper()

	server := httptest.NewServer(makePingHandler(t, testCase.checkAuthToken, testCase.statusCode, testCase.responseBody))
	defer server.Close()

	client := lunatask.NewClient(testCase.checkAuthToken, lunatask.BaseURL(server.URL))
	resp, err := client.Ping(context.Background())

	if testCase.wantErr != nil {
		if err == nil {
			t.Fatalf("expected error %v, got nil", testCase.wantErr)
		}

		if !errors.Is(err, testCase.wantErr) {
			t.Errorf("expected error %v, got %v", testCase.wantErr, err)
		}

		return
	}

	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	if resp == nil {
		t.Fatal("expected response, got nil")
	}

	if resp.Message != testCase.wantMessage {
		t.Errorf("expected message %q, got %q", testCase.wantMessage, resp.Message)
	}
}

func makePingHandler(t *testing.T, expectedToken string, statusCode int, responseBody string) http.HandlerFunc {
	t.Helper()

	return func(writer http.ResponseWriter, req *http.Request) {
		if req.Method != http.MethodGet {
			t.Errorf("expected GET request, got %s", req.Method)
		}

		if req.URL.Path != "/ping" {
			t.Errorf("expected /ping path, got %s", req.URL.Path)
		}

		authHeader := req.Header.Get("Authorization")
		expectedAuth := "bearer " + expectedToken

		if authHeader != expectedAuth {
			t.Errorf("expected Authorization header %q, got %q", expectedAuth, authHeader)
		}

		writer.WriteHeader(statusCode)

		if _, err := writer.Write([]byte(responseBody)); err != nil {
			t.Errorf("failed to write response: %v", err)
		}
	}
}
