const path = require('path');
const protoLoader = require('@grpc/proto-loader');
const grpc = require('@grpc/grpc-js');
const fs = require('fs');

/**
 * gRPC proto 로딩 결과를 캐싱하기 위한 변수
 */
let _cache = null;

const findProtoPath = () => {
  const attemptedPaths = [];

  // 1. Try explicit environment variable
  if (process.env.KORD_PROTO_PATH) {
    if (fs.existsSync(process.env.KORD_PROTO_PATH)) return process.env.KORD_PROTO_PATH;
    attemptedPaths.push(`Env: ${process.env.KORD_PROTO_PATH}`);
  }

  // 2. Try standard __dirname (most reliable for direct node/tsx runs)
  const dirnamePath = path.resolve(__dirname, 'kord.proto');
  if (fs.existsSync(dirnamePath)) return dirnamePath;
  attemptedPaths.push(`Dirname: ${dirnamePath}`);

  // 3. Try monorepo root via process.cwd()
  const rootPath = path.resolve(process.cwd(), 'packages/grpc-contracts/src/kord.proto');
  if (fs.existsSync(rootPath)) return rootPath;
  attemptedPaths.push(`CWD Root: ${rootPath}`);

  // 4. Try relative from apps/ (Next.js context)
  const relativePath = path.resolve(process.cwd(), '../../packages/grpc-contracts/src/kord.proto');
  if (fs.existsSync(relativePath)) return relativePath;
  attemptedPaths.push(`Relative: ${relativePath}`);

  // 5. Try shared node_modules depth (monorepo artifacts)
  const nmPath = path.resolve(process.cwd(), 'node_modules/@kord/grpc-contracts/src/kord.proto');
  if (fs.existsSync(nmPath)) return nmPath;
  attemptedPaths.push(`NodeModules: ${nmPath}`);

  return { error: true, attemptedPaths };
};

const initialize = () => {
  if (_cache) return _cache;

  // browser환경이나 분석 단계에서 fs가 없을 경우를 대비하여 체크 (Turbopack 대응)
  if (!fs || !fs.existsSync) {
    return { kordProto: null, protoPath: null };
  }

  const result = findProtoPath();
  if (result.error) {
    // 런타임에 에러가 발생하도록 경고를 출력하되, 빌드/분석 단계에서는 치명적 에러가 되지 않도록 함
    console.warn('⚠️ [grpc-contracts] Failed to locate kord.proto during initialization.');
    return { kordProto: null, protoPath: null };
  }

  const PROTO_PATH = result;
  let packageDefinition;
  try {
    packageDefinition = protoLoader.loadSync(PROTO_PATH, {
      keepCase: true,
      longs: String,
      enums: String,
      defaults: true,
      oneofs: true,
    });
  } catch (error) {
    console.error(`Failed to load gRPC proto from: ${PROTO_PATH}`);
    throw error;
  }

  const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
  
  _cache = {
    kordProto: protoDescriptor.kord,
    protoPath: PROTO_PATH
  };

  return _cache;
};

module.exports = {
  // getter를 사용하여 실제 접근 시점에 로딩되도록 함 (Lazy Initialization)
  get kordProto() {
    return initialize().kordProto;
  },
  get protoPath() {
    return initialize().protoPath;
  }
};

