import { readFile, writeFile, mkdir } from "fs/promises";
import { existsSync } from "fs";
import * as path from "path";
import * as crypto from "crypto";
import hcl2JsonParser from "hcl2-json-parser";
const { parseToObject } = hcl2JsonParser;
export const SECRETS_FILE = "specific.secrets";
export const GENERATED_SECRETS_FILE = ".specific/generated-secrets.json";
/**
 * Parse a specific.secrets file and return a map of secret names to values.
 * Format: HCL key = "value" pairs
 */
export async function parseSecretsFile(content) {
    const secrets = new Map();
    if (!content.trim()) {
        return secrets;
    }
    const parsed = (await parseToObject(content));
    for (const [key, value] of Object.entries(parsed)) {
        if (typeof value === "string") {
            secrets.set(key, value);
        }
    }
    return secrets;
}
/**
 * Load secrets from specific.secrets file.
 * Returns an empty map if the file doesn't exist.
 */
export async function loadSecrets() {
    if (!existsSync(SECRETS_FILE)) {
        return new Map();
    }
    const content = await readFile(SECRETS_FILE, "utf-8");
    return await parseSecretsFile(content);
}
/**
 * Generate a random alphanumeric string.
 */
export function generateRandomString(length = 30) {
    const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    const bytes = crypto.randomBytes(length);
    let result = "";
    for (let i = 0; i < length; i++) {
        result += chars[bytes[i] % chars.length];
    }
    return result;
}
/**
 * Load generated secrets from .specific/generated-secrets.json.
 * Returns an empty map if the file doesn't exist.
 */
export async function loadGeneratedSecrets() {
    if (!existsSync(GENERATED_SECRETS_FILE)) {
        return new Map();
    }
    const content = await readFile(GENERATED_SECRETS_FILE, "utf-8");
    const parsed = JSON.parse(content);
    return new Map(Object.entries(parsed));
}
/**
 * Save a generated secret to .specific/generated-secrets.json.
 * Creates the file and directory if they don't exist.
 */
export async function saveGeneratedSecret(name, value) {
    // Load existing secrets
    let secrets = {};
    if (existsSync(GENERATED_SECRETS_FILE)) {
        const content = await readFile(GENERATED_SECRETS_FILE, "utf-8");
        secrets = JSON.parse(content);
    }
    // Add new secret
    secrets[name] = value;
    // Ensure .specific directory exists
    const dir = path.dirname(GENERATED_SECRETS_FILE);
    if (!existsSync(dir)) {
        await mkdir(dir, { recursive: true });
    }
    // Write back
    await writeFile(GENERATED_SECRETS_FILE, JSON.stringify(secrets, null, 2) + "\n");
}
/**
 * Prepare all secrets for use, handling generated secrets.
 * - Loads user secrets from specific.secrets
 * - For generated secrets not in user secrets, loads or creates from generated storage
 * - Returns merged secrets map ready for env resolution
 */
export async function prepareSecrets(secretsConfig) {
    // Load user-defined secrets
    const userSecrets = await loadSecrets();
    // Load previously generated secrets
    const generatedSecrets = await loadGeneratedSecrets();
    // Build final secrets map
    const finalSecrets = new Map();
    for (const secretDef of secretsConfig) {
        // Check user secrets first
        const userValue = userSecrets.get(secretDef.name);
        if (userValue !== undefined) {
            finalSecrets.set(secretDef.name, userValue);
            continue;
        }
        // For generated secrets, check or create generated value
        if (secretDef.generated) {
            let generatedValue = generatedSecrets.get(secretDef.name);
            if (generatedValue === undefined) {
                // Generate new value and persist it
                generatedValue = generateRandomString(30);
                await saveGeneratedSecret(secretDef.name, generatedValue);
            }
            finalSecrets.set(secretDef.name, generatedValue);
        }
        // Non-generated secrets without values will be handled by MissingSecretError in resolver
    }
    return finalSecrets;
}
//# sourceMappingURL=parser.js.map