package migration

import (
	"context"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"
)

func TestParseRetryAfter(t *testing.T) {
	if got := parseRetryAfter("30"); got != 30*time.Second {
		t.Fatalf("seconds = %v", got)
	}
	if got := parseRetryAfter(""); got != 0 {
		t.Fatalf("empty = %v", got)
	}
	future := time.Now().Add(45 * time.Second).UTC().Format(http.TimeFormat)
	if got := parseRetryAfter(future); got < 40*time.Second || got > 50*time.Second {
		t.Fatalf("http date = %v", got)
	}
}

func TestRateLimitDelayUsesRetryAfter(t *testing.T) {
	ConfigureRateLimit(RateLimitConfig{
		MaxRetries: 3,
		BaseDelay:  100 * time.Millisecond,
		MaxDelay:   time.Second,
	})
	delay := rateLimitDelay(1, 500*time.Millisecond)
	if delay != 500*time.Millisecond {
		t.Fatalf("delay = %v", delay)
	}
	delay = rateLimitDelay(3, 0)
	if delay != 400*time.Millisecond {
		t.Fatalf("exponential delay = %v", delay)
	}
}

func TestAPIGETRetries429ThenSucceeds(t *testing.T) {
	ConfigureRateLimit(RateLimitConfig{
		MaxRetries: 5,
		BaseDelay:  5 * time.Millisecond,
		MaxDelay:   50 * time.Millisecond,
	})

	calls := 0
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		calls++
		if calls < 3 {
			w.Header().Set("Retry-After", "0")
			w.WriteHeader(http.StatusTooManyRequests)
			_, _ = w.Write([]byte(`{"error":"rateLimitExceeded"}`))
			return
		}
		w.WriteHeader(http.StatusOK)
		_, _ = w.Write([]byte(`{"ok":true}`))
	}))
	t.Cleanup(srv.Close)

	body, err := apiGet(context.Background(), srv.Client(), srv.URL, "token")
	if err != nil {
		t.Fatalf("apiGet: %v", err)
	}
	if string(body) != `{"ok":true}` {
		t.Fatalf("body = %q", body)
	}
	if calls != 3 {
		t.Fatalf("calls = %d", calls)
	}
}

func TestAPIGETReturnsRateLimitErrorAfterMaxRetries(t *testing.T) {
	ConfigureRateLimit(RateLimitConfig{
		MaxRetries: 2,
		BaseDelay:  time.Millisecond,
		MaxDelay:   10 * time.Millisecond,
	})

	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Retry-After", "0")
		w.WriteHeader(http.StatusTooManyRequests)
		_, _ = w.Write([]byte(`{"error":"quota"}`))
	}))
	t.Cleanup(srv.Close)

	_, err := apiGet(context.Background(), srv.Client(), srv.URL, "token")
	if !IsRateLimitError(err) {
		t.Fatalf("expected RateLimitError, got %v", err)
	}
}

func TestWorkerRateLimitErrorIsPending(t *testing.T) {
	if !IsRateLimitError(&RateLimitError{Cause: errTestRateLimit}) {
		t.Fatal("expected typed rate limit error")
	}
}

var errTestRateLimit = &RateLimitError{Cause: errTestRateLimitCause{}}

type errTestRateLimitCause struct{}

func (errTestRateLimitCause) Error() string { return "api rate limited (429): quota" }
