/**
 * Go SDK for OpenFGA
 *
 * API version: 1.x
 * Website: https://openfga.dev
 * Documentation: https://openfga.dev/docs
 * Support: https://openfga.dev/community
 * License: [Apache-2.0](https://github.com/openfga/go-sdk/blob/main/LICENSE)
 *
 * NOTE: This file was auto generated by OpenAPI Generator (https://openapi-generator.tech). DO NOT EDIT.
 */

package openfga

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

func TestStreamingChannel_Close(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	channel := &StreamingChannel[StreamedListObjectsResponse]{
		Results: make(chan StreamedListObjectsResponse),
		Errors:  make(chan error),
		cancel:  cancel,
	}

	channel.Close()

	select {
	case <-ctx.Done():
	case <-time.After(100 * time.Millisecond):
		t.Error("Context was not cancelled")
	}
}

func TestStreamedListObjectsChannel_Close(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	channel := &StreamedListObjectsChannel{
		Objects: make(chan StreamedListObjectsResponse),
		Errors:  make(chan error),
		cancel:  cancel,
	}

	channel.Close()

	select {
	case <-ctx.Done():
	case <-time.After(100 * time.Millisecond):
		t.Error("Context was not cancelled")
	}
}

func TestStreamedListObjectsWithAPI_Success(t *testing.T) {
	objects := []string{"document:1", "document:2", "document:3"}
	expectedResults := []string{}
	for _, obj := range objects {
		expectedResults = append(expectedResults, `{"result":{"object":"`+obj+`"}}`)
	}
	responseBody := strings.Join(expectedResults, "\n")

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/stores/test-store/streamed-list-objects" {
			t.Errorf("Expected path /stores/test-store/streamed-list-objects, got %s", r.URL.Path)
		}
		if r.Method != http.MethodPost {
			t.Errorf("Expected POST method, got %s", r.Method)
		}

		w.Header().Set("Content-Type", "application/x-ndjson")
		w.WriteHeader(http.StatusOK)
		_, _ = w.Write([]byte(responseBody))
	}))
	defer server.Close()

	config, err := NewConfiguration(Configuration{
		ApiUrl: server.URL,
	})
	if err != nil {
		t.Fatalf("Failed to create configuration: %v", err)
	}

	client := NewAPIClient(config)
	ctx := context.Background()

	request := ListObjectsRequest{
		Type:     "document",
		Relation: "viewer",
		User:     "user:anne",
	}

	channel, err := client.OpenFgaApi.StreamedListObjects(ctx, "test-store").
		Body(request).
		Execute()

	if err != nil {
		t.Fatalf("StreamedListObjects failed: %v", err)
	}

	defer channel.Close()

	receivedObjects := []string{}
	for obj := range channel.Objects {
		receivedObjects = append(receivedObjects, obj.Object)
	}

	if err := <-channel.Errors; err != nil {
		t.Fatalf("Received error from channel: %v", err)
	}

	if len(receivedObjects) != len(objects) {
		t.Fatalf("Expected %d objects, got %d", len(objects), len(receivedObjects))
	}

	for i, expected := range objects {
		if receivedObjects[i] != expected {
			t.Errorf("Expected object %s at index %d, got %s", expected, i, receivedObjects[i])
		}
	}
}

func TestStreamedListObjectsWithAPI_EmptyLines(t *testing.T) {
	responseBody := `{"result":{"object":"document:1"}}

{"result":{"object":"document:2"}}

{"result":{"object":"document:3"}}`

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/x-ndjson")
		w.WriteHeader(http.StatusOK)
		_, _ = w.Write([]byte(responseBody))
	}))
	defer server.Close()

	config, err := NewConfiguration(Configuration{
		ApiUrl: server.URL,
	})
	if err != nil {
		t.Fatalf("Failed to create configuration: %v", err)
	}

	client := NewAPIClient(config)
	ctx := context.Background()

	request := ListObjectsRequest{
		Type:     "document",
		Relation: "viewer",
		User:     "user:anne",
	}

	channel, err := client.OpenFgaApi.StreamedListObjects(ctx, "test-store").
		Body(request).
		Execute()

	if err != nil {
		t.Fatalf("StreamedListObjects failed: %v", err)
	}

	defer channel.Close()

	receivedObjects := []string{}
	for obj := range channel.Objects {
		receivedObjects = append(receivedObjects, obj.Object)
	}

	if len(receivedObjects) != 3 {
		t.Fatalf("Expected 3 objects, got %d", len(receivedObjects))
	}
}

