import { SACError as CLIError, ExitCode } from "../errors.js";
import { registerProvider } from "./store.js";
const PROMPT_REQUIRED_MODELS = ["volces_seedance_3_0"];
const PROMPT_OPTIONAL_MODELS = [
    "volces_seedance_1_5_pro",
    "volces_seedance_2_0",
    "volces_seedance_2_0_fast",
    "volces_seedance_3_0_pro",
    "volces_seedance_30_i2v",
    "volces_seedance_pro_fast",
    "volces_realman_avatar_picture_omni_v15",
];
const NO_PROMPT_MODELS = [
    "volces_draft_video",
    "volces_jimeng_dream_actor_m1",
    "volces_jimeng_dream_actor_m2",
    "volces_realman_avatar_picture_omni_v2",
    "volces_realman_avatar_imitator_v2v",
];
const VOLCES_VIDEO_MODELS = [
    ...PROMPT_REQUIRED_MODELS,
    ...PROMPT_OPTIONAL_MODELS,
    ...NO_PROMPT_MODELS,
];
const PROMPT_REQUIRED_SET = new Set(PROMPT_REQUIRED_MODELS);
const NO_PROMPT_SET = new Set(NO_PROMPT_MODELS);
function buildBodyEnvelope(model, params) {
    return {
        model,
        dash_scope: true,
        moderation: true,
        input: [{ params }],
        metadata: {},
    };
}
function requireStringFlag(value, message) {
    if (typeof value !== "string" || value.length === 0) {
        throw new CLIError(message, ExitCode.USAGE);
    }
    return value;
}
function maybeStringArray(value) {
    if (Array.isArray(value))
        return value.filter((item) => typeof item === "string" && item.length > 0);
    if (typeof value === "string" && value.length > 0)
        return [value];
    return [];
}
function requirePrimaryImage(flags, model) {
    return requireStringFlag(flags.imageUrl, `Model "${model}" requires --image-url.`);
}
function requireVideoUrl(flags, model) {
    return requireStringFlag(flags.videoUrl, `Model "${model}" requires --video-url.`);
}
function requireAudioUrl(flags, model) {
    return requireStringFlag(flags.audioUrl, `Model "${model}" requires --audio-url.`);
}
function requirePromptOrInput(model, prompt, values, hint) {
    const hasPrompt = prompt.length > 0;
    const hasInput = values.some((value) => {
        if (Array.isArray(value))
            return value.length > 0;
        return typeof value === "string" ? value.length > 0 : value !== undefined && value !== null;
    });
    if (!hasPrompt && !hasInput) {
        throw new CLIError(`Model "${model}" requires --prompt or ${hint}.`, ExitCode.USAGE);
    }
}
function requireFirstFrameForTail(model, flags) {
    if (flags.imageTailUrl && !flags.imageUrl) {
        throw new CLIError(`Model "${model}" requires --image-url when using --image-tail-url.`, ExitCode.USAGE);
    }
}
function maybeRatio(flags) {
    return flags.aspectRatio;
}
function maybeFramesPerSecond(flags) {
    return flags.fps;
}
function maybeSeed(flags) {
    return flags.seed;
}
function applyCommonSeedanceParams(params, flags, options = {}) {
    if (flags.resolution)
        params["resolution"] = flags.resolution;
    if (maybeRatio(flags))
        params["ratio"] = maybeRatio(flags);
    if (flags.duration !== undefined)
        params["duration"] = flags.duration;
    if (options.includeFrames && flags.frames !== undefined)
        params["frames"] = flags.frames;
    if (options.allowFps !== false && maybeFramesPerSecond(flags) !== undefined) {
        params["framespersecond"] = maybeFramesPerSecond(flags);
    }
    if (maybeSeed(flags) !== undefined)
        params["seed"] = maybeSeed(flags);
    if (flags.watermark !== undefined)
        params["watermark"] = flags.watermark;
    if (flags.cameraFixed !== undefined)
        params["camerafixed"] = flags.cameraFixed;
    if (flags.returnLastFrame !== undefined)
        params["return_last_frame"] = flags.returnLastFrame;
    if (options.includeAudio && flags.audio !== undefined)
        params["generate_audio"] = flags.audio;
    if (options.includeServiceTier && flags.serviceTier)
        params["service_tier"] = flags.serviceTier;
    if (options.includeExpiresAfter && flags.expiresAfter !== undefined) {
        params["execution_expires_after"] = flags.expiresAfter;
    }
    if (options.includeDraft && flags.draft !== undefined)
        params["draft"] = flags.draft;
}
function buildTextItem(text) {
    return {
        type: "text",
        text,
    };
}
function buildImageItem(url, role) {
    const item = {
        type: "image_url",
        image_url: { url },
    };
    if (role)
        item["role"] = role;
    return item;
}
function buildVideoItem(url, role) {
    const item = {
        type: "video_url",
        video_url: { url },
    };
    if (role)
        item["role"] = role;
    return item;
}
function buildAudioItem(url, role) {
    const item = {
        type: "audio_url",
        audio_url: { url },
    };
    if (role)
        item["role"] = role;
    return item;
}
function buildSeedance15ProParams(model, prompt, flags) {
    requireFirstFrameForTail(model, flags);
    const content = [];
    if (prompt)
        content.push(buildTextItem(prompt));
    if (flags.imageUrl)
        content.push(buildImageItem(flags.imageUrl, "first_frame"));
    if (flags.imageTailUrl)
        content.push(buildImageItem(flags.imageTailUrl, "last_frame"));
    if (content.length === 0) {
        throw new CLIError(`Model "${model}" requires --prompt or --image-url.`, ExitCode.USAGE);
    }
    const params = { content };
    applyCommonSeedanceParams(params, flags, {
        includeAudio: true,
        includeServiceTier: true,
        includeExpiresAfter: true,
        includeDraft: true,
    });
    return params;
}
function buildSeedance20FamilyParams(model, prompt, flags) {
    requireFirstFrameForTail(model, flags);
    const content = [];
    if (prompt)
        content.push(buildTextItem(prompt));
    if (flags.imageUrl)
        content.push(buildImageItem(flags.imageUrl, "first_frame"));
    if (flags.imageTailUrl)
        content.push(buildImageItem(flags.imageTailUrl, "last_frame"));
    for (const url of maybeStringArray(flags.imageUrls)) {
        content.push(buildImageItem(url, "reference_image"));
    }
    if (flags.videoUrl)
        content.push(buildVideoItem(flags.videoUrl, "reference_video"));
    if (flags.audioUrl)
        content.push(buildAudioItem(flags.audioUrl, "reference_audio"));
    if (content.length === 0) {
        throw new CLIError(`Model "${model}" requires --prompt or at least one of --image-url, --image-urls, --video-url, --audio-url.`, ExitCode.USAGE);
    }
    const params = { content };
    applyCommonSeedanceParams(params, flags, {
        includeAudio: true,
        includeServiceTier: true,
    });
    return params;
}
function buildSeedance30Params(model, prompt, flags) {
    if (!prompt) {
        throw new CLIError(`Model "${model}" requires --prompt.`, ExitCode.USAGE);
    }
    const params = {
        content: [buildTextItem(prompt)],
    };
    applyCommonSeedanceParams(params, flags);
    return params;
}
function buildSeedance30ProParams(model, prompt, flags) {
    requireFirstFrameForTail(model, flags);
    requirePromptOrInput(model, prompt, [flags.imageUrl, flags.imageTailUrl], "--image-url");
    const content = [];
    if (prompt)
        content.push(buildTextItem(prompt));
    if (flags.imageUrl)
        content.push(buildImageItem(flags.imageUrl, "first_frame"));
    if (flags.imageTailUrl)
        content.push(buildImageItem(flags.imageTailUrl, "last_frame"));
    const params = { content };
    applyCommonSeedanceParams(params, flags);
    return params;
}
function buildSeedance30I2VParams(model, prompt, flags) {
    const imageUrl = requirePrimaryImage(flags, model);
    const referenceImages = maybeStringArray(flags.imageUrls);
    if (referenceImages.length > 4) {
        throw new CLIError(`Model "${model}" supports at most 4 --image-urls reference images.`, ExitCode.USAGE);
    }
    const content = [buildImageItem(imageUrl)];
    if (prompt)
        content.push(buildTextItem(prompt));
    for (const url of referenceImages) {
        content.push(buildImageItem(url, "reference_image"));
    }
    const params = { content };
    applyCommonSeedanceParams(params, flags);
    return params;
}
function buildSeedanceProFastParams(model, prompt, flags) {
    if (flags.frames !== undefined && flags.duration !== undefined) {
        throw new CLIError(`Model "${model}" does not allow --frames together with --duration.`, ExitCode.USAGE);
    }
    if (flags.fps !== undefined) {
        throw new CLIError(`Model "${model}" does not support --fps; frame rate is fixed by the upstream API.`, ExitCode.USAGE);
    }
    if (flags.imageTailUrl) {
        throw new CLIError(`Model "${model}" does not support --image-tail-url.`, ExitCode.USAGE);
    }
    requirePromptOrInput(model, prompt, [flags.imageUrl], "--image-url");
    const content = [];
    if (prompt)
        content.push(buildTextItem(prompt));
    if (flags.imageUrl)
        content.push(buildImageItem(flags.imageUrl));
    const params = { content };
    applyCommonSeedanceParams(params, flags, {
        includeFrames: true,
        allowFps: false,
    });
    return params;
}
function buildDraftVideoParams(model, flags) {
    const draftTaskId = requireStringFlag(flags.draftTaskId, `Model "${model}" requires --draft-task-id.`);
    return {
        content: [
            {
                type: "draft_task",
                draft_task: { id: draftTaskId },
            },
        ],
        ...(flags.returnLastFrame !== undefined
            ? { return_last_frame: flags.returnLastFrame }
            : {}),
        ...(flags.serviceTier ? { service_tier: flags.serviceTier } : {}),
        ...(flags.expiresAfter !== undefined
            ? { execution_expires_after: flags.expiresAfter }
            : {}),
        ...(flags.resolution ? { resolution: flags.resolution } : {}),
        ...(maybeRatio(flags) ? { ratio: maybeRatio(flags) } : {}),
        ...(flags.duration !== undefined ? { duration: flags.duration } : {}),
        ...(maybeFramesPerSecond(flags) !== undefined
            ? { framespersecond: maybeFramesPerSecond(flags) }
            : {}),
        ...(flags.watermark !== undefined ? { watermark: flags.watermark } : {}),
        ...(maybeSeed(flags) !== undefined ? { seed: maybeSeed(flags) } : {}),
        ...(flags.cameraFixed !== undefined ? { camerafixed: flags.cameraFixed } : {}),
    };
}
function buildDreamActorM1Params(model, flags) {
    const imageUrl = requirePrimaryImage(flags, model);
    const videoUrl = requireVideoUrl(flags, model);
    const params = {
        image_url: imageUrl,
        video_url: videoUrl,
        return_url: true,
    };
    if (maybeSeed(flags) !== undefined)
        params["seed"] = maybeSeed(flags);
    if (flags.videoQuality)
        params["video_quality"] = flags.videoQuality;
    return params;
}
function buildDreamActorM2Params(model, flags) {
    return {
        image_url: requirePrimaryImage(flags, model),
        video_url: requireVideoUrl(flags, model),
    };
}
function buildAvatarPictureOmniV2Params(model, flags) {
    const params = {
        image_url: requirePrimaryImage(flags, model),
        audio_url: requireAudioUrl(flags, model),
    };
    if (flags.resolution)
        params["resolution"] = flags.resolution;
    if (flags.fps !== undefined)
        params["fps"] = flags.fps;
    if (flags.bitrate !== undefined)
        params["bitrate"] = flags.bitrate;
    return params;
}
function buildAvatarImitatorParams(model, flags) {
    const params = {
        image_url: requirePrimaryImage(flags, model),
        driving_video_info: {
            video_url: requireVideoUrl(flags, model),
            store_type: 0,
        },
    };
    if (maybeSeed(flags) !== undefined)
        params["seed"] = maybeSeed(flags);
    if (flags.resolution)
        params["resolution"] = flags.resolution;
    if (flags.fps !== undefined)
        params["fps"] = flags.fps;
    if (flags.bitrate !== undefined)
        params["bitrate"] = flags.bitrate;
    return params;
}
function buildAvatarPictureOmniV15Params(model, prompt, flags) {
    const params = {
        image_url: requirePrimaryImage(flags, model),
        audio_url: requireAudioUrl(flags, model),
    };
    const maskUrls = maybeStringArray(flags.maskUrls);
    if (maskUrls.length > 0)
        params["mask_url"] = maskUrls;
    if (maybeSeed(flags) !== undefined)
        params["seed"] = maybeSeed(flags);
    if (prompt)
        params["prompt"] = prompt;
    if (flags.peFastMode !== undefined)
        params["pe_fast_mode"] = flags.peFastMode;
    return params;
}
function buildVolcesVideoParams(model, prompt, flags) {
    switch (model) {
        case "volces_seedance_1_5_pro":
            return buildSeedance15ProParams(model, prompt, flags);
        case "volces_seedance_2_0":
        case "volces_seedance_2_0_fast":
            return buildSeedance20FamilyParams(model, prompt, flags);
        case "volces_seedance_3_0":
            return buildSeedance30Params(model, prompt, flags);
        case "volces_seedance_3_0_pro":
            return buildSeedance30ProParams(model, prompt, flags);
        case "volces_seedance_30_i2v":
            return buildSeedance30I2VParams(model, prompt, flags);
        case "volces_seedance_pro_fast":
            return buildSeedanceProFastParams(model, prompt, flags);
        case "volces_draft_video":
            return buildDraftVideoParams(model, flags);
        case "volces_jimeng_dream_actor_m1":
            return buildDreamActorM1Params(model, flags);
        case "volces_jimeng_dream_actor_m2":
            return buildDreamActorM2Params(model, flags);
        case "volces_realman_avatar_picture_omni_v2":
            return buildAvatarPictureOmniV2Params(model, flags);
        case "volces_realman_avatar_imitator_v2v":
            return buildAvatarImitatorParams(model, flags);
        case "volces_realman_avatar_picture_omni_v15":
            return buildAvatarPictureOmniV15Params(model, prompt, flags);
        default:
            throw new CLIError(`Unsupported Volces video model "${model}".`, ExitCode.USAGE);
    }
}
registerProvider({
    provider: "volces",
    category: "video",
    models: VOLCES_VIDEO_MODELS,
    requiresPrompt(model) {
        if (PROMPT_REQUIRED_SET.has(model))
            return true;
        if (NO_PROMPT_SET.has(model))
            return false;
        return false;
    },
    buildBody(model, prompt, flags) {
        return buildBodyEnvelope(model, buildVolcesVideoParams(model, prompt, flags));
    },
});
//# sourceMappingURL=volces-video.js.map