import fs from "node:fs";
import path from "node:path";
import { logger } from "../logger.js";
import { createRealtimeBackend } from "./server.js";
import { getConfigDir } from "../config/index.js";
import { REALTIME_SIDECAR_SCHEMA_VERSION, REALTIME_SIDECAR_SOURCE } from "./types.js";
/** Path prefix used for tunnel ingress routing (e.g., xicas.visionclawobs.com/realtime). */
export const REALTIME_PATH_PREFIX = "/realtime";
/**
 * Start the realtime module.
 *
 * The realtime backend is mounted inside the OBS HTTP server (see
 * `src/obs/server.ts`) under the `/realtime` path. This mirrors how `/rdp`
 * is mounted: a single listening socket, served via the existing Cloudflare
 * tunnel, so no separate port or DNS setup is required. The caller is
 * expected to register {@link RealtimeModuleHandle.backend} with the OBS
 * server.
 */
export function startRealtimeModule(config) {
    logger.system("[Realtime] Starting realtime module...");
    const backend = createRealtimeBackend(config);
    // Derive the public URL from the existing OBS tunnel hostname.
    const obsTunnelHostname = config.obs.tunnelHostname;
    const tunnelUrl = obsTunnelHostname
        ? `https://${obsTunnelHostname}${REALTIME_PATH_PREFIX}`
        : null;
    if (tunnelUrl) {
        logger.system(`[Realtime] Accessible at ${tunnelUrl} (via OBS HTTP server)`);
    }
    else {
        logger.warn("[Realtime] No OBS tunnel hostname — realtime only accessible locally");
    }
    return {
        backend,
        tunnelUrl,
        close: async () => {
            await backend.close();
            logger.system("[Realtime] Module stopped.");
        },
        getUnprocessedTranscripts: () => Promise.resolve(getUnprocessedTranscriptsFromDir()),
        markTranscriptProcessed: (filename) => {
            markTranscriptProcessedInDir(filename);
            return Promise.resolve();
        },
        getActiveSessionInfo: () => backend.getActiveSessionInfo(),
        onVoiceSessionFinished: (listener) => { backend.onVoiceSessionFinished(listener); },
    };
}
// ── Transcript Processing (Merge Step) ────────────────────────────────────────
function getUnprocessedTranscriptsFromDir() {
    const profileDir = getConfigDir();
    const transcriptsDir = path.join(profileDir, "voice-transcripts");
    if (!fs.existsSync(transcriptsDir))
        return [];
    const files = fs.readdirSync(transcriptsDir).filter((f) => f.endsWith(".json"));
    const unprocessed = [];
    for (const file of files) {
        try {
            const data = JSON.parse(fs.readFileSync(path.join(transcriptsDir, file), "utf-8"));
            const fromCurrentRealtimeFeature = data.schemaVersion === REALTIME_SIDECAR_SCHEMA_VERSION && data.source === REALTIME_SIDECAR_SOURCE;
            const ready = data.summaryStatus === "ready" || (data.summaryStatus === "failed" && !!data.summaryText);
            if (fromCurrentRealtimeFeature && !data.processedByAgent && ready && data.summary?.noActionable !== true) {
                unprocessed.push({ ...data, filename: file });
            }
        }
        catch {
            logger.warn(`[Realtime] Failed to parse transcript: ${file}`);
        }
    }
    unprocessed.sort((a, b) => (a.endedAt ?? "").localeCompare(b.endedAt ?? ""));
    return unprocessed;
}
function markTranscriptProcessedInDir(filename) {
    const profileDir = getConfigDir();
    const filePath = path.join(profileDir, "voice-transcripts", filename);
    if (!fs.existsSync(filePath)) {
        logger.warn(`[Realtime] Transcript not found: ${filename}`);
        return;
    }
    const data = JSON.parse(fs.readFileSync(filePath, "utf-8"));
    data.processedByAgent = true;
    data.processedAt = new Date().toISOString();
    fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
    logger.system(`[Realtime] Transcript marked as processed: ${filename}`);
}
// ── Telegram Menu Button ──────────────────────────────────────────────────────
//
// The persistent chat menu button is intentionally not set by this module
// anymore. Instead the realtime Mini App is surfaced via the `/realtime`
// Telegram slash command, which sends an inline Web App button. This keeps
// the entry point flow consistent with /status and /tasks, and avoids the
// awkward UX of a permanent "Voice" button that breaks whenever the tunnel
// is down.
//# sourceMappingURL=index.js.map