package packs

import (
	"encoding/json"
	"net/url"
	"slices"
	"strings"
	"testing"
)

func TestConnectorCalloutProfileBatchQueryParamsSurviveOwnedProjection(t *testing.T) {
	definition := connectorCalloutProfileQueryParamsTestDefinition()
	component, err := newConnectorCalloutProfileComponent("connector-a", definition)
	if err != nil {
		t.Fatal(err)
	}

	projectionAny, err := component.ExpectedProjection()
	if err != nil {
		t.Fatal(err)
	}
	projection, ok := projectionAny.(connectorCalloutProfileProjectionRow)
	if !ok {
		t.Fatalf("projection type = %T", projectionAny)
	}
	if !slices.Equal(projection.BatchSpec.QueryParams["properties"], []string{"email", "archived"}) ||
		!slices.Equal(projection.BatchSpec.InactiveProbeQueryParams["archived"], []string{"true"}) {
		t.Fatalf("batch query parameters = %#v / %#v", projection.BatchSpec.QueryParams, projection.BatchSpec.InactiveProbeQueryParams)
	}

	payload, err := component.ExpectedPayload()
	if err != nil {
		t.Fatal(err)
	}
	var persisted connectorCalloutProfileDefinition
	if err := json.Unmarshal(payload, &persisted); err != nil {
		t.Fatal(err)
	}
	if !slices.Equal(persisted.BatchSpec.QueryParams["properties"], []string{"email", "archived"}) ||
		!slices.Equal(persisted.BatchSpec.InactiveProbeQueryParams["archived"], []string{"true"}) {
		t.Fatalf("owned payload query parameters = %#v / %#v", persisted.BatchSpec.QueryParams, persisted.BatchSpec.InactiveProbeQueryParams)
	}

	projection.BatchSpec.QueryParams["properties"][0] = "mutated"
	projection.BatchSpec.InactiveProbeQueryParams["archived"][0] = "false"
	againAny, err := component.ExpectedProjection()
	if err != nil {
		t.Fatal(err)
	}
	again := againAny.(connectorCalloutProfileProjectionRow)
	if again.BatchSpec.QueryParams["properties"][0] != "email" ||
		again.BatchSpec.InactiveProbeQueryParams["archived"][0] != "true" {
		t.Fatalf("caller mutation aliased component-owned query parameters: %#v / %#v", again.BatchSpec.QueryParams, again.BatchSpec.InactiveProbeQueryParams)
	}
}

func TestConnectorCalloutProfileBatchQueryParamsRejectMalformedShape(t *testing.T) {
	tests := []struct {
		name   string
		values url.Values
		want   string
	}{
		{name: "blank key", values: url.Values{" ": {"true"}}, want: "blank key"},
		{name: "empty values", values: url.Values{"archived": {}}, want: "at least one string value"},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			definition := connectorCalloutProfileQueryParamsTestDefinition()
			definition.BatchSpec.InactiveProbeQueryParams = test.values
			_, err := newConnectorCalloutProfileComponent("connector-a", definition)
			if err == nil || !strings.Contains(err.Error(), test.want) {
				t.Fatalf("error = %v, want containing %q", err, test.want)
			}
		})
	}
}

func connectorCalloutProfileQueryParamsTestDefinition() connectorCalloutProfileDefinition {
	return connectorCalloutProfileDefinition{
		ProfileName:   "default",
		CredentialRef: "connector-a-credential",
		EndpointClass: "crm.read",
		RetryPolicy: connectorCalloutProfileRetryPolicy{
			MaxAttempts: 1,
		},
		BatchSpec: connectorCalloutProfileBatchSpec{
			Method:          "POST",
			RelativePath:    "/crm/v3/objects/contacts/batch/read",
			MaxBatchSize:    100,
			IDsRequestField: "inputs",
			IDResponseField: "id",
			CredentialRef:   "connector-a-credential",
			EndpointClass:   "crm.read",
			QueryParams: url.Values{
				"properties": {"email", "archived"},
			},
			InactiveProbeQueryParams: url.Values{
				"archived": {"true"},
			},
		},
	}
}
