#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function __assignType(fn, args) {
    fn.__type = args;
    return fn;
}
const child_process_1 = require("child_process");
const fs_1 = require("fs");
const path_1 = require("path");
const args = process.argv.slice(2);
function printUsage() {
    console.log(`
Usage: dksf-gen-proto <proto-file-or-dir> <output-dir> [options]

Generates TypeScript types from Protocol Buffer definitions using ts-proto.

Arguments:
  <proto-file-or-dir>  Path to a .proto file or directory containing .proto files
  <output-dir>         Directory where generated files will be written

Options:
  --only-types         Only generate type definitions (no encode/decode)
  --use-date           Use Date for google.protobuf.Timestamp (default: string)
  --use-map-type       Use ES6 Map for proto maps (default: plain object)

  -h, --help           Show this help message

Examples:
  dksf-gen-proto ./proto/service.proto ./src/generated
  dksf-gen-proto ./proto ./src/generated/proto
  dksf-gen-proto ./resources/proto/my-service.proto ./src/types
`);
}
printUsage.__type = ['printUsage', 'P"/!'];
if (args.includes('-h') || args.includes('--help') || args.length < 2) {
    printUsage();
    process.exit(args.length < 2 ? 1 : 0);
}
const inputPath = (0, path_1.resolve)(args[0]);
const outputDir = (0, path_1.resolve)(args[1]);
// Parse options
const onlyTypes = args.includes('--only-types');
const useDate = args.includes('--use-date');
const useMapType = args.includes('--use-map-type');
// Validate input path exists
if (!(0, fs_1.existsSync)(inputPath)) {
    console.error(`Error: Input path does not exist: ${inputPath}`);
    process.exit(1);
}
// Collect proto files
const protoFiles = [];
let protoDir;
const stat = (0, fs_1.statSync)(inputPath);
if (stat.isFile()) {
    if (!inputPath.endsWith('.proto')) {
        console.error(`Error: Input file must be a .proto file: ${inputPath}`);
        process.exit(1);
    }
    protoFiles.push(inputPath);
    protoDir = (0, path_1.dirname)(inputPath);
}
else if (stat.isDirectory()) {
    const files = (0, fs_1.readdirSync)(inputPath);
    for (const file of files) {
        if (file.endsWith('.proto')) {
            protoFiles.push((0, path_1.join)(inputPath, file));
        }
    }
    if (protoFiles.length === 0) {
        console.log('No .proto files found in directory, nothing to generate.');
        process.exit(0);
    }
    protoDir = inputPath;
}
else {
    console.error(`Error: Input path is neither a file nor directory: ${inputPath}`);
    process.exit(1);
}
// Create output directory if it doesn't exist
if (!(0, fs_1.existsSync)(outputDir)) {
    (0, fs_1.mkdirSync)(outputDir, { recursive: true });
}
// Find ts-proto plugin
function findTsProtoPlugin() {
    // Use require.resolve to find ts-proto, which works with workspaces and hoisting
    try {
        const tsProtoPath = require.resolve('ts-proto/package.json');
        const tsProtoDir = (0, path_1.dirname)(tsProtoPath);
        const pluginPath = (0, path_1.join)(tsProtoDir, 'protoc-gen-ts_proto');
        if ((0, fs_1.existsSync)(pluginPath)) {
            return pluginPath;
        }
    }
    catch {
        // Fall through to error
    }
    console.error(`Error: ts-proto not found. Install it with:
  npm install --save-dev ts-proto
  # or
  yarn add -D ts-proto`);
    process.exit(1);
}
findTsProtoPlugin.__type = ['findTsProtoPlugin', 'P&/!'];
const tsProtoPlugin = findTsProtoPlugin();
// Build ts-proto options
const tsProtoOpts = [];
if (onlyTypes) {
    tsProtoOpts.push('onlyTypes=true');
}
// Use string for timestamps by default (cleaner for JSON APIs)
if (!useDate) {
    tsProtoOpts.push('useDate=false');
}
// Use plain objects for maps by default
if (!useMapType) {
    tsProtoOpts.push('useMapType=false');
}
// Additional sensible defaults
tsProtoOpts.push('esModuleInterop=true');
tsProtoOpts.push('outputServices=false');
const tsProtoOptString = tsProtoOpts.join(',');
console.log(`Generating TypeScript types from ${protoFiles.length} proto file(s)...`);
// Build protoc command
const protocArgs = [
    `--plugin=protoc-gen-ts_proto="${tsProtoPlugin}"`,
    `--ts_proto_out="${outputDir}"`,
    `--ts_proto_opt=${tsProtoOptString}`,
    `-I"${protoDir}"`,
    ...protoFiles.map(__assignType(f => `"${f}"`, ['f', '', 'P"2!"/"']))
];
const protocCmd = `npx protoc ${protocArgs.join(' ')}`;
try {
    (0, child_process_1.execSync)(protocCmd, {
        stdio: 'inherit',
        cwd: process.cwd()
    });
}
catch {
    console.error('Error running protoc with ts-proto');
    process.exit(1);
}
// Get the base name for the output message
const baseName = stat.isFile() ? (0, path_1.basename)(inputPath, '.proto') : 'proto';
console.log(`
TypeScript types generated successfully!

Output directory: ${outputDir}

Usage with SrpcServer:
  import { ClientMessage, ServerMessage } from '${outputDir.replace(process.cwd(), '.')}/${baseName}';

  const server = new SrpcServer<SrpcMeta, ClientMessage, ServerMessage>({
      // ...
  });

Usage with SrpcClient:
  import { ClientMessage, ServerMessage } from '${outputDir.replace(process.cwd(), '.')}/${baseName}';

  const client = new SrpcClient<ClientMessage, ServerMessage>(
      // ...
  );
`);
//# sourceMappingURL=dksf-gen-proto.js.map