package httpapi

import (
	"context"
	"errors"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/easyai/easyai-ai-gateway/apps/api/internal/config"
)

func TestAdmittedTaskRunModeReservesAcceptanceAndProductionSimulation(t *testing.T) {
	server := &Server{cfg: config.Config{AppEnv: "production"}}
	for _, runMode := range []string{"simulation", "SIMULATION", "acceptance", "acceptance_canary"} {
		_, err := server.admittedTaskRunMode(taskTrafficAdmission{}, map[string]any{"runMode": runMode})
		var trafficErr *taskTrafficError
		if !errors.As(err, &trafficErr) || trafficErr.Status != 403 {
			t.Fatalf("run mode %q error=%v", runMode, err)
		}
	}
	for _, runMode := range []string{"acceptance", "acceptance_canary"} {
		got, err := server.admittedTaskRunMode(taskTrafficAdmission{RunMode: runMode}, map[string]any{
			"runMode": "production",
		})
		if err != nil || got != runMode {
			t.Fatalf("admitted mode=%q got=%q err=%v", runMode, got, err)
		}
	}
}

func TestCachedTaskTrafficAuthorizationCollapsesConcurrentLoads(t *testing.T) {
	server := &Server{}
	key := taskTrafficAuthorizationCacheKey{runID: "run", apiKeyID: "key", userID: "user"}
	var loads atomic.Int32
	start := make(chan struct{})
	const callers = 64
	var wg sync.WaitGroup
	errCh := make(chan error, callers)
	for range callers {
		wg.Add(1)
		go func() {
			defer wg.Done()
			<-start
			runID, err := server.cachedTaskTrafficAuthorization(
				context.Background(), key, time.Minute,
				func() (string, error) {
					loads.Add(1)
					time.Sleep(10 * time.Millisecond)
					return "run", nil
				},
			)
			if err != nil || runID != "run" {
				errCh <- errors.New("unexpected cached authorization result")
			}
		}()
	}
	close(start)
	wg.Wait()
	close(errCh)
	for err := range errCh {
		t.Fatal(err)
	}
	if got := loads.Load(); got != 1 {
		t.Fatalf("authorization loads=%d, want 1", got)
	}

	if _, err := server.cachedTaskTrafficAuthorization(
		context.Background(), key, time.Minute,
		func() (string, error) {
			loads.Add(1)
			return "run", nil
		},
	); err != nil {
		t.Fatal(err)
	}
	if got := loads.Load(); got != 1 {
		t.Fatalf("cached authorization loads=%d, want 1", got)
	}
}

func TestCachedTaskTrafficAuthorizationDoesNotCacheFailures(t *testing.T) {
	server := &Server{}
	key := taskTrafficAuthorizationCacheKey{runID: "run", apiKeyID: "key", userID: "user"}
	wantErr := errors.New("database unavailable")
	loads := 0
	for range 2 {
		_, err := server.cachedTaskTrafficAuthorization(
			context.Background(), key, time.Minute,
			func() (string, error) {
				loads++
				return "", wantErr
			},
		)
		if !errors.Is(err, wantErr) {
			t.Fatalf("authorization error=%v, want %v", err, wantErr)
		}
	}
	if loads != 2 {
		t.Fatalf("failed authorization loads=%d, want 2", loads)
	}
}
