// Builders for Weavy recipe execute payload, faithful to the structure
// captured from app.weavy.ai for the "Kling Motion Control" predefined recipe
// (recipe id: YDyaydo2aT1abHpDqPPy8a, model: fal-ai/kling-video/v2.6/pro/motion-control).

const MODEL_NODE_ID = "f22db7fc-a055-45ed-865b-2a12052e98e7";
const IMAGE_NODE_ID = "cc9a9f76-d661-437a-bca1-ff5586c72d66";
const VIDEO_NODE_ID = "81ac95c3-bdd8-4603-9c2c-4f823f6c61fc";

const HANDLE_IDS = {
  prompt: "e7dfb623-49f1-4721-b563-40814c4454e0",
  image_url: "23849317-61d9-463a-a019-0fec97a6cfb2",
  video_url: "71b66c49-368a-4451-bb6c-929aef10f6c7",
  result: "bb0d416a-f903-4aa3-b5b5-5d9b01736721",
};

const EDGE_IDS = {
  video: "494bb4ca-1d18-4c98-b6d1-942053250363",
  image: "38b85d7f-ca26-4605-802d-dd0c944798cd",
};

const MODEL_INFO = {
  name: "fal-ai/kling-video/v2.6/pro/motion-control",
  service: "fal_imported",
  version: "fal-ai/kling-video/v2.6/pro/motion-control",
};

const MODEL_DESCRIPTION =
  "Transfer movements from a reference video to any character image. Pro mode delivers higher quality output, ideal for complex dance moves and gestures.";

const DESCRIPTIONS = {
  prompt: "Text prompt for the video generation. Can include positive and negative descriptions to add elements and motion effects.",
  image_url: "Reference image. The characters, backgrounds, and other elements in the generated video are based on this reference image. Characters should have clear body proportions, avoid occlusion, and occupy more than 5% of the image area.",
  video_url: "Reference video. The character actions in the generated video will be consistent with this reference video. Should contain a realistic style character with entire body or upper body visible, including head, without obstruction. Duration limit depends on character_orientation: 10s max for 'image', 30s max for 'video'.",
  keep_original_sound: "Whether to keep the original sound from the reference video.",
  character_orientation: "Controls whether the output character's orientation matches the reference image or video. 'video': orientation matches reference video - better for complex motions (max 30s). 'image': orientation matches reference image - better for following camera movements (max 10s).",
  model: "Kling Motion Control type",
  version: "Kling Motion Control version",
};


function buildImageFile({ url, meta = {}, insertionOrder = 1 }) {
  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",
    insertionOrder,
  };
}

function buildVideoFile({ url, meta = {}, insertionOrder = 0 }) {
  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",
    insertionOrder,
  };
}

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

function buildSchemaBlock() {
  return {
    model: { type: "enum", order: 0, title: "Model", default: "Pro", options: ["Pro", "Standard"], description: DESCRIPTIONS.model },
    prompt: { type: "string", title: "Prompt", required: false, description: DESCRIPTIONS.prompt },
    version: { type: "enum", order: 0, title: "Version", default: "V3.0", options: ["V2.6", "V3.0"], description: DESCRIPTIONS.version },
    keep_original_sound: { type: "boolean", title: "Keep Original Sound", default: true, required: false, description: DESCRIPTIONS.keep_original_sound },
    character_orientation: { type: "enum", title: "Character Orientation", options: ["image", "video"], required: true, description: DESCRIPTIONS.character_orientation },
  };
}


