import { randomBytes } from 'node:crypto';
import { mkdir, open, readFile } from 'node:fs/promises';
import { dirname } from 'node:path';

export interface ExecutorRuntimeConfig {
  host: '127.0.0.1';
  port: number;
  token: string;
  tokenPath: string;
}

export async function loadOrCreateExecutorToken(path: string): Promise<string> {
  try {
    const existing = (await readFile(path, 'utf8')).trim();
    if (existing.length < 32) throw new Error(`Executor token at ${path} is too short.`);
    return existing;
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
  }

  await mkdir(dirname(path), { recursive: true, mode: 0o700 });
  const token = randomBytes(32).toString('base64url');
  const handle = await open(path, 'wx', 0o600);
  try {
    await handle.writeFile(`${token}\n`, 'utf8');
  } finally {
    await handle.close();
  }
  return token;
}

export async function loadExecutorRuntimeConfig(): Promise<ExecutorRuntimeConfig> {
  const home = process.env.HOME ?? '.';
  const tokenPath = process.env.CHATGPT_ORCHESTRATOR_EXECUTOR_TOKEN_FILE
    ?? `${home}/.config/chatgpt-orchestrator/executor-token`;
  const port = Number.parseInt(process.env.CHATGPT_ORCHESTRATOR_EXECUTOR_PORT ?? '8765', 10);
  if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error('CHATGPT_ORCHESTRATOR_EXECUTOR_PORT must be a TCP port.');
  return { host: '127.0.0.1', port, token: await loadOrCreateExecutorToken(tokenPath), tokenPath };
}
