/**
 * Studio Binding utilities.
 *
 * Read/write/delete `.aexol/aexol.jsonc` — the local file that links a
 * repository directory to an Aexol Studio project.
 */
import { access, mkdir, readFile, unlink, writeFile } from "node:fs/promises";
import { constants } from "node:fs";
import { join } from "node:path";
const BINDING_DIR = ".aexol";
const BINDING_FILE = "aexol.jsonc";
function bindingDir() {
    return join(process.cwd(), BINDING_DIR);
}
function bindingPath() {
    return join(bindingDir(), BINDING_FILE);
}
/**
 * Strip JSONC comments (// line and /* block *​/) from raw source text.
 * Kept simple — the binding file shape is well-known.
 */
export function stripJsoncComments(raw) {
    return raw
        .replace(/\/\*[\s\S]*?\*\//g, "") // block comments
        .replace(/^\s*\/\/.*$/gm, ""); // line comments (standalone lines only)
}
/**
 * Read and parse the local Studio binding file.
 * Returns `null` when no binding file exists (file missing, or directory
 * absent — treated the same way: not bound).
 */
export async function readStudioBinding() {
    try {
        const raw = await readFile(bindingPath(), "utf8");
        return JSON.parse(stripJsoncComments(raw));
    }
    catch (err) {
        const code = err.code;
        // Missing file or missing directory → not bound.
        if (code === "ENOENT" || code === "ENOTDIR")
            return null;
        throw err;
    }
}
/**
 * Read and parse the Studio binding file at an arbitrary project path.
 * Works like `readStudioBinding()` but reads from `projectPath/.aexol/aexol.jsonc`
 * instead of `process.cwd()`.
 */
export async function readStudioBindingAt(projectPath) {
    try {
        const raw = await readFile(join(projectPath, BINDING_DIR, BINDING_FILE), "utf8");
        return JSON.parse(stripJsoncComments(raw));
    }
    catch (err) {
        const code = err.code;
        // Missing file or missing directory → not bound.
        if (code === "ENOENT" || code === "ENOTDIR")
            return null;
        throw err;
    }
}
/**
 * Persist a Studio binding. Creates `.aexol/` if it does not exist.
 */
export async function writeStudioBinding(binding) {
    const dir = bindingDir();
    try {
        await access(dir, constants.F_OK);
    }
    catch {
        await mkdir(dir, { recursive: true });
    }
    const content = `// Aexol Studio Binding\n` +
        `// Links this repository to a Studio project.\n` +
        `// Schema: https://aexol.ai/schemas/studio-binding.json\n` +
        `\n` +
        JSON.stringify(binding, null, 2) +
        "\n";
    await writeFile(bindingPath(), content, "utf8");
}
/**
 * Persist a Studio binding at an arbitrary project path (creates `.aexol/`
 * under that directory). Uses the same format as `writeStudioBinding`.
 */
export async function writeStudioBindingAt(projectPath, binding) {
    const dir = join(projectPath, BINDING_DIR);
    try {
        await access(dir, constants.F_OK);
    }
    catch {
        await mkdir(dir, { recursive: true });
    }
    const content = `// Aexol Studio Binding\n` +
        `// Links this repository to a Studio project.\n` +
        `// Schema: https://aexol.ai/schemas/studio-binding.json\n` +
        `\n` +
        JSON.stringify(binding, null, 2) +
        "\n";
    await writeFile(join(dir, BINDING_FILE), content, "utf8");
}
/**
 * Remove the local Studio binding file.
 * Returns `true` when the file existed and was deleted, `false` otherwise (no-op).
 */
export async function deleteStudioBinding() {
    try {
        await unlink(bindingPath());
        return true;
    }
    catch (err) {
        const code = err.code;
        if (code === "ENOENT")
            return false;
        throw err;
    }
}
