package acceptance

import (
	"context"
	"net/http"
	"net/url"
	"os"
	"testing"
)

func TestMain(m *testing.M) {
	code := m.Run()
	if err := writeReport(testConfig); err != nil && code == 0 {
		code = 1
	}
	os.Exit(code)
}

func TestFixtureSeedLoader(t *testing.T) {
	c := cfg(t)
	ctx := context.Background()
	newFixtureLoader(c).SeedIfConfigured(t, ctx)
}

func TestPublicSmoke(t *testing.T) {
	c := cfg(t)
	ctx := context.Background()
	client := newClient(c)

	t.Run("happy path user info", func(t *testing.T) {
		token := loginUser(t, ctx, client, c)
		envelope, raw, status, err := client.WithToken(token).Get(ctx, "/v1/public/user/info", nil)
		if err != nil {
			t.Fatalf("request failed: %v", err)
		}
		assertOK(t, envelope, raw, status)
		recordCase(t, "public", http.MethodGet, "/v1/public/user/info", "200 envelope")
	})

	t.Run("error path missing auth", func(t *testing.T) {
		envelope, raw, status, err := client.Get(ctx, "/v1/public/user/info", nil)
		if err != nil {
			t.Fatalf("request failed: %v", err)
		}
		assertAPIError(t, envelope, raw, status)
		recordCase(t, "public", http.MethodGet, "/v1/public/user/info", "non-200 envelope without auth")
	})
}

func TestAdminSmoke(t *testing.T) {
	c := cfg(t)
	ctx := context.Background()
	client := newClient(c)

	t.Run("happy path current admin", func(t *testing.T) {
		token := loginAdmin(t, ctx, client, c)
		envelope, raw, status, err := client.WithToken(token).Get(ctx, "/v1/admin/user/current", nil)
		if err != nil {
			t.Fatalf("request failed: %v", err)
		}
		assertOK(t, envelope, raw, status)
		recordCase(t, "admin", http.MethodGet, "/v1/admin/user/current", "200 envelope")
	})

	t.Run("error path missing auth", func(t *testing.T) {
		envelope, raw, status, err := client.Get(ctx, "/v1/admin/user/current", nil)
		if err != nil {
			t.Fatalf("request failed: %v", err)
		}
		assertAPIError(t, envelope, raw, status)
		recordCase(t, "admin", http.MethodGet, "/v1/admin/user/current", "non-200 envelope without auth")
	})
}

func TestNodeSmoke(t *testing.T) {
	c := cfg(t)
	ctx := context.Background()
	client := newClient(c)
	loader := newFixtureLoader(c)

	t.Run("happy path server config", func(t *testing.T) {
		secret, err := loader.NodeSecret(ctx)
		if err != nil {
			t.Fatalf("load node secret: %v", err)
		}
		secret = requireSecret(t, "node secret", secret)
		query := url.Values{}
		query.Set("secret_key", secret)
		query.Set("protocols", c.NodeProtocol)
		envelope, raw, status, err := client.Get(ctx, "/v2/server/"+c.NodeServerID, query)
		if err != nil {
			t.Fatalf("request failed: %v", err)
		}
		assertOK(t, envelope, raw, status)
		recordCase(t, "node", http.MethodGet, "/v2/server/{server_id}", "200 envelope")
	})

	t.Run("error path invalid secret", func(t *testing.T) {
		query := url.Values{}
		query.Set("secret_key", "invalid-"+c.RunID)
		query.Set("protocols", c.NodeProtocol)
		_, raw, status, err := client.Get(ctx, "/v1/server/config", query)
		if err != nil {
			t.Fatalf("request failed: %v", err)
		}
		if status != http.StatusForbidden {
			t.Fatalf("http status = %d, want 403; body=%s", status, sanitizeBody(raw))
		}
		recordCase(t, "node", http.MethodGet, "/v1/server/config", "403 with invalid secret")
	})
}
