import path from "node:path";
import { readdir, stat } from "node:fs/promises";
import { createId, ensureDir, nowIso, readJsonFile, sanitizeText, withFileLock, writeBufferFile, writeJsonFile, writeTextFile } from "../../shared/index.js";
import { runDir } from "../run-state/store.js";
export const SEED_ARTIFACT_INDEX_SCHEMA_VERSION = 1;
export async function writeArtifact(store, runId, input) {
    const safeName = (input.name ?? createId("artifact")).replace(/[^a-zA-Z0-9_.-]/g, "_");
    const file = path.join(runDir(store, runId), "artifacts", `${safeName}${input.extension ?? ""}`);
    await writeTextFile(file, sanitizeText(input.content));
    await upsertArtifactIndexRecord(store, runId, file, safeName, input.extension ?? "");
    return file;
}
export async function writeBinaryArtifact(store, runId, input) {
    const safeName = (input.name ?? createId("artifact")).replace(/[^a-zA-Z0-9_.-]/g, "_");
    const file = path.join(runDir(store, runId), "artifacts", `${safeName}${input.extension ?? ""}`);
    await writeBinaryFile(file, input.content);
    await upsertArtifactIndexRecord(store, runId, file, safeName, input.extension ?? "");
    return file;
}
export async function indexArtifactFile(store, runId, input) {
    const name = (input.name ?? path.basename(input.file).replace(/\.[^.]+$/, "")).replace(/[^a-zA-Z0-9_.-]/g, "_");
    await upsertArtifactIndexRecord(store, runId, input.file, name, input.extension ?? path.extname(input.file));
}
export async function readArtifactIndex(store, runId) {
    const file = artifactIndexPath(store, runId);
    const raw = await readJsonFile(file);
    const index = raw ? normalizeArtifactIndex(raw) : await indexLegacyArtifacts(store, runId);
    if (JSON.stringify(raw) !== JSON.stringify(index))
        await writeJsonFile(file, index);
    return index;
}
function artifactRoot(store, runId) {
    return path.join(runDir(store, runId), "artifacts");
}
function artifactIndexPath(store, runId) {
    return path.join(artifactRoot(store, runId), "index.json");
}
async function upsertArtifactIndexRecord(store, runId, file, name, extension) {
    const indexFile = artifactIndexPath(store, runId);
    await ensureDir(path.dirname(indexFile));
    await withFileLock(indexFile, async () => {
        const index = await readArtifactIndex(store, runId);
        const timestamp = nowIso();
        const fileStat = await stat(file);
        const relativePath = path.relative(runDir(store, runId), file).split(path.sep).join("/");
        const existing = index.artifacts.find((artifact) => artifact.path === relativePath);
        const record = {
            schema_version: SEED_ARTIFACT_INDEX_SCHEMA_VERSION,
            artifact_id: existing?.artifact_id ?? createId("artifact"),
            name,
            path: relativePath,
            extension,
            size_bytes: fileStat.size,
            created_at: existing?.created_at ?? timestamp,
            updated_at: timestamp,
        };
        const artifacts = existing
            ? index.artifacts.map((artifact) => (artifact.path === relativePath ? record : artifact))
            : [...index.artifacts, record];
        await writeJsonFile(indexFile, {
            schema_version: SEED_ARTIFACT_INDEX_SCHEMA_VERSION,
            updated_at: timestamp,
            artifacts: artifacts.sort((left, right) => left.path.localeCompare(right.path)),
        });
    });
}
async function indexLegacyArtifacts(store, runId) {
    const root = artifactRoot(store, runId);
    const timestamp = nowIso();
    const artifacts = [];
    for (const name of await readDirIfExists(root)) {
        if (name === "index.json")
            continue;
        const file = path.join(root, name);
        const fileStat = await stat(file);
        if (!fileStat.isFile())
            continue;
        artifacts.push({
            schema_version: SEED_ARTIFACT_INDEX_SCHEMA_VERSION,
            artifact_id: createId("artifact"),
            name: name.replace(/\.[^.]+$/, ""),
            path: path.relative(runDir(store, runId), file).split(path.sep).join("/"),
            extension: path.extname(name),
            size_bytes: fileStat.size,
            created_at: timestamp,
            updated_at: timestamp,
        });
    }
    return {
        schema_version: SEED_ARTIFACT_INDEX_SCHEMA_VERSION,
        updated_at: timestamp,
        artifacts: artifacts.sort((left, right) => left.path.localeCompare(right.path)),
    };
}
function normalizeArtifactIndex(raw) {
    const timestamp = nowIso();
    return {
        schema_version: SEED_ARTIFACT_INDEX_SCHEMA_VERSION,
        updated_at: typeof raw.updated_at === "string" ? raw.updated_at : timestamp,
        artifacts: Array.isArray(raw.artifacts)
            ? raw.artifacts.map((artifact) => normalizeArtifactRecord(artifact)).sort((left, right) => left.path.localeCompare(right.path))
            : [],
    };
}
function normalizeArtifactRecord(raw) {
    const timestamp = nowIso();
    const artifactPath = typeof raw.path === "string" ? raw.path : "";
    return {
        schema_version: SEED_ARTIFACT_INDEX_SCHEMA_VERSION,
        artifact_id: typeof raw.artifact_id === "string" ? raw.artifact_id : createId("artifact"),
        name: typeof raw.name === "string" ? raw.name : path.basename(artifactPath).replace(/\.[^.]+$/, ""),
        path: artifactPath,
        extension: typeof raw.extension === "string" ? raw.extension : path.extname(artifactPath),
        size_bytes: typeof raw.size_bytes === "number" && Number.isFinite(raw.size_bytes) ? raw.size_bytes : 0,
        created_at: typeof raw.created_at === "string" ? raw.created_at : timestamp,
        updated_at: typeof raw.updated_at === "string" ? raw.updated_at : timestamp,
    };
}
async function readDirIfExists(dir) {
    try {
        return await readdir(dir);
    }
    catch (error) {
        if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")
            return [];
        throw error;
    }
}
async function writeBinaryFile(file, value) {
    await writeBufferFile(file, value);
}
//# sourceMappingURL=store.js.map