//go:build failpoint

package server

import (
	"bytes"
	"context"
	"encoding/json"
	"io"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/pingcap/failpoint"

	"github.com/mem9-ai/drive9/pkg/tenant"
)

const beforeTenantObjectNamespaceLockFailpoint = "github.com/mem9-ai/drive9/pkg/meta/beforeTenantExtractConfigLock"

// A terminal tenant delete committing between the namespace PUT's
// authorization precheck and its write transaction must win: the PUT
// fails with 404 and no namespace row can exist after the committed delete.
func TestAdminObjectNamespacePutVsTerminalDelete(t *testing.T) {
	rt := newQuotaRuntime(t, tenant.ProviderTiDBCloudNative)
	ts := httptest.NewServer(rt.server)
	defer ts.Close()
	ctx := context.Background()

	if err := failpoint.EnableCall(beforeTenantObjectNamespaceLockFailpoint, func(tenantID string) {
		if tenantID != rt.tenantID {
			return
		}
		if err := rt.meta.MarkTenantDeleted(context.Background(), tenantID); err != nil {
			t.Errorf("mark tenant deleted: %v", err)
		}
	}); err != nil {
		t.Fatalf("enable failpoint: %v", err)
	}
	t.Cleanup(func() { _ = failpoint.Disable(beforeTenantObjectNamespaceLockFailpoint) })

	body, _ := json.Marshal(map[string]any{
		"public_key": "public-1", "private_key": "private-1", "namespace_id": "race-cust",
	})
	req, err := http.NewRequest(http.MethodPut, ts.URL+"/v1/admin/tenants/"+rt.tenantID+"/object-namespace", bytes.NewReader(body))
	if err != nil {
		t.Fatal(err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set(quotaPublicKeyHeader, "public-1")
	req.Header.Set(quotaPrivateKeyHeader, "private-1")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer func() { _ = resp.Body.Close() }()
	if resp.StatusCode != http.StatusNotFound {
		b, _ := io.ReadAll(resp.Body)
		t.Fatalf("PUT status = %d, want 404 body=%s", resp.StatusCode, b)
	}
	got, err := rt.meta.GetTenantObjectNamespaceID(ctx, rt.tenantID)
	if err != nil {
		t.Fatal(err)
	}
	if got != "" {
		t.Fatalf("namespace after committed terminal delete = %q, want empty", got)
	}
}
