/**
 * Browser-friendly packages only.
 * (No Node.js built-ins like fs, path, dotenv, etc.)
 * Works in both Node.js and modern browsers.
 */
import { text2SpeechProviderSchema, } from "../types/index.js";
import { beatId } from "../utils/utils.js";
import { GraphAILogger } from "graphai";
import { MulmoPresentationStyleMethods } from "./mulmo_presentation_style.js";
const sessionProgressCallbacks = new Set();
export const addSessionProgressCallback = (cb) => {
    sessionProgressCallbacks.add(cb);
};
export const removeSessionProgressCallback = (cb) => {
    sessionProgressCallbacks.delete(cb);
};
const notifyStateChange = (context, sessionType, result) => {
    const inSession = context.sessionState.inSession[sessionType] ?? false;
    const prefix = inSession ? "<" : " >";
    GraphAILogger.info(`${prefix} ${sessionType}`);
    for (const callback of sessionProgressCallbacks) {
        if (result !== undefined) {
            callback({ kind: "session", sessionType, inSession, result });
        }
        else {
            callback({ kind: "session", sessionType, inSession });
        }
    }
};
const notifyBeatStateChange = (context, sessionType, id) => {
    const inSession = context.sessionState.inBeatSession[sessionType][id] ?? false;
    const prefix = inSession ? "{" : " }";
    GraphAILogger.info(`${prefix} ${sessionType} ${id}`);
    for (const callback of sessionProgressCallbacks) {
        callback({ kind: "beat", sessionType, id, inSession });
    }
};
export const MulmoStudioContextMethods = {
    getAudioDirPath(context) {
        return context.fileDirs.audioDirPath;
    },
    getImageDirPath(context) {
        return context.fileDirs.imageDirPath;
    },
    getImageProjectDirPath(context) {
        const imageDirPath = MulmoStudioContextMethods.getImageDirPath(context);
        if (context.fileDirs.grouped) {
            return imageDirPath;
        }
        return `${imageDirPath}/${context.studio.filename}`;
    },
    getOutDirPath(context) {
        return context.fileDirs.outDirPath;
    },
    getFileName(context) {
        return context.studio.filename;
    },
    getCaption(context) {
        return context.studio.script.captionParams?.lang;
    },
    setSessionState(context, sessionType, value, result) {
        context.sessionState.inSession[sessionType] = value;
        notifyStateChange(context, sessionType, result);
    },
    setBeatSessionState(context, sessionType, index, id, value) {
        if (!sessionType || !Object.hasOwn(context.sessionState.inBeatSession, sessionType)) {
            return;
        }
        const key = beatId(id, index);
        const session = context.sessionState.inBeatSession[sessionType];
        if (value) {
            session[key] = true;
        }
        else {
            // NOTE: Setting to false causes the parse error in rebuildStudio in preprocess.ts
            delete session[key];
        }
        notifyBeatStateChange(context, sessionType, key);
    },
    needTranslate(context, includeCaption = false) {
        // context.studio.script.lang = defaultLang, context.lang = targetLanguage.
        if (includeCaption) {
            return (context.studio.script.lang !== context.lang ||
                (context.studio.script.captionParams?.lang && context.studio.script.lang !== context.studio.script.captionParams?.lang));
        }
        return context.studio.script.lang !== context.lang;
    },
    getIntroPadding(context) {
        if (context.studio.script.beats[0].enableLipSync) {
            // NOTE: We must set introPadding to 0 when enableLipSync is true. Otherwise, the lipsync will be out of sync.
            return 0;
        }
        return context.presentationStyle.audioParams.introPadding;
    },
    getAudioParam(context, beat, lang) {
        const speaker = MulmoPresentationStyleMethods.getSpeaker(context, beat, lang);
        const speechOptions = { ...speaker.speechOptions, ...beat.speechOptions };
        const provider = text2SpeechProviderSchema.parse(speaker.provider);
        return { voiceId: speaker.voiceId, provider, speechOptions, model: speaker.model };
    },
};
