// tools/generate-tests/generators/grpc-test-generator.ts — SPEC-058a Section D
// Generates gRPC test scaffolds: proto contracts, unary, streaming, deadlines.
const GRPC_SIGNALS = ['grpc', '@grpc/grpc-js', 'protobuf', 'buf', 'proto-loader', 'grpc-web'];
/**
 * Returns true when the project uses gRPC / Protocol Buffers.
 */
export function isGrpcProject(knowledge) {
    const stackLower = knowledge.stack.map((s) => s.toLowerCase());
    const hasStackSignal = GRPC_SIGNALS.some((sig) => stackLower.some((s) => s.includes(sig)));
    const toolingValues = Object.values(knowledge.tooling).map((v) => v.toLowerCase());
    const hasProtoFile = toolingValues.some((v) => v.includes('.proto') || v.includes('protobuf'));
    return hasStackSignal || hasProtoFile;
}
/**
 * Generate gRPC test definitions: proto contracts, unary, streaming, deadlines.
 */
export function generateGrpcTestDefs(title, testDir, _testExt) {
    return [
        {
            name: `${title} — gRPC: proto contract validation`,
            type: 'integration',
            file: `${testDir}/grpc/`,
            description: 'Verify the .proto definition compiles and all service methods are reachable',
            priority: 'critical',
            automatable: true,
        },
        {
            name: `${title} — gRPC: unary call returns correct response`,
            type: 'integration',
            file: `${testDir}/grpc/`,
            description: 'Execute a unary RPC and assert the response message matches the proto schema',
            priority: 'high',
            automatable: true,
        },
        {
            name: `${title} — gRPC: server streaming yields all expected messages`,
            type: 'integration',
            file: `${testDir}/grpc/`,
            description: 'Consume a server-streaming RPC and verify each streamed message',
            priority: 'high',
            automatable: true,
        },
        {
            name: `${title} — gRPC: client streaming aggregates messages correctly`,
            type: 'integration',
            file: `${testDir}/grpc/`,
            description: 'Send multiple messages via client-streaming RPC and verify aggregated response',
            priority: 'medium',
            automatable: true,
        },
        {
            name: `${title} — gRPC: bidirectional streaming echoes messages in order`,
            type: 'integration',
            file: `${testDir}/grpc/`,
            description: 'Open a bidirectional stream and verify messages are echoed in FIFO order',
            priority: 'medium',
            automatable: true,
        },
        {
            name: `${title} — gRPC: deadline propagation cancels slow calls`,
            type: 'integration',
            file: `${testDir}/grpc/`,
            description: 'Set a short deadline on a slow call and assert DEADLINE_EXCEEDED status code',
            priority: 'high',
            automatable: true,
        },
    ];
}
// ---------------------------------------------------------------------------
// Content generators
// ---------------------------------------------------------------------------
function buildTsGrpcTest(title) {
    return `// gRPC tests for: ${title}
// Generated by Planu SDD MCP Server (SPEC-058a)
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
// import * as grpc from '@grpc/grpc-js';
// import * as protoLoader from '@grpc/proto-loader';

// const PROTO_PATH = './proto/service.proto';
// const packageDefinition = protoLoader.loadSync(PROTO_PATH);
// const proto = grpc.loadPackageDefinition(packageDefinition) as grpc.GrpcObject;

describe('${title} — gRPC Tests', () => {
  // let client: grpc.ServiceClient;

  beforeAll(() => {
    // const ServiceClient = proto['YourService'] as grpc.ServiceClientConstructor;
    // client = new ServiceClient(
    //   'localhost:50051',
    //   grpc.credentials.createInsecure(),
    // );
  });

  afterAll(() => {
    // client.close();
  });

  describe('Proto contract', () => {
    it('service definition loads without errors', () => {
      // const packageDef = protoLoader.loadSync(PROTO_PATH);
      // expect(packageDef).toBeDefined();
      expect(true).toBe(true); // Replace with real proto load assertion
    });
  });

  describe('Unary call', () => {
    it('returns correct response message', async () => {
      // const response = await new Promise((resolve, reject) =>
      //   client.unaryMethod({ id: '1' }, (err, res) =>
      //     err ? reject(err) : resolve(res),
      //   ),
      // );
      // expect(response).toMatchObject({ id: '1' });
      expect(true).toBe(true); // Replace with real unary assertion
    });
  });

  describe('Server streaming', () => {
    it('yields all expected messages', async () => {
      // const messages: unknown[] = [];
      // await new Promise<void>((resolve, reject) => {
      //   const stream = client.serverStreamMethod({ count: 3 });
      //   stream.on('data', (msg) => messages.push(msg));
      //   stream.on('error', reject);
      //   stream.on('end', resolve);
      // });
      // expect(messages).toHaveLength(3);
      expect(true).toBe(true); // Replace with real server-stream assertion
    });
  });

  describe('Deadline propagation', () => {
    it('returns DEADLINE_EXCEEDED for slow calls', async () => {
      // const deadline = new Date(Date.now() + 1); // 1ms deadline
      // await expect(
      //   new Promise((resolve, reject) =>
      //     client.slowMethod({}, { deadline }, (err, res) =>
      //       err ? reject(err) : resolve(res),
      //     ),
      //   ),
      // ).rejects.toMatchObject({ code: grpc.status.DEADLINE_EXCEEDED });
      expect(true).toBe(true); // Replace with real deadline assertion
    });
  });
});
`;
}
function buildGoGrpcTest(title) {
    const pkg = title.toLowerCase().replace(/\s+/g, '_');
    return `// gRPC tests for: ${title}
// Generated by Planu SDD MCP Server (SPEC-058a)
package ${pkg}_test

import (
\t"context"
\t"testing"
\t"time"

\t"google.golang.org/grpc"
\t"google.golang.org/grpc/codes"
\t"google.golang.org/grpc/credentials/insecure"
\t"google.golang.org/grpc/status"
\t// pb "your/module/proto/gen"
)

func setupClient(t *testing.T) (*grpc.ClientConn, func()) {
\tt.Helper()
\tconn, err := grpc.NewClient(
\t\t"localhost:50051",
\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),
\t)
\tif err != nil {
\t\tt.Fatalf("failed to connect: %v", err)
\t}
\treturn conn, func() { conn.Close() } //nolint:errcheck
}

func TestUnaryCall(t *testing.T) {
\t// conn, teardown := setupClient(t)
\t// defer teardown()
\t// client := pb.NewYourServiceClient(conn)
\t//
\t// ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
\t// defer cancel()
\t//
\t// resp, err := client.UnaryMethod(ctx, &pb.Request{Id: "1"})
\t// if err != nil { t.Fatalf("unary call failed: %v", err) }
\t// if resp.Id != "1" { t.Errorf("expected id=1, got %s", resp.Id) }
\tt.Skip("TODO: implement unary call test")
}

func TestDeadlinePropagation(t *testing.T) {
\t// conn, teardown := setupClient(t)
\t// defer teardown()
\t// client := pb.NewYourServiceClient(conn)
\t//
\tctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
\tdefer cancel()
\t_ = ctx
\t//
\t// _, err := client.SlowMethod(ctx, &pb.Request{})
\t// if status.Code(err) != codes.DeadlineExceeded {
\t//     t.Errorf("expected DeadlineExceeded, got %v", status.Code(err))
\t// }
\t_ = codes.DeadlineExceeded
\t_ = status.Code
\tt.Skip("TODO: implement deadline propagation test")
}
`;
}
function buildPythonGrpcTest(title) {
    const cls = title.replace(/\s+/g, '');
    return `"""gRPC tests for: ${title}
Generated by Planu SDD MCP Server (SPEC-058a).
Uses grpcio + grpcio-testing patterns.
"""
import pytest
# import grpc
# from your.proto import service_pb2, service_pb2_grpc


class Test${cls}Grpc:
    """gRPC test suite for ${title}."""

    def test_proto_contract_loads(self) -> None:
        """Proto definition loads without import errors."""
        # TODO: from your.proto import service_pb2_grpc
        pass

    def test_unary_call_returns_correct_response(self) -> None:
        """Unary RPC returns the expected response message."""
        # TODO: channel = grpc.insecure_channel("localhost:50051")
        # stub = service_pb2_grpc.YourServiceStub(channel)
        # response = stub.UnaryMethod(service_pb2.Request(id="1"))
        # assert response.id == "1"
        pass

    def test_server_streaming_yields_all_messages(self) -> None:
        """Server-streaming RPC yields all expected messages."""
        # TODO: messages = list(stub.ServerStreamMethod(service_pb2.Request(count=3)))
        # assert len(messages) == 3
        pass

    def test_deadline_exceeded_for_slow_call(self) -> None:
        """Call with a short deadline raises StatusCode.DEADLINE_EXCEEDED."""
        # TODO: with pytest.raises(grpc.RpcError) as exc_info:
        #     stub.SlowMethod(request, timeout=0.001)
        # assert exc_info.value.code() == grpc.StatusCode.DEADLINE_EXCEEDED
        pass
`;
}
/**
 * Generate gRPC test file scaffolds for the target language.
 */
export function generateGrpcTestFiles(spec, testDir, framework, language, testExt, autoGenerate) {
    let content;
    let resolvedExt;
    let resolvedFramework;
    if (language === 'go') {
        content = buildGoGrpcTest(spec.title);
        resolvedExt = 'go';
        resolvedFramework = 'go-test';
    }
    else if (language === 'python') {
        content = buildPythonGrpcTest(spec.title);
        resolvedExt = 'py';
        resolvedFramework = 'pytest';
    }
    else {
        content = buildTsGrpcTest(spec.title);
        resolvedExt = testExt;
        resolvedFramework = framework;
    }
    return [
        {
            path: `${testDir}/grpc/${spec.slug}.grpc.test.${resolvedExt}`,
            framework: resolvedFramework,
            content,
            ready: autoGenerate,
        },
    ];
}
//# sourceMappingURL=grpc-test-generator.js.map