import path from "node:path";
import fs from "node:fs";
import type { Database as DBType } from "better-sqlite3";

interface ScanStats {
  contracts: number;
}

// Proto 符号正则
const PROTO_SERVICE_RE = /^service\s+(\w+)\s*\{/gm;
const PROTO_MESSAGE_RE = /^message\s+(\w+)\s*\{/gm;
const PROTO_RPC_RE = /^\s*rpc\s+(\w+)\s*\(/gm;

export function scanProtobuf(db: DBType, root: string): ScanStats {
  const insertContract = db.prepare(
    "INSERT OR IGNORE INTO contracts (name, type, file_path, service, content) VALUES (?, ?, ?, ?, ?)",
  );

  let contracts = 0;

  // 扫描 packages/shared-proto/proto/*.proto
  const protoDir = path.join(root, "packages", "shared-proto", "proto");
  if (!fs.existsSync(protoDir)) return { contracts };

  const entries = fs.readdirSync(protoDir, { withFileTypes: true });
  for (const entry of entries) {
    if (!entry.isFile() || !entry.name.endsWith(".proto")) continue;
    const filePath = path.join(protoDir, entry.name);
    const protoName = path.basename(entry.name, ".proto");
    const serviceName = protoName.replace("_", "-");

    let content: string;
    try {
      content = fs.readFileSync(filePath, "utf-8");
    } catch {
      continue;
    }

    // 提取 package 名
    const pkgMatch = content.match(/^package\s+(\S+);/m);
    const pkgName = pkgMatch ? pkgMatch[1] : "";

    // 记录 proto 文件作为契约
    insertContract.run(protoName, "proto-file", filePath, serviceName, pkgName);
    contracts++;

    // 提取 service 定义
    let match: RegExpExecArray | null;
    const serviceRe = new RegExp(PROTO_SERVICE_RE);
    while ((match = serviceRe.exec(content)) !== null) {
      const name = match[1];
      insertContract.run(
        `${protoName}.${name}`,
        "service",
        filePath,
        serviceName,
        name,
      );
      contracts++;
    }

    // 提取 message 定义
    const messageRe = new RegExp(PROTO_MESSAGE_RE);
    while ((match = messageRe.exec(content)) !== null) {
      const name = match[1];
      insertContract.run(
        `${protoName}.${name}`,
        "message",
        filePath,
        serviceName,
        name,
      );
      contracts++;
    }

    // 提取 rpc 方法
    const rpcRe = new RegExp(PROTO_RPC_RE);
    while ((match = rpcRe.exec(content)) !== null) {
      const name = match[1];
      insertContract.run(
        `${protoName}.rpc.${name}`,
        "rpc",
        filePath,
        serviceName,
        name,
      );
      contracts++;
    }
  }

  return { contracts };
}