function buildKindBlock({ imageFile, videoFile, modelType, version, keepOriginalSound, characterOrientation }) {
  // Strip insertionOrder from file copies inside kind.inputs (matches captured payload)
  const imgNoOrder = { ...imageFile }; delete imgNoOrder.insertionOrder;
  const vidNoOrder = { ...videoFile }; delete vidNoOrder.insertionOrder;

  return {
    type: "wildcard",
    model: {
      type: "predefined",
      ...MODEL_INFO,
      description: MODEL_DESCRIPTION,
    },
    inputs: [
      [
        { id: "prompt", title: "Prompt", description: DESCRIPTIONS.prompt, validTypes: ["text"], required: false },
        null,
      ],
      [
        { id: "image_url", title: "image", description: DESCRIPTIONS.image_url, validTypes: ["image"], required: true },
        { nodeId: IMAGE_NODE_ID, outputId: "file", file: imgNoOrder },
      ],
      [
        { id: "video_url", title: "video", description: DESCRIPTIONS.video_url, validTypes: ["video"], required: true },
        { nodeId: VIDEO_NODE_ID, outputId: "file", file: vidNoOrder },
      ],
    ],
    parameters: [
      [
        { id: "model", title: "Model", description: DESCRIPTIONS.model,
          constraint: { type: "enum", options: ["Pro", "Standard"] },
          defaultValue: { type: "string", value: "Pro" } },
        { type: "value", data: { type: "string", value: modelType } },
      ],
      [
        { id: "version", title: "Version", description: DESCRIPTIONS.version,
          constraint: { type: "enum", options: ["V2.6", "V3.0"] },
          defaultValue: { type: "string", value: "V3.0" } },
        { type: "value", data: { type: "string", value: version } },
      ],
      [
        { 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) } },
      ],
      [
        { 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: characterOrientation } },
      ],
    ],
    outputs: [{ id: "result", title: "result", description: "Result video", dataType: "video" }],
  };
}


function buildEdges() {
  return [
    {
      id: EDGE_IDS.video,
      source: VIDEO_NODE_ID,
      target: MODEL_NODE_ID,
      sourceHandle: `${VIDEO_NODE_ID}-output-file`,
      targetHandle: `${MODEL_NODE_ID}-input-video_url`,
      type: "custom",
      data: { sourceColor: "Yambo_Blue", targetColor: "Red", sourceHandleType: "any", targetHandleType: "video" },
      selected: true,
    },
    {
      id: EDGE_IDS.image,
      source: IMAGE_NODE_ID,
      target: MODEL_NODE_ID,
      sourceHandle: `${IMAGE_NODE_ID}-output-file`,
      targetHandle: `${MODEL_NODE_ID}-input-image_url`,
      type: "custom",
      data: { sourceColor: "Yambo_Blue", targetColor: "Red", sourceHandleType: "any", targetHandleType: "image" },
      selected: true,
    },
  ];
}

function buildModelNode({ imageFile, videoFile, prompt, modelType, version, keepOriginalSound, characterOrientation }) {
  return {
    id: MODEL_NODE_ID,
    dragHandle: ".node-header",
    owner: null,
    type: "custommodelV2",
    visibility: "private",
    isModel: true,
    data: {
      handles: buildHandlesBlock(),
      name: "Kling Motion Control",
      description: MODEL_DESCRIPTION,
      color: "Red",
      label: null,
      menu: { icon: "EmojiObjectsIcon", isModel: true, displayName: "Kling Motion Control" },
      model: MODEL_INFO,
      params: {
        model: modelType,
        version,
        keep_original_sound: Boolean(keepOriginalSound),
        character_orientation: characterOrientation,
        ...(prompt ? { prompt } : {}),
        image_url: imageFile,
        video_url: videoFile,
      },
      schema: buildSchemaBlock(),
      version: 3,
      kind: buildKindBlock({ imageFile, videoFile, modelType, version, keepOriginalSound, characterOrientation }),
      generations: [],
      selectedIndex: 0,
      cameraLocked: false,
      result: [],
      output: {},
      selectedOutput: 0,
      input: { image_url: imageFile, video_url: videoFile },
    },
    createdAt: "2026-05-26T12:57:00.267Z",
    updatedAt: "2026-03-06T12:21:09.410Z",
    locked: false,
    position: { x: 2010, y: 620 },
    selected: true,
    width: 460,
    height: 559,
    zIndex: 2,
  };
}


export function buildExecutePayload({
  imageUrl, imageMeta,
  videoUrl, videoMeta,
  prompt = "",
  modelType = "Standard",
  version = "V2.6",
  keepOriginalSound = true,
  characterOrientation = "image",
  numberOfRuns = 1,
}) {
  const imageFile = buildImageFile({ url: imageUrl, meta: imageMeta, insertionOrder: 1 });
  const videoFile = buildVideoFile({ url: videoUrl, meta: videoMeta, insertionOrder: 0 });

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

// Save endpoint not used by this client (we go straight to execute)
export function buildSavePayload(opts) {
  return buildExecutePayload(opts);
}
