package com.yaoai.ai.providers.util;

import java.util.ArrayList;
import java.util.List;

/**
 * 把"结构化视频生成请求"拼装为 Seedance 2.0 可消费的 final prompt + 图片顺序。
 *
 * 图片顺序固定（即 @图N 标号）：
 *   @图1..@图K = 角色（K = 角色数量），@图K+1 = 场景，
 *   @图K+2.. = 道具（按顺序），之后是首/尾帧参考图，最后一张 = 风格图（如有）
 */
public final class SeedancePromptBuilder {

    private SeedancePromptBuilder() {}

    /**
     * 仅依赖原语类型（字符串），不引入 yaoai-api DTO，保持模块依赖单向。
     *
     * @param characterCount 角色图数量（>=1，决定 @图1..@图K 的范围）
     * @param propCount      道具图数量（用于计算 @图N 的范围）
     * @param hasStyleImage  是否含风格图
     */
    /** V17：单段 freeform 提示词模式（前端单输入框后的主要入口）。 */
    public static String buildPromptFreeform(String freeformBody, int characterCount,
                                             boolean hasSceneImage, int propCount, boolean hasStyleImage) {
        return buildPromptFreeform(freeformBody, characterCount, hasSceneImage, propCount, 0, hasStyleImage);
    }

    public static String buildPromptFreeform(String freeformBody, int characterCount,
                                             boolean hasSceneImage, int propCount, int frameCount,
                                             boolean hasStyleImage) {
        StringBuilder sb = new StringBuilder();
        appendImageHeader(sb, characterCount, hasSceneImage, propCount, frameCount, hasStyleImage);
        sb.append("\n分镜内容：\n");
        if (freeformBody != null && !freeformBody.isBlank()) {
            sb.append(freeformBody.trim()).append('\n');
        }
        appendCommonRules(sb);
        return sb.toString();
    }

    public static String buildPrompt(UserPromptParts parts, int characterCount,
                                     boolean hasSceneImage, int propCount, boolean hasStyleImage) {
        return buildPrompt(parts, characterCount, hasSceneImage, propCount, 0, hasStyleImage);
    }

    public static String buildPrompt(UserPromptParts parts, int characterCount,
                                     boolean hasSceneImage, int propCount, int frameCount,
                                     boolean hasStyleImage) {
        StringBuilder sb = new StringBuilder();
        appendImageHeader(sb, characterCount, hasSceneImage, propCount, frameCount, hasStyleImage);

        sb.append("\n分镜内容：\n");
        appendIfPresent(sb, "人物动作", parts.characterAction());
        appendIfPresent(sb, "场景事件", parts.sceneEvent());
        appendIfPresent(sb, "镜头运动", parts.cameraMovement());
        appendIfPresent(sb, "光影氛围", parts.lightingAtmosphere());
        appendIfPresent(sb, "视频风格", parts.videoStyle());

        appendCommonRules(sb);
        return sb.toString();
    }

    /**
     * 根据实际存在的图类型动态分配 @图N 编号（角色 → 场景 → 道具 → 风格）。
     * 任一类可缺省；全空时不输出图片说明。
     */
    private static void appendImageHeader(StringBuilder sb, int characterCount,
                                          boolean hasSceneImage, int propCount, boolean hasStyleImage) {
        appendImageHeader(sb, characterCount, hasSceneImage, propCount, 0, hasStyleImage);
    }

