package exploit

import (
	"context"
	"net/http"
	"net/http/httptest"
	"sync/atomic"
	"testing"
)

func TestParseHTTPReqArgs_Race(t *testing.T) {
	o, err := parseHTTPReqArgs([]string{"--url", "http://x", "--race", "10"})
	if err != nil || o.race != 10 {
		t.Fatalf("race=10 parse: race=%d err=%v", o.race, err)
	}
	// clamps to max
	o, _ = parseHTTPReqArgs([]string{"--url", "http://x", "--race", "999"})
	if o.race != maxRaceRequests {
		t.Errorf("expected clamp to %d, got %d", maxRaceRequests, o.race)
	}
	// invalid
	if _, err := parseHTTPReqArgs([]string{"--race", "1"}); err == nil {
		t.Error("--race 1 should error (needs >= 2)")
	}
	if _, err := parseHTTPReqArgs([]string{"--race", "abc"}); err == nil {
		t.Error("--race abc should error")
	}
}

// fireRace must send all N requests; the server counts them and grants 2xx to
// only the first (a single-use action), so exactly one 2xx should be reported.
func TestFireRace_ConcurrentSendAndCount(t *testing.T) {
	var hits, granted int64
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		atomic.AddInt64(&hits, 1)
		if atomic.AddInt64(&granted, 1) == 1 {
			w.WriteHeader(http.StatusOK)
			return
		}
		w.WriteHeader(http.StatusConflict) // 409: already used
	}))
	defer srv.Close()

	opts := httpReqOptions{method: "POST", url: srv.URL, race: 12}
	rep, summary, err := fireRace(context.Background(), &http.Client{}, opts)
	if err != nil {
		t.Fatal(err)
	}
	defer rep.Body.Close()
	if got := atomic.LoadInt64(&hits); got != 12 {
		t.Errorf("expected 12 requests fired, server saw %d", got)
	}
	if rep.StatusCode != http.StatusOK {
		t.Errorf("representative should be the 2xx winner, got %d", rep.StatusCode)
	}
	if summary == "" {
		t.Error("expected a race summary")
	}
}
