package apiimp

import (
	"testing"

	"github.com/tech/sendico/pkg/discovery"
)

func TestParseDiscoveryInvokeURI(t *testing.T) {
	testCases := []struct {
		name     string
		raw      string
		address  string
		insecure bool
		wantErr  bool
	}{
		{
			name:     "host_port",
			raw:      "ledger:50052",
			address:  "ledger:50052",
			insecure: true,
		},
		{
			name:     "grpc_scheme",
			raw:      "grpc://payments-orchestrator:50062",
			address:  "payments-orchestrator:50062",
			insecure: true,
		},
		{
			name:     "grpcs_scheme",
			raw:      "grpcs://payments-orchestrator:50062",
			address:  "payments-orchestrator:50062",
			insecure: false,
		},
		{
			name:     "dns_scheme",
			raw:      "dns:///ledger:50052",
			address:  "dns:///ledger:50052",
			insecure: true,
		},
		{
			name:    "invalid",
			raw:     "ledger",
			wantErr: true,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			endpoint, err := parseDiscoveryInvokeURI(tc.raw)
			if tc.wantErr {
				if err == nil {
					t.Fatalf("expected error for %q", tc.raw)
				}
				return
			}
			if err != nil {
				t.Fatalf("parseDiscoveryInvokeURI(%q) failed: %v", tc.raw, err)
			}
			if endpoint.address != tc.address {
				t.Fatalf("expected address %q, got %q", tc.address, endpoint.address)
			}
			if endpoint.insecure != tc.insecure {
				t.Fatalf("expected insecure %t, got %t", tc.insecure, endpoint.insecure)
			}
		})
	}
}

func TestSelectServiceEndpointPrefersRequiredOperation(t *testing.T) {
	services := []discovery.ServiceSummary{
		{
			ID:        "candidate-without-op",
			Service:   "LEDGER",
			Healthy:   true,
			InvokeURI: "ledger-2:50052",
			Ops:       []string{"balance.read"},
		},
		{
			ID:        "candidate-with-op",
			Service:   "LEDGER",
			Healthy:   true,
			InvokeURI: "ledger-1:50052",
			Ops:       []string{"ledger.debit"},
		},
	}

	endpoint, selected, ok := selectServiceEndpoint(services, []string{"LEDGER"}, []string{"ledger.debit"})
	if !ok {
		t.Fatal("expected service endpoint to be selected")
	}
	if selected.ID != "candidate-with-op" {
		t.Fatalf("expected candidate-with-op, got %s", selected.ID)
	}
	if endpoint.address != "ledger-1:50052" {
		t.Fatalf("expected address ledger-1:50052, got %s", endpoint.address)
	}
}

func TestSelectGatewayEndpointPrefersNetworkAndOperation(t *testing.T) {
	gateways := []discovery.GatewaySummary{
		{
			ID:              "high-priority-no-op",
			Rail:            "CRYPTO",
			Network:         "TRON_NILE",
			Healthy:         true,
			InvokeURI:       "gw-high:50053",
			RoutingPriority: 10,
		},
		{
			ID:              "low-priority-with-op",
			Rail:            "CRYPTO",
			Network:         "TRON_NILE",
			Healthy:         true,
			InvokeURI:       "gw-low:50053",
			Ops:             []string{"balance.read"},
			RoutingPriority: 1,
		},
		{
			ID:              "different-network",
			Rail:            "CRYPTO",
			Network:         "ARBITRUM_ONE",
			Healthy:         true,
			InvokeURI:       "gw-other:50053",
			Ops:             []string{"balance.read"},
			RoutingPriority: 100,
		},
	}

	endpoint, selected, ok := selectGatewayEndpoint(gateways, "TRON_NILE", []string{"balance.read"})
	if !ok {
		t.Fatal("expected gateway endpoint to be selected")
	}
	if selected.ID != "low-priority-with-op" {
		t.Fatalf("expected low-priority-with-op, got %s", selected.ID)
	}
	if endpoint.address != "gw-low:50053" {
		t.Fatalf("expected address gw-low:50053, got %s", endpoint.address)
	}
}