func TestStreamedListObjectsWithAPI_ErrorInStream(t *testing.T) {
	responseBody := `{"result":{"object":"document:1"}}
{"error":{"code":500,"message":"Internal error"}}`

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/x-ndjson")
		w.WriteHeader(http.StatusOK)
		_, _ = w.Write([]byte(responseBody))
	}))
	defer server.Close()

	config, err := NewConfiguration(Configuration{
		ApiUrl: server.URL,
	})
	if err != nil {
		t.Fatalf("Failed to create configuration: %v", err)
	}

	client := NewAPIClient(config)
	ctx := context.Background()

	request := ListObjectsRequest{
		Type:     "document",
		Relation: "viewer",
		User:     "user:anne",
	}

	channel, err := client.OpenFgaApi.StreamedListObjects(ctx, "test-store").
		Body(request).
		Execute()

	if err != nil {
		t.Fatalf("StreamedListObjects failed: %v", err)
	}

	defer channel.Close()

	receivedObjects := []string{}
	for obj := range channel.Objects {
		receivedObjects = append(receivedObjects, obj.Object)
	}

	err = <-channel.Errors
	if err == nil {
		t.Fatal("Expected error from channel, got nil")
	}

	if !strings.Contains(err.Error(), "Internal error") {
		t.Errorf("Expected error message to contain 'Internal error', got %s", err.Error())
	}

	if len(receivedObjects) != 1 {
		t.Fatalf("Expected 1 object before error, got %d", len(receivedObjects))
	}
}

func TestStreamedListObjectsWithAPI_InvalidJSON(t *testing.T) {
	responseBody := `{"result":{"object":"document:1"}}
invalid json`

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/x-ndjson")
		w.WriteHeader(http.StatusOK)
		_, _ = w.Write([]byte(responseBody))
	}))
	defer server.Close()

	config, err := NewConfiguration(Configuration{
		ApiUrl: server.URL,
	})
	if err != nil {
		t.Fatalf("Failed to create configuration: %v", err)
	}

	client := NewAPIClient(config)
	ctx := context.Background()

	request := ListObjectsRequest{
		Type:     "document",
		Relation: "viewer",
		User:     "user:anne",
	}

	channel, err := client.OpenFgaApi.StreamedListObjects(ctx, "test-store").
		Body(request).
		Execute()

	if err != nil {
		t.Fatalf("StreamedListObjects failed: %v", err)
	}

	defer channel.Close()

	receivedObjects := []string{}
	for obj := range channel.Objects {
		receivedObjects = append(receivedObjects, obj.Object)
	}

	err = <-channel.Errors
	if err == nil {
		t.Fatal("Expected error from channel, got nil")
	}

	if len(receivedObjects) != 1 {
		t.Fatalf("Expected 1 object before error, got %d", len(receivedObjects))
	}
}

func TestStreamedListObjectsWithAPI_ContextCancellation(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/x-ndjson")
		w.WriteHeader(http.StatusOK)
		// Send first result
		_, _ = w.Write([]byte(`{"result":{"object":"document:1"}}` + "\n"))
		if f, ok := w.(http.Flusher); ok {
			f.Flush()
		}
		// Wait indefinitely to simulate a long stream
		<-r.Context().Done()
	}))
	defer server.Close()

	config, err := NewConfiguration(Configuration{
		ApiUrl: server.URL,
	})
	if err != nil {
		t.Fatalf("Failed to create configuration: %v", err)
	}

	client := NewAPIClient(config)
	ctx, cancel := context.WithCancel(context.Background())

	request := ListObjectsRequest{
		Type:     "document",
		Relation: "viewer",
		User:     "user:anne",
	}

	channel, err := client.OpenFgaApi.StreamedListObjects(ctx, "test-store").
		Body(request).
		Execute()

	if err != nil {
		t.Fatalf("StreamedListObjects failed: %v", err)
	}

	defer channel.Close()

	// Read first result
	obj := <-channel.Objects
	if obj.Object != "document:1" {
		t.Errorf("Expected document:1, got %s", obj.Object)
	}

	// Cancel context
	cancel()

	// Check that we get a cancellation error
	err = <-channel.Errors
	if err == nil {
		t.Fatal("Expected cancellation error, got nil")
	}

	if !strings.Contains(err.Error(), "context canceled") && !strings.Contains(err.Error(), "operation was canceled") {
		t.Errorf("Expected context cancellation error, got: %v", err)
	}
}