    private static void appendImageHeader(StringBuilder sb, int characterCount,
                                          boolean hasSceneImage, int propCount, int frameCount,
                                          boolean hasStyleImage) {
        int idx = 0;
        if (characterCount == 1) {
            sb.append("@图").append(idx + 1)
              .append(" 是角色/角色状态参考图，请保持人物脸型、五官比例、发型、体型、服装或状态一致，不要随意改变角色身份。\n");
            idx += 1;
        } else if (characterCount > 1) {
            sb.append("@图").append(idx + 1).append("-").append(idx + characterCount)
              .append(" 是出镜角色参考图（按顺序对应剧本中第 1..").append(characterCount)
              .append(" 位角色或角色状态），请保持每位人物的脸型、五官比例、发型、体型、服装或状态一致，不要混淆角色身份。\n");
            idx += characterCount;
        }
        if (hasSceneImage) {
            sb.append("@图").append(idx + 1)
              .append(" 是场景参考图，只参考空间结构、环境布局、走位区域、光影、氛围和构图，不要从场景图里生成新人物。\n");
            idx += 1;
        }
        if (propCount > 0) {
            int propStart = idx + 1;
            int propEnd = propStart + propCount - 1;
            if (propCount == 1) {
                sb.append("@图").append(propStart).append(" 是道具参考图，请在画面中合理使用。\n");
            } else {
                sb.append("@图").append(propStart).append("-").append(propEnd)
                  .append(" 是道具参考图，请在画面中合理使用这些道具。\n");
            }
            idx += propCount;
        }
        if (frameCount > 0) {
            if (frameCount == 1) {
                sb.append("@图").append(idx + 1)
                  .append(" 是分镜首帧或尾帧参考图，请作为画面起止状态参考，不要生硬复制成静态画面。\n");
            } else {
                sb.append("@图").append(idx + 1).append(" 是首帧参考图，@图").append(idx + 2)
                  .append(" 是尾帧参考图，请参考起始和结束画面状态，让视频动作自然衔接。\n");
            }
            idx += frameCount;
        }
        if (hasStyleImage) {
            sb.append("@图").append(idx + 1)
              .append(" 是风格参考图，请参考整体美术风格、色彩和质感。\n");
        }
    }

    private static void appendCommonRules(StringBuilder sb) {
        sb.append("\n生成要求：\n");
        sb.append("- 保持角色一致性\n");
        sb.append("- 如果参考图是同一角色的不同状态，只允许采用状态差异，不要改变身份、脸型、体型和项目视觉风格\n");
        sb.append("- 保持场景逻辑合理\n");
        sb.append("- 人物与环境融合自然\n");
        sb.append("- 镜头运动流畅\n");
        sb.append("- 画面具备电影感\n");
        sb.append("- 不要混合真人、动漫、CG 等不同视觉模式，除非用户在分镜内容里明确要求\n");
        sb.append("- 不要出现多余人物\n");
        sb.append("- 不要出现明显变脸、错位、肢体畸形\n");
    }

    /**
     * 按 @图N 顺序拼接图片 TOS key 列表（角色1..K → 场景 → 道具… → 风格）。
     *
     * @param characterImageKeys 出镜角色图 keys（>=1 张）
     */
    public static List<String> buildOrderedImageKeys(List<String> characterImageKeys,
                                                     String sceneImageKey,
                                                     List<String> propImageKeys,
                                                     String styleImageKey) {
        return buildOrderedImageKeys(characterImageKeys, sceneImageKey, propImageKeys, null, styleImageKey);
    }

    public static List<String> buildOrderedImageKeys(List<String> characterImageKeys,
                                                     String sceneImageKey,
                                                     List<String> propImageKeys,
                                                     List<String> frameImageKeys,
                                                     String styleImageKey) {
        List<String> keys = new ArrayList<>();
        if (characterImageKeys != null) {
            for (String k : characterImageKeys) {
                if (k != null && !k.isBlank()) {
                    keys.add(k);
                }
            }
        }
        if (sceneImageKey != null && !sceneImageKey.isBlank()) {
            keys.add(sceneImageKey);
        }
        if (propImageKeys != null) {
            for (String k : propImageKeys) {
                if (k != null && !k.isBlank()) {
                    keys.add(k);
                }
            }
        }
        if (frameImageKeys != null) {
            for (String k : frameImageKeys) {
                if (k != null && !k.isBlank()) {
                    keys.add(k);
                }
            }
        }
        if (styleImageKey != null && !styleImageKey.isBlank()) {
            keys.add(styleImageKey);
        }
        return keys;
    }

    private static void appendIfPresent(StringBuilder sb, String label, String value) {
        if (value != null && !value.isBlank()) {
            sb.append("- ").append(label).append("：").append(value.trim()).append('\n');
        }
    }

    /** 用户结构化提示词的五段输入；放在工具类内部避免跨模块耦合。 */
    public record UserPromptParts(
            String characterAction,
            String sceneEvent,
            String cameraMovement,
            String lightingAtmosphere,
            String videoStyle
    ) {
    }
}
