import { mkdir, readFile, writeFile } from 'node:fs/promises';
import { dirname, resolve } from 'node:path';

const root = resolve(import.meta.dirname, '..');
const protoRoot = resolve(root, '../../shared/proto');
const outputFile = resolve(root, 'src/generated/proto/contracts.ts');

const scalarMap = {
  string: 'string',
  bool: 'boolean',
  int32: 'number',
  int64: 'number',
  uint32: 'number',
  uint64: 'number',
  double: 'number',
  float: 'number'
};

function toTsType(type, namespace) {
  return scalarMap[type] ?? `${namespace}${type}`;
}

function parseMessages(proto, namespace) {
  const messages = [];
  const messageRegex = /message\s+(\w+)\s*\{([\s\S]*?)\}/g;
  let match;

  while ((match = messageRegex.exec(proto))) {
    const [, name, body] = match;
    const fields = [];
    for (const line of body.split('\n')) {
      const trimmed = line.trim();
      if (!trimmed || trimmed.startsWith('//')) continue;
      const fieldMatch = /^(optional\s+)?(repeated\s+)?(\w+)\s+(\w+)\s*=\s*\d+;/.exec(trimmed);
      if (!fieldMatch) continue;
      const [, optional, repeated, type, fieldName] = fieldMatch;
      const tsType = repeated ? `${toTsType(type, namespace)}[]` : toTsType(type, namespace);
      fields.push(`  ${fieldName}${optional ? '?' : ''}: ${tsType};`);
    }
    messages.push(`export interface ${namespace}${name} {\n${fields.join('\n')}\n}`);
  }

  return messages;
}

function parseServices(proto, namespace) {
  const services = [];
  const serviceRegex = /service\s+(\w+)\s*\{([\s\S]*?)\}/g;
  let match;

  while ((match = serviceRegex.exec(proto))) {
    const [, name, body] = match;
    const methods = [];
    for (const line of body.split('\n')) {
      const trimmed = line.trim();
      const methodMatch = /^rpc\s+(\w+)\s+\((\w+)\)\s+returns\s+\((\w+)\);/.exec(trimmed);
      if (!methodMatch) continue;
      const [, methodName, request, response] = methodMatch;
      methods.push(`  ${methodName}(request: ${namespace}${request}): Promise<${namespace}${response}>;`);
    }
    services.push(`export interface ${namespace}${name}Client {\n${methods.join('\n')}\n}`);
  }

  return services;
}

const outputs = [
  '/* eslint-disable */',
  '// Сгенерировано из shared/proto. Не редактируйте вручную.',
  ''
];

for (const file of ['auth.proto', 'admin.proto', 'rbac.proto', 'security.proto', 'profile.proto', 'documents.proto', 'identity.proto']) {
  const proto = await readFile(resolve(protoRoot, file), 'utf8');
  const packageMatch = /package\s+(\w+);/.exec(proto);
  const namespace = packageMatch ? `${packageMatch[1][0].toUpperCase()}${packageMatch[1].slice(1)}` : '';
  outputs.push(...parseMessages(proto, namespace), ...parseServices(proto, namespace), '');
}

await mkdir(dirname(outputFile), { recursive: true });
await writeFile(outputFile, `${outputs.join('\n\n')}\n`, 'utf8');