func TestStreamedListObjectsWithAPI_ManyObjects(t *testing.T) {
	numObjects := 100
	expectedResults := []string{}
	for i := 0; i < numObjects; i++ {
		expectedResults = append(expectedResults, `{"result":{"object":"document:`+strconv.Itoa(i)+`"}}`)
	}
	responseBody := strings.Join(expectedResults, "\n")

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/x-ndjson")
		w.WriteHeader(http.StatusOK)
		_, _ = w.Write([]byte(responseBody))
	}))
	defer server.Close()

	config, err := NewConfiguration(Configuration{
		ApiUrl: server.URL,
	})
	if err != nil {
		t.Fatalf("Failed to create configuration: %v", err)
	}

	client := NewAPIClient(config)
	ctx := context.Background()

	request := ListObjectsRequest{
		Type:     "document",
		Relation: "viewer",
		User:     "user:anne",
	}

	channel, err := client.OpenFgaApi.StreamedListObjects(ctx, "test-store").
		Body(request).
		Execute()

	if err != nil {
		t.Fatalf("StreamedListObjects failed: %v", err)
	}

	defer channel.Close()

	receivedObjects := []string{}
	for obj := range channel.Objects {
		receivedObjects = append(receivedObjects, obj.Object)
	}

	if err := <-channel.Errors; err != nil {
		t.Fatalf("Received error from channel: %v", err)
	}

	if len(receivedObjects) != numObjects {
		t.Fatalf("Expected %d objects, got %d", numObjects, len(receivedObjects))
	}
}

func TestProcessStreamingResponse_Generic(t *testing.T) {
	// Test the generic ProcessStreamingResponse function
	responseBody := `{"result":{"object":"document:1"}}
{"result":{"object":"document:2"}}`

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/x-ndjson")
		w.WriteHeader(http.StatusOK)
		_, _ = w.Write([]byte(responseBody))
	}))
	defer server.Close()

	resp, err := http.Get(server.URL)
	if err != nil {
		t.Fatalf("Failed to make request: %v", err)
	}

	channel, err := ProcessStreamingResponse[StreamedListObjectsResponse](context.Background(), resp, 10)
	if err != nil {
		t.Fatalf("ProcessStreamingResponse failed: %v", err)
	}
	defer channel.Close()

	receivedObjects := []string{}
	for obj := range channel.Results {
		receivedObjects = append(receivedObjects, obj.Object)
	}

	if len(receivedObjects) != 2 {
		t.Fatalf("Expected 2 objects, got %d", len(receivedObjects))
	}
}

func TestProcessStreamingResponse_NilResponse(t *testing.T) {
	channel, err := ProcessStreamingResponse[StreamedListObjectsResponse](context.Background(), nil, 10)
	if err == nil {
		t.Fatal("Expected error for nil response, got nil")
	}
	if channel != nil {
		t.Fatal("Expected nil channel for nil response")
	}
}

func TestProcessStreamingResponse_NilBody(t *testing.T) {
	resp := &http.Response{
		StatusCode: 200,
		Body:       nil,
	}
	channel, err := ProcessStreamingResponse[StreamedListObjectsResponse](context.Background(), resp, 10)
	if err == nil {
		t.Fatal("Expected error for nil body, got nil")
	}
	if channel != nil {
		t.Fatal("Expected nil channel for nil body")
	}
}
