package iceberg

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

	"github.com/seaweedfs/seaweedfs/weed/s3api/s3tables"
)

func TestWantsVendedCredentials(t *testing.T) {
	tests := []struct {
		name   string
		values []string
		want   bool
	}{
		{name: "no header", want: false},
		{name: "vended credentials", values: []string{"vended-credentials"}, want: true},
		{name: "mechanism list", values: []string{"remote-signing,vended-credentials"}, want: true},
		{name: "spaced and mixed case", values: []string{"Remote-Signing, Vended-Credentials"}, want: true},
		{name: "repeated header", values: []string{"remote-signing", "vended-credentials"}, want: true},
		{name: "remote signing only", values: []string{"remote-signing"}, want: false},
	}
	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			r := httptest.NewRequest(http.MethodGet, "/v1/namespaces/ns/tables/t", nil)
			for _, v := range tc.values {
				r.Header.Add(accessDelegationHeader, v)
			}
			if got := wantsVendedCredentials(r); got != tc.want {
				t.Fatalf("wantsVendedCredentials(%v) = %v, want %v", tc.values, got, tc.want)
			}
		})
	}
}

// A client that asked for vended credentials replaces its own storage
// credentials with whatever the catalog returns. With no vending configured
// there are none, so an endpoint by itself would leave the client signing
// nothing and every data file read and write would come back 403.
func TestBuildFileIOConfigWithholdsEndpointFromCredentialVendingClients(t *testing.T) {
	s := &Server{s3Endpoint: "http://seaweed.example:8333"}

	r := httptest.NewRequest(http.MethodGet, "/v1/namespaces/ns/tables/t", nil)
	r.Header.Set(accessDelegationHeader, "vended-credentials")
	if got, _ := s.buildFileIOConfig(r, "s3://warehouse/ns/t"); len(got) != 0 {
		t.Fatalf("buildFileIOConfig() = %v, want empty for a vended-credentials request", got)
	}

	plain := httptest.NewRequest(http.MethodGet, "/v1/namespaces/ns/tables/t", nil)
	if got, _ := s.buildFileIOConfig(plain, "s3://warehouse/ns/t"); got["s3.endpoint"] != s.s3Endpoint {
		t.Fatalf("s3.endpoint = %q, want %q", got["s3.endpoint"], s.s3Endpoint)
	}
}

// The body of a load response depends on the delegation header, so a cache in
// front of the catalog must not key on the URL alone.
func TestWriteLoadResultVariesOnTheDelegationHeader(t *testing.T) {
	rec := httptest.NewRecorder()
	writeLoadResult(rec, http.StatusOK, LoadTableResult{})
	if got := rec.Header().Get("Vary"); got != accessDelegationHeader {
		t.Fatalf("Vary = %q, want %q", got, accessDelegationHeader)
	}
}

func TestLoadTableResultOmitsConfigForCredentialVendingClients(t *testing.T) {
	s := &Server{s3Endpoint: "http://seaweed.example:8333"}
	r := httptest.NewRequest(http.MethodGet, "/v1/namespaces/ns/tables/t", nil)
	r.Header.Set(accessDelegationHeader, "vended-credentials")

	getResp := s3tables.GetTableResponse{MetadataLocation: "s3://bkt/ns/t/metadata/v1.metadata.json"}
	result, err := s.buildLoadTableResult(r, getResp, "bkt", []string{"ns"}, "t")
	if err != nil {
		t.Fatalf("buildLoadTableResult() error = %v", err)
	}
	if len(result.Config) != 0 {
		t.Fatalf("LoadTableResult.Config = %v, want empty", result.Config)
	}
}
