// Builders for Weavy recipe execute payload, based on the actual flow structure
// from kwaivgi/kling-v2.6-motion-control via Replicate
//
// Node IDs are from this specific recipe — each account has its own copy.
// For bot-created accounts, node IDs are overridden via the recipeNodes field.

// ── Default node IDs (kwaivgi/kling-v2.6-motion-control) ──
const DEFAULT_NODE_IDS = {
  model:   "8c577580-26b9-4c54-bc9b-fecec16c671c",
  image:   "6e193dbd-e115-4ccb-9971-0c0659e0311e",
  video:   "6fece398-8a76-491e-981a-c888b343a97c",
  export:  "b305289d-81dc-4fa8-a37a-7fcf108a71c8",
  group:   "febc2fe9-1e80-4502-b289-9bd60ddd5088",
};

// ── Handle IDs (locked to the current recipe shape) ──
const HANDLE_IDS = {
  prompt:    "169bfd06-05f3-44c7-9ad1-d97dba4b6313",
  image:     "efa1f577-bc4d-4320-b7fb-830bee7768ea",
  video:     "8d24d124-4ca6-4c6b-be5c-9ef0e8b0da78",
};

const MODEL_INFO = {
  name: "kwaivgi/kling-v2.6-motion-control",
  service: "replicate",
  version: "cdfd1d85d50b9fb970f0e864e871129f7abcfbd5caa546eb533ab12d322b06ea",
};

const MODEL_DISPLAY_NAME = "kwaivgi/kling-v2.6-motion-control";

const MODEL_DESCRIPTION =
  "Enables precise control of character actions and expressions from a reference image.";

const DESCRIPTIONS = {
  prompt: "Text prompt for video generation. You can add elements to the screen and achieve motion effects through prompt words.",
  image: "Reference image. The characters, backgrounds, and other elements in the generated video are based on the reference image. Supports .jpg/.jpeg/.png, max 10MB, dimensions 340px-3850px, aspect ratio 1:2.5 to 2.5:1.",
  video: "Reference video. The character actions in the generated video are consistent with the reference video. Supports .mp4/.mov, max 100MB, 3-30 seconds duration depending on character_orientation.",
  keep_original_sound: "Whether to keep the original sound of the video",
  character_orientation: "Generate the orientation of the characters in the video. 'image': same orientation as the person in the picture (max 10s video). 'video': consistent with the orientation of the characters in the video (max 30s video).",
  mode: "Video generation mode. 'std': Standard mode (cost-effective). 'pro': Professional mode (higher quality).",
};

// ── LOCKED VALUES (frontend is locked to std mode + image orientation by default) ──
const LOCKED_MODE = "std";
const LOCKED_ORIENTATION = "image";

function buildImageFile({ url, meta = {} }) {
  return {
    type: "image",
    url,
    width: meta.width ?? 1024,
    height: meta.height ?? 1024,
    thumbnailUrl: meta.thumbnailUrl ?? url,
    publicId: meta.publicId ?? "",
    id: meta.id ?? "",
    name: meta.name ?? "image.png",
  };
}

function buildVideoFile({ url, meta = {} }) {
  return {
    type: "video",
    url,
    width: meta.width ?? 576,
    height: meta.height ?? 1024,
    duration: meta.duration ?? 0,
    fps: meta.fps ?? 30,
    hasAudio: meta.hasAudio ?? true,
    thumbnailUrl: meta.thumbnailUrl ?? url,
    publicId: meta.publicId ?? "",
    id: meta.id ?? "",
    name: meta.name ?? "video.mp4",
  };
}

function buildHandlesBlock() {
  return {
    input: {
      prompt: {
        id: HANDLE_IDS.prompt,
        type: "text",
        label: "prompt",
        order: 0,
        format: "text",
        required: false,
        description: DESCRIPTIONS.prompt,
      },
      image: {
        id: HANDLE_IDS.image,
        type: "image",
        label: "image",
        order: 1,
        format: "uri",
        required: true,
        description: DESCRIPTIONS.image,
      },
      video: {
        id: HANDLE_IDS.video,
        type: "video",
        label: "video",
        order: 2,
        format: "uri",
        required: true,
        description: DESCRIPTIONS.video,
      },
    },
    output: ["result"],
  };
}

