package grpcapi

import (
	"context"
	"crypto/sha256"
	"testing"

	"galaxy/gateway/internal/session"

	"connectrpc.com/connect"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestExecuteCommandRejectsPayloadHashWithInvalidLength(t *testing.T) {
	t.Parallel()

	delegate := &recordingEdgeGatewayService{}
	server, runGateway := newTestGateway(t, ServerDependencies{
		Service:      delegate,
		SessionCache: staticSessionCache{lookupFunc: func(context.Context, string) (session.Record, error) { return newActiveSessionRecord(), nil }},
	})
	defer runGateway.stop(t)

	addr := waitForListenAddr(t, server)
	client := newEdgeClient(t, addr)

	req := newValidExecuteCommandRequest()
	req.PayloadHash = []byte("short")

	_, err := client.ExecuteCommand(context.Background(), connect.NewRequest(req))
	require.Error(t, err)
	assert.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err))
	assert.Equal(t, "payload_hash must be a 32-byte SHA-256 digest", connectErrorMessage(t, err))
	assert.Zero(t, delegate.executeCalls)
}

func TestExecuteCommandRejectsPayloadHashMismatch(t *testing.T) {
	t.Parallel()

	delegate := &recordingEdgeGatewayService{}
	server, runGateway := newTestGateway(t, ServerDependencies{
		Service:      delegate,
		SessionCache: staticSessionCache{lookupFunc: func(context.Context, string) (session.Record, error) { return newActiveSessionRecord(), nil }},
	})
	defer runGateway.stop(t)

	addr := waitForListenAddr(t, server)
	client := newEdgeClient(t, addr)

	req := newValidExecuteCommandRequest()
	sum := sha256.Sum256([]byte("other"))
	req.PayloadHash = sum[:]

	_, err := client.ExecuteCommand(context.Background(), connect.NewRequest(req))
	require.Error(t, err)
	assert.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err))
	assert.Equal(t, "payload_hash does not match payload_bytes", connectErrorMessage(t, err))
	assert.Zero(t, delegate.executeCalls)
}

func TestSubscribeEventsRejectsPayloadHashWithInvalidLength(t *testing.T) {
	t.Parallel()

	delegate := &recordingEdgeGatewayService{}
	server, runGateway := newTestGateway(t, ServerDependencies{
		Service:      delegate,
		SessionCache: staticSessionCache{lookupFunc: func(context.Context, string) (session.Record, error) { return newActiveSessionRecord(), nil }},
	})
	defer runGateway.stop(t)

	addr := waitForListenAddr(t, server)
	client := newEdgeClient(t, addr)

	req := newValidSubscribeEventsRequest()
	req.PayloadHash = []byte("short")

	err := subscribeEventsError(t, context.Background(), client, req)
	require.Error(t, err)
	assert.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err))
	assert.Equal(t, "payload_hash must be a 32-byte SHA-256 digest", connectErrorMessage(t, err))
	assert.Zero(t, delegate.subscribeCalls)
}

func TestSubscribeEventsRejectsPayloadHashMismatch(t *testing.T) {
	t.Parallel()

	delegate := &recordingEdgeGatewayService{}
	server, runGateway := newTestGateway(t, ServerDependencies{
		Service:      delegate,
		SessionCache: staticSessionCache{lookupFunc: func(context.Context, string) (session.Record, error) { return newActiveSessionRecord(), nil }},
	})
	defer runGateway.stop(t)

	addr := waitForListenAddr(t, server)
	client := newEdgeClient(t, addr)

	req := newValidSubscribeEventsRequest()
	sum := sha256.Sum256([]byte("other"))
	req.PayloadHash = sum[:]

	err := subscribeEventsError(t, context.Background(), client, req)
	require.Error(t, err)
	assert.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err))
	assert.Equal(t, "payload_hash does not match payload_bytes", connectErrorMessage(t, err))
	assert.Zero(t, delegate.subscribeCalls)
}
