import { createHash } from 'node:crypto';
import fs from 'node:fs/promises';
import path from 'node:path';

function getProjectDataDir(...segments) {
  return path.resolve(process.cwd(), "data", ...segments);
}
const LATENCY_ROOT_SEGMENTS = ["data", "latency"];
const RECORDING_FILE_NAME = "recording.wav";
const METADATA_FILE_NAME = "metadata.json";
function normalizeSourceId(sourceId) {
  const trimmed = String(sourceId ?? "").trim();
  return trimmed || "default";
}
function makeSafePathSegment(raw, fallback) {
  const trimmed = String(raw ?? "").trim();
  const value = trimmed || fallback;
  const slug = value.slice(0, 80).replace(/[^a-zA-Z0-9._-]+/g, "_").replace(/^_+|_+$/g, "") || fallback;
  const hash = createHash("sha1").update(value).digest("hex").slice(0, 12);
  return `${slug}-${hash}`;
}
async function resolveConversationDir(conversationId, sourceId) {
  const normalizedSourceId = normalizeSourceId(sourceId);
  return getProjectDataDir(
    ...LATENCY_ROOT_SEGMENTS.slice(1),
    makeSafePathSegment(normalizedSourceId, "source"),
    makeSafePathSegment(conversationId, "conversation")
  );
}
async function readMetadataFile(filePath) {
  try {
    const raw = await fs.readFile(filePath, "utf-8");
    const parsed = JSON.parse(raw);
    if (typeof parsed?.conversationId !== "string" || typeof parsed?.sourceId !== "string" || typeof parsed?.fileName !== "string" || typeof parsed?.mimeType !== "string" || typeof parsed?.size !== "number" || typeof parsed?.uploadedAt !== "string" || typeof parsed?.alignmentOffsetMs !== "number") {
      return null;
    }
    return parsed;
  } catch (error) {
    if (error.code === "ENOENT") return null;
    console.error("Failed to read latency recording metadata:", filePath, error);
    return null;
  }
}
async function writeMetadataFile(filePath, metadata) {
  await fs.mkdir(path.dirname(filePath), { recursive: true });
  await fs.writeFile(filePath, JSON.stringify(metadata, null, 2), "utf-8");
}
function isWavBytes(bytes) {
  if (!(bytes instanceof Uint8Array) || bytes.byteLength < 12) return false;
  const riff = bytes[0] === 82 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 70;
  const wave = bytes[8] === 87 && bytes[9] === 65 && bytes[10] === 86 && bytes[11] === 69;
  return riff && wave;
}
async function getLatencyRecording(conversationId, sourceId) {
  const normalizedSourceId = normalizeSourceId(sourceId);
  const dirPath = await resolveConversationDir(conversationId, normalizedSourceId);
  const audioPath = path.join(dirPath, RECORDING_FILE_NAME);
  const metadataPath = path.join(dirPath, METADATA_FILE_NAME);
  const [metadata, audioStat] = await Promise.all([
    readMetadataFile(metadataPath),
    fs.stat(audioPath).catch((error) => {
      if (error.code === "ENOENT") return null;
      throw error;
    })
  ]);
  if (!metadata || !audioStat?.isFile()) return null;
  return {
    ...metadata,
    audioPath,
    size: Number.isFinite(metadata.size) && metadata.size > 0 ? metadata.size : audioStat.size
  };
}
async function saveLatencyRecording(input) {
  const normalizedSourceId = normalizeSourceId(input.sourceId);
  const dirPath = await resolveConversationDir(input.conversationId, normalizedSourceId);
  const audioPath = path.join(dirPath, RECORDING_FILE_NAME);
  const metadataPath = path.join(dirPath, METADATA_FILE_NAME);
  await fs.mkdir(dirPath, { recursive: true });
  await fs.writeFile(audioPath, input.bytes);
  const metadata = {
    conversationId: input.conversationId,
    sourceId: normalizedSourceId,
    fileName: input.fileName.trim() || RECORDING_FILE_NAME,
    mimeType: input.mimeType.trim() || "audio/wav",
    size: input.bytes.byteLength,
    uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
    alignmentOffsetMs: 0
  };
  await writeMetadataFile(metadataPath, metadata);
  return {
    ...metadata,
    audioPath
  };
}
async function updateLatencyRecordingAlignment(input) {
  const existing = await getLatencyRecording(input.conversationId, input.sourceId);
  if (!existing) return null;
  const dirPath = await resolveConversationDir(input.conversationId, existing.sourceId);
  const metadataPath = path.join(dirPath, METADATA_FILE_NAME);
  const metadata = {
    conversationId: existing.conversationId,
    sourceId: existing.sourceId,
    fileName: existing.fileName,
    mimeType: existing.mimeType,
    size: existing.size,
    uploadedAt: existing.uploadedAt,
    alignmentOffsetMs: input.alignmentOffsetMs
  };
  await writeMetadataFile(metadataPath, metadata);
  return {
    ...metadata,
    audioPath: existing.audioPath
  };
}

export { getLatencyRecording as g, isWavBytes as i, saveLatencyRecording as s, updateLatencyRecordingAlignment as u };
//# sourceMappingURL=latency-recordings-CqioXMQl.js.map