function buildSchemaBlock() {
  return {
    prompt: {
      type: "string",
      order: 0,
      title: "Prompt",
      default: "",
      required: false,
      description: DESCRIPTIONS.prompt,
    },
    image: {
      type: "string",
      order: 1,
      title: "Image",
      format: "uri",
      required: true,
      description: DESCRIPTIONS.image,
    },
    video: {
      type: "string",
      order: 2,
      title: "Video",
      format: "uri",
      required: true,
      description: DESCRIPTIONS.video,
    },
    character_orientation: {
      type: "enum",
      order: 3,
      title: "Character Orientation",
      default: "image",
      options: ["image", "video"],
      required: false,
      description: DESCRIPTIONS.character_orientation,
    },
    mode: {
      type: "enum",
      order: 4,
      title: "Mode",
      default: "std",
      options: ["std", "pro"],
      required: false,
      description: DESCRIPTIONS.mode,
    },
    keep_original_sound: {
      type: "boolean",
      order: 5,
      title: "Keep Original Sound",
      default: true,
      required: false,
      description: DESCRIPTIONS.keep_original_sound,
    },
  };
}

function buildKindBlock({ nodeIds, keepOriginalSound, imageFile, videoFile, characterOrientation, modelType }) {
  const modeVal = (modelType === "Pro" || modelType === "pro") ? "pro" : "std";
  const orientationVal = characterOrientation || "image";

  return {
    type: "wildcard",
    model: {
      type: "imported",
      name: MODEL_INFO.name,
      version: MODEL_INFO.version,
      service: MODEL_INFO.service,
      coverImage: "https://replicate.delivery/xezq/xNPHY8OYsDbvDpAI22C9pa0FgDJcdV3ZzX2HBUj8nkAygcdF/tmp2jsjo2ed.mp4",
      description: MODEL_DESCRIPTION,
    },
    inputs: [
      [
        { id: "prompt", title: "Prompt", description: DESCRIPTIONS.prompt, validTypes: ["text"], required: false },
        null,
      ],
      [
        { id: "image", title: "Image", description: DESCRIPTIONS.image, validTypes: ["image"], required: true },
        { nodeId: nodeIds.image, outputId: "file", file: imageFile },
      ],
      [
        { id: "video", title: "Video", description: DESCRIPTIONS.video, validTypes: ["video"], required: true },
        { nodeId: nodeIds.video, outputId: "file", file: videoFile },
      ],
    ],
    parameters: [
      [
        { id: "character_orientation", title: "Character Orientation", description: DESCRIPTIONS.character_orientation, constraint: { type: "enum", options: ["image", "video"] }, defaultValue: { type: "string", value: "image" } },
        { type: "value", data: { type: "string", value: orientationVal } },
      ],
      [
        { id: "mode", title: "Mode", description: DESCRIPTIONS.mode, constraint: { type: "enum", options: ["std", "pro"] }, defaultValue: { type: "string", value: "std" } },
        { type: "value", data: { type: "string", value: modeVal } },
      ],
      [
        { id: "keep_original_sound", title: "Keep Original Sound", description: DESCRIPTIONS.keep_original_sound, constraint: { type: "boolean" }, defaultValue: { type: "boolean", value: true } },
        { type: "value", data: { type: "boolean", value: Boolean(keepOriginalSound) } },
      ],
    ],
    outputs: [
      { id: "result", title: "Result" },
    ],
  };
}

