import { promises as fs } from "node:fs";
import { transcribeChunkedFile } from "./chunking.js";
import { DEFAULT_SEGMENT_SECONDS, MAX_OPENAI_UPLOAD_BYTES } from "./constants.js";
import { transcribeMediaBytesWithDiarization, transcribeMediaFileWithDiarization, } from "./diarization.js";
import { isFfmpegAvailable, transcodeBytesToMp3 } from "./ffmpeg.js";
import { shouldRetryGroqViaFfmpeg, transcribeWithGroq } from "./groq.js";
import { transcribeWithLocalOnnx, transcribeWithLocalOnnxFile, transcribeWithLocalWhisperBytes, transcribeWithLocalWhisperFile, } from "./local.js";
import { transcribeBytesWithRemoteFallbacks, transcribeFileWithRemoteFallbacks, transcribeOversizedBytesViaTempFile, } from "./remote.js";
import { formatBytes, wrapError } from "./utils.js";
export async function transcribeMediaWithWhisper({ bytes, mediaType, filename, groqApiKey, skipGroq = false, assemblyaiApiKey = null, elevenlabsApiKey = null, geminiApiKey = null, openaiApiKey, falApiKey, deepgramApiKey = null, diarization = null, totalDurationSeconds = null, onProgress, env = process.env, }) {
    if (diarization) {
        return await transcribeMediaBytesWithDiarization({
            bytes,
            mediaType,
            filename,
            preference: diarization,
            elevenlabsApiKey,
            openaiApiKey,
            env,
            totalDurationSeconds,
            onProgress,
        });
    }
    const notes = [];
    let groqError = null;
    if (groqApiKey && !skipGroq) {
        const groqResult = await transcribeWithGroqFirst({
            bytes,
            mediaType,
            filename,
            groqApiKey,
            notes,
        });
        bytes = groqResult.bytes;
        mediaType = groqResult.mediaType;
        filename = groqResult.filename;
        if (groqResult.text) {
            return { text: groqResult.text, provider: "groq", error: null, notes };
        }
        groqError = groqResult.error;
    }
    if (groqError) {
        notes.push(`Groq transcription failed; falling back to local/AssemblyAI/Gemini/OpenAI/FAL/Deepgram: ${groqError.message}`);
    }
    const onnx = await transcribeWithLocalOnnx({
        bytes,
        mediaType,
        filename,
        totalDurationSeconds,
        onProgress,
        env,
        notes,
    });
    if (onnx)
        return onnx;
    const local = await transcribeWithLocalWhisperBytes({
        bytes,
        mediaType,
        filename,
        totalDurationSeconds,
        onProgress,
        env,
        notes,
    });
    if (local)
        return local;
    return await transcribeBytesWithRemoteFallbacks({
        bytes,
        mediaType,
        filename,
        notes,
        groqApiKey,
        groqError,
        assemblyaiApiKey,
        geminiApiKey,
        openaiApiKey,
        falApiKey,
        deepgramApiKey,
        env,
        onProgress,
        transcribeOversizedBytesWithChunking: ({ bytes, mediaType, filename, onProgress }) => transcribeOversizedBytesViaTempFile({
            bytes,
            mediaType,
            filename,
            onProgress,
            transcribeFile: ({ filePath, mediaType, filename, onProgress }) => transcribeMediaFileWithWhisper({
                filePath,
                mediaType,
                filename,
                groqApiKey,
                assemblyaiApiKey,
                geminiApiKey,
                openaiApiKey,
                falApiKey,
                deepgramApiKey,
                segmentSeconds: DEFAULT_SEGMENT_SECONDS,
                onProgress,
                env,
            }),
        }),
    });
}
export async function transcribeMediaFileWithWhisper({ filePath, mediaType, filename, groqApiKey, assemblyaiApiKey = null, elevenlabsApiKey = null, geminiApiKey = null, openaiApiKey, falApiKey, deepgramApiKey = null, diarization = null, segmentSeconds = DEFAULT_SEGMENT_SECONDS, totalDurationSeconds = null, onProgress = null, env = process.env, }) {
    if (diarization) {
        return await transcribeMediaFileWithDiarization({
            filePath,
            mediaType,
            filename,
            preference: diarization,
            elevenlabsApiKey,
            openaiApiKey,
            env,
            totalDurationSeconds,
            onProgress,
        });
    }
    const notes = [];
    let skipGroqInNestedCalls = false;
    let groqError = null;
    if (groqApiKey) {
        skipGroqInNestedCalls = true;
        const groqResult = await transcribeGroqFileFirst({
            filePath,
            mediaType,
            filename,
            groqApiKey,
            assemblyaiApiKey,
            geminiApiKey,
            openaiApiKey,
            falApiKey,
            deepgramApiKey,
            segmentSeconds,
            totalDurationSeconds,
            onProgress,
            env,
            notes,
        });
        if (groqResult.text)
            return groqResult;
        groqError = groqResult.error;
    }
    const onnx = await transcribeWithLocalOnnxFile({
        filePath,
        mediaType,
        totalDurationSeconds,
        onProgress,
        env,
        notes,
    });
    if (onnx)
        return onnx;
    const local = await transcribeWithLocalWhisperFile({
        filePath,
        mediaType,
        totalDurationSeconds,
        onProgress,
        env,
        notes,
    });
    if (local)
        return local;
    return await transcribeFileWithRemoteFallbacks({
        filePath,
        mediaType,
        filename,
        notes,
        groqApiKey,
        groqError,
        assemblyaiApiKey,
        geminiApiKey,
        openaiApiKey,
        falApiKey,
        deepgramApiKey,
        env,
        totalDurationSeconds,
        onProgress,
        transcribeChunkedFile: ({ filePath, segmentSeconds, totalDurationSeconds, onProgress }) => transcribeChunkedFile({
            filePath,
            segmentSeconds,
            totalDurationSeconds,
            onProgress,
            transcribeSegment: ({ bytes, filename }) => transcribeMediaWithWhisper({
                bytes,
                mediaType: "audio/mpeg",
                filename,
                groqApiKey,
                skipGroq: skipGroqInNestedCalls,
                assemblyaiApiKey,
                geminiApiKey,
                openaiApiKey,
                falApiKey,
                deepgramApiKey,
                env,
            }),
        }),
    });
}
async function transcribeWithGroqFirst({ bytes, mediaType, filename, groqApiKey, notes, }) {
    let groqError = null;
    try {
        const text = await transcribeWithGroq(bytes, mediaType, filename, groqApiKey);
        if (text)
            return { text, error: null, bytes, mediaType, filename };
        groqError = new Error("Groq transcription returned empty text");
    }
    catch (error) {
        groqError = wrapError("Groq transcription failed", error);
    }
    if (groqError && shouldRetryGroqViaFfmpeg(groqError)) {
        const canTranscode = await isFfmpegAvailable();
        if (canTranscode) {
            try {
                notes.push("Groq could not decode media; transcoding via ffmpeg and retrying");
                const mp3Bytes = await transcodeBytesToMp3(bytes);
                const retried = await transcribeWithGroq(mp3Bytes, "audio/mpeg", "audio.mp3", groqApiKey);
                if (retried) {
                    return {
                        text: retried,
                        error: null,
                        bytes: mp3Bytes,
                        mediaType: "audio/mpeg",
                        filename: "audio.mp3",
                    };
                }
                groqError = new Error("Groq transcription returned empty text after ffmpeg transcode");
                bytes = mp3Bytes;
                mediaType = "audio/mpeg";
                filename = "audio.mp3";
            }
            catch (error) {
                notes.push(`ffmpeg transcode failed; cannot retry Groq decode error: ${error instanceof Error ? error.message : String(error)}`);
            }
        }
        else {
            notes.push("Groq could not decode media; install ffmpeg to enable transcoding retry");
        }
    }
    return { text: null, error: groqError, bytes, mediaType, filename };
}
async function transcribeGroqFileFirst({ filePath, mediaType, filename, groqApiKey, assemblyaiApiKey, geminiApiKey, openaiApiKey, falApiKey, deepgramApiKey, segmentSeconds, totalDurationSeconds, onProgress, env, notes, }) {
    const stat = await fs.stat(filePath);
    if (stat.size <= MAX_OPENAI_UPLOAD_BYTES) {
        const fileBytes = new Uint8Array(await fs.readFile(filePath));
        try {
            const text = await transcribeWithGroq(fileBytes, mediaType, filename, groqApiKey);
            if (text)
                return { text, provider: "groq", error: null, notes };
            const error = new Error("Groq transcription returned empty text");
            notes.push("Groq transcription returned empty text; falling back to local/AssemblyAI/Gemini/OpenAI/FAL/Deepgram");
            return { text: null, provider: "groq", error, notes };
        }
        catch (error) {
            const wrapped = wrapError("Groq transcription failed", error);
            notes.push(`Groq transcription failed; falling back to local/AssemblyAI/Gemini/OpenAI/FAL/Deepgram: ${error instanceof Error ? error.message : String(error)}`);
            return { text: null, provider: "groq", error: wrapped, notes };
        }
    }
    const canChunk = await isFfmpegAvailable();
    if (!canChunk) {
        const error = new Error(`File too large for Groq upload (${formatBytes(stat.size)}); trying local providers`);
        notes.push(error.message);
        return { text: null, provider: "groq", error, notes };
    }
    const chunked = await transcribeChunkedFile({
        filePath,
        segmentSeconds,
        totalDurationSeconds,
        onProgress,
        transcribeSegment: ({ bytes, filename }) => transcribeMediaWithWhisper({
            bytes,
            mediaType: "audio/mpeg",
            filename,
            groqApiKey,
            assemblyaiApiKey,
            geminiApiKey,
            openaiApiKey,
            falApiKey,
            deepgramApiKey,
            env,
        }),
    });
    if (chunked.notes.length > 0)
        notes.push(...chunked.notes);
    if (chunked.text)
        return { ...chunked, notes };
    const error = chunked.error ?? new Error("Groq chunked transcription failed");
    notes.push(`Groq chunked transcription failed; falling back to local/AssemblyAI/Gemini/OpenAI/FAL/Deepgram: ${error.message}`);
    return { text: null, provider: "groq", error, notes };
}
//# sourceMappingURL=core.js.map