function buildModelNode({ nodeIds, imageFile, videoFile, prompt, keepOriginalSound, characterOrientation, modelType }) {
  return {
    id: nodeIds.model,
    dragHandle: ".node-header",
    type: "custommodelV2",
    visibility: null,
    isModel: true,
    data: {
      handles: buildHandlesBlock(),
      name: MODEL_DISPLAY_NAME,
      description: MODEL_DESCRIPTION,
      color: "Yambo_Purple",
      label: null,
      menu: null,
      model: {
        name: MODEL_INFO.name,
        version: MODEL_INFO.version,
        coverImage: "https://replicate.delivery/xezq/xNPHY8OYsDbvDpAI22C9pa0FgDJcdV3ZzX2HBUj8nkAygcdF/tmp2jsjo2ed.mp4",
        service: MODEL_INFO.service,
        originalImportSource: "https://replicate.com/kwaivgi/kling-v2.6-motion-control",
      },
      params: {
        prompt: prompt || "",
        image: imageFile,
        video: videoFile,
        character_orientation: characterOrientation || "image",
        mode: (modelType === "Pro" || modelType === "pro") ? "pro" : "std",
        keep_original_sound: Boolean(keepOriginalSound),
      },
      schema: buildSchemaBlock(),
      version: 2,
      kind: buildKindBlock({ nodeIds, keepOriginalSound, imageFile, videoFile, characterOrientation, modelType }),
      generations: [],
      selectedIndex: 0,
      cameraLocked: false,
      result: [],
      output: {},
      selectedOutput: 0,
    },
    createdAt: "2026-06-30T18:44:33.627Z",
    locked: false,
    parentId: nodeIds.group,
    position: { x: 740, y: 530 },
    selected: true,
    width: 460,
    height: 130,
  };
}

function buildImageImportNode({ nodeIds, imageFile }) {
  return {
    id: nodeIds.image,
    dragHandle: ".node-header",
    type: "import",
    isModel: false,
    data: {
      handles: {
        output: {
          file: { type: "any", label: "File", order: 0, format: "uri", description: "The uploaded file" },
        },
      },
      name: "File",
      color: "Yambo_Blue",
      label: null,
      menu: null,
      params: null,
      schema: null,
      version: 3,
      dark_color: "Yambo_Blue_Dark",
      border_color: "Yambo_Blue_Stroke",
      files: [],
      cameraLocked: false,
      selectedIndex: 0,
      output: {},
    },
    createdAt: "2026-06-30T18:42:19.901Z",
    updatedAt: "2025-06-03T09:49:14.704Z",
    locked: false,
    parentId: nodeIds.group,
    position: { x: 30, y: 30 },
    selected: true,
    width: 460,
    height: 556,
  };
}

function buildVideoImportNode({ nodeIds, videoFile }) {
  return {
    id: nodeIds.video,
    dragHandle: ".node-header",
    type: "import",
    isModel: false,
    data: {
      handles: {
        output: {
          file: { type: "any", label: "File", order: 0, format: "uri", description: "The uploaded file" },
        },
      },
      name: "File",
      color: "Yambo_Blue",
      label: null,
      menu: null,
      params: null,
      schema: null,
      version: 3,
      dark_color: "Yambo_Blue_Dark",
      border_color: "Yambo_Blue_Stroke",
      files: [],
      cameraLocked: false,
      selectedIndex: 0,
      output: {},
    },
    createdAt: "2026-06-30T18:42:19.901Z",
    updatedAt: "2025-06-03T09:49:14.704Z",
    locked: false,
    parentId: nodeIds.group,
    position: { x: 30, y: 810 },
    selected: true,
    width: 460,
    height: 556,
  };
}

function buildExportNode({ nodeIds }) {
  return {
    id: nodeIds.export,
    dragHandle: ".node-header",
    type: "preview",
    isModel: false,
    data: {
      menu: {
        icon: "PreviewIcon",
        order: 4,
        isModel: false,
        displayName: "Preview",
      },
      name: "Preview",
      color: "Yambo_Black",
      label: "Preview",
      params: null,
      schema: null,
      handles: { input: ["file"], output: [] },
      version: null,
      inputNode: { nodeId: nodeIds.model, outputId: "result" },
      dark_color: "Yambo_Black_Dark",
      description: null,
      border_color: "Yambo_Black_Stroke",
    },
    createdAt: "2026-06-30T18:42:19.901Z",
    updatedAt: "2025-06-03T09:49:14.704Z",
    locked: false,
    parentId: nodeIds.group,
    position: { x: 1300, y: 510 },
    selected: true,
    width: 460,
    height: 506,
  };
}

function buildGroupNode({ nodeIds }) {
  return {
    id: nodeIds.group,
    type: "custom_group",
    data: {
      version: 3,
      color: "rgba(227, 232, 236, 0.64)",
      description: "Group of nodes",
      type: "custom_group",
      name: "Group",
      handles: { input: [], output: [] },
      width: 1790,
      height: 1799,
      labelFontSize: 16,
    },
    position: { x: 1680, y: 830 },
    width: 1790,
    height: 1799,
    locked: false,
    selected: true,
    createdAt: "2026-06-30T18:42:19.901Z",
  };
}

function buildInputEdges({ nodeIds }) {
  return [
    {
      id: "df9bb4ba-fb44-4593-b124-b3e417f7029d",
      source: nodeIds.image,
      target: nodeIds.model,
      sourceHandle: `${nodeIds.image}-output-file`,
      targetHandle: `${nodeIds.model}-input-image`,
      type: "custom",
      data: { sourceColor: "Yambo_Blue", targetColor: "Yambo_Purple", sourceHandleType: "any", targetHandleType: "image" },
      selected: true,
    },
    {
      id: "0d23795b-843b-4de2-ae2c-8ae599151827",
      source: nodeIds.video,
      target: nodeIds.model,
      sourceHandle: `${nodeIds.video}-output-file`,
      targetHandle: `${nodeIds.model}-input-video`,
      type: "custom",
      data: { sourceColor: "Yambo_Blue", targetColor: "Yambo_Purple", sourceHandleType: "any", targetHandleType: "video" },
      selected: true,
    },
  ];
}

function buildEdges({ nodeIds }) {
  return [
    ...buildInputEdges({ nodeIds }),
    {
      id: "5696f468-1db9-409a-9be8-124bc56ffa11",
      source: nodeIds.model,
      target: nodeIds.export,
      sourceHandle: `${nodeIds.model}-output-result`,
      targetHandle: `${nodeIds.export}-input-file`,
      type: "custom",
      data: { sourceColor: "Yambo_Purple", targetColor: "Yambo_Black", sourceHandleType: "any" },
      selected: true,
    },
  ];
}

export function buildExecutePayload({
  imageUrl, imageMeta = {},
  videoUrl, videoMeta = {},
  prompt = "",
  keepOriginalSound = true,
  numberOfRuns = 1,
  recipeNodes = null,
  characterOrientation = "image",
  modelType = "Standard",
}) {
  const nodeIds = recipeNodes || DEFAULT_NODE_IDS;

  const imageFile = buildImageFile({ url: imageUrl, meta: imageMeta });
  const videoFile = buildVideoFile({ url: videoUrl, meta: videoMeta });

  return {
    numberOfRuns,
    nodes: [
      buildModelNode({ nodeIds, imageFile, videoFile, prompt, keepOriginalSound, characterOrientation, modelType }),
    ],
    edges: buildEdges({ nodeIds }),
  };
}

export function buildSavePayload({
  imageUrl, imageMeta = {},
  videoUrl, videoMeta = {},
  prompt = "",
  keepOriginalSound = true,
  numberOfRuns = 1,
  recipeNodes = null,
  characterOrientation = "image",
  modelType = "Standard",
}) {
  const nodeIds = recipeNodes || DEFAULT_NODE_IDS;

  const imageFile = buildImageFile({ url: imageUrl, meta: imageMeta });
  const videoFile = buildVideoFile({ url: videoUrl, meta: videoMeta });

  return {
    numberOfRuns,
    nodes: [
      buildModelNode({ nodeIds, imageFile, videoFile, prompt, keepOriginalSound, characterOrientation, modelType }),
      buildImageImportNode({ nodeIds, imageFile }),
      buildVideoImportNode({ nodeIds, videoFile }),
      buildExportNode({ nodeIds }),
      buildGroupNode({ nodeIds }),
    ],
    edges: buildEdges({ nodeIds }),
  };
}
