import { defineEventHandler, readBody, setResponseStatus } from 'h3';
import {
  assignIdsRecursively,
  buildActionMenu,
  buildActivityRing,
  buildAlert,
  buildAvatar,
  buildBadge,
  buildBodyText,
  buildBottomNav,
  buildBreadcrumb,
  buildCalendarGrid,
  buildCardRow,
  buildCarouselDots,
  buildChartBars,
  buildChartLine,
  buildChartPie,
  buildCheckbox,
  buildChipInput,
  buildComment,
  buildCodeBlock,
  buildColorSwatch,
  buildDatePicker,
  buildDivider,
  buildEmptyChart,
  buildEmptyState,
  buildFab,
  buildFaqItem,
  buildFormField,
  buildHeading,
  buildHeadingV1,
  buildIconButton,
  buildIconLabel,
  buildImagePlaceholder,
  buildVideoPlaceholder,
  buildModalShell,
  buildModalShellV1,
  buildUploadDropzone,
  buildOtpInput,
  buildAttachmentRow,
  buildChatBubble,
  buildStatCard,
  buildSocialLoginRow,
  buildPricingCard,
  buildToastV1,
  buildRangeSlider,
  buildEmptyChartV1,
  buildPhoneInput,
  buildInputWithAction,
  buildCookieBanner,
  buildSidebarNav,
  buildAvatarGroup,
  buildDataTableRow,
  buildTag,
  buildUserCard,
  buildDrawerShell,
  buildCombobox,
  buildToolbar,
  buildCallout,
  buildShareRow,
  buildInlineAction,
  buildLegendItem,
  buildInboxMessage,
  buildProfileHeader,
  buildSettingRow,
  buildMemberRow,
  buildFilterGroup,
  buildInviteRow,
  buildActivityLog,
  buildEventCard,
  buildStepCard,
  buildKbd,
  buildLink,
  buildListRow,
  buildMetricComparison,
  buildMetricRow,
  buildNavChipRow,
  buildNotificationRow,
  buildPagination,
  buildPrice,
  buildProgressBar,
  buildQuoteBlock,
  buildRadio,
  buildRatingStars,
  buildSearchBar,
  buildSectionHeader,
  buildSegmentedControl,
  buildSelect,
  buildSkeleton,
  buildStatGrid,
  buildStatusBadge,
  buildSpinner,
  buildStepper,
  buildSwitch,
  buildTabs,
  buildTextarea,
  buildTextButton,
  buildTimeline,
  buildToast,
  buildTooltip,
  buildTopNavBar,
  buildCardRowV1,
  buildSettingRowV1,
  buildMemberRowV1,
  buildActivityLogV1,
  buildAvatarV1,
  buildBadgeV1,
  buildDividerV1,
  buildBodyTextV1,
  buildIconLabelV1,
  buildAlertV1,
  buildBottomNavV1,
  buildBreadcrumbV1,
  buildActivityRingV1,
  buildCarouselDotsV1,
  buildActionMenuV1,
  buildAttachmentRowV1,
  buildCalendarGridV1,
  buildAvatarGroupV1,
  buildCalloutV1,
  buildChartBarsV1,
  buildChartLineV1,
  buildChartPieV1,
  buildChatBubbleV1,
  buildCheckboxV1,
  buildChipInputV1,
  buildCodeBlockV1,
  buildColorSwatchV1,
  buildComboboxV1,
  buildCommentV1,
  buildCookieBannerV1,
  buildDataTableRowV1,
  buildDatePickerV1,
  buildDrawerShellV1,
  buildEmptyStateV1,
  buildEventCardV1,
  buildFabV1,
  buildFaqItemV1,
  buildFilterGroupV1,
  buildFormFieldV1,
  buildIconButtonV1,
  buildImagePlaceholderV1,
  buildInboxMessageV1,
  buildInlineActionV1,
  buildInputWithActionV1,
  buildInviteRowV1,
  buildKbdV1,
  buildLegendItemV1,
  buildLinkV1,
  buildListRowV1,
  buildMetricComparisonV1,
  buildMetricRowV1,
  buildNavChipRowV1,
  buildNotificationRowV1,
  buildOtpInputV1,
  buildPaginationV1,
  buildPhoneInputV1,
  buildPriceV1,
  buildPricingCardV1,
  buildProfileHeaderV1,
  buildProgressBarV1,
  buildQuoteBlockV1,
  buildRadioV1,
  buildRangeSliderV1,
  buildRatingStarsV1,
  buildSearchBarV1,
  buildSectionHeaderV1,
  buildSegmentedControlV1,
  buildSelectV1,
  buildShareRowV1,
  buildSidebarNavV1,
  buildSkeletonV1,
  buildSocialLoginRowV1,
  buildSpinnerV1,
  buildStatCardV1,
  buildStatGridV1,
  buildStatusBadgeV1,
  buildStepCardV1,
  buildStepperV1,
  buildSwitchV1,
  buildTabsV1,
  buildTagV1,
  buildTextButtonV1,
  buildTextareaV1,
  buildTimelineV1,
  buildToolbarV1,
  buildTooltipV1,
  buildTopNavBarV1,
  buildUploadDropzoneV1,
  buildUserCardV1,
  buildVideoPlaceholderV1,
  findNodeInTree,
  insertNodeInTree,
  type ElementTree,
} from '@zseven-w/pen-core';
import { runBatchDesignDsl } from '@zseven-w/pen-mcp';
import { getSyncDocument, setSyncDocument } from '../../utils/mcp-sync-state';
import { serverLog } from '../../utils/server-logger';
import type { PenDocument, PenNode } from '../../../src/types/pen';

/**
 * POST /api/mcp/exec-tool — Phase 2 M3 HTTP fallback.
 *
 * Accepts either:
 *   - `{ name: 'add_X_v0', arguments: {...} }` — an element-tool call
 *     the browser couldn't match to a client shim (or for which the
 *     caller wants authoritative server-side state)
 *   - `{ dsl: '...' }` — a batch_design DSL string
 *
 * For known element tools, the endpoint uses the SAME pen-core
 * builders the client shim uses, so the tree shape is byte-identical
 * across paths. The constructed tree is inserted under the
 * explicitly-named parent (parent_id) or the caller-supplied
 * default (default_parent_id) or the first page's root.
 *
 * For batch_design DSL, the endpoint runs pen-mcp's
 * `runBatchDesignDsl` against the in-memory sync-state doc — no
 * file I/O, no post-processing hooks (those live in the pen-mcp
 * server process). This is the fallback path advertised to the
 * embedded orchestrator's AI when no covered `add_*_v0` matches
 * its intent; it must actually execute or the prompt contract is
 * broken.
 *
 * Both paths call `setSyncDocument` to broadcast via SSE and
 * return the updated doc in the response body so the dispatching
 * client can `applyExternalDocument` immediately without waiting
 * for its own SSE to arrive.
 */

type BuilderFn = (args: unknown) => ElementTree;

/**
 * Server-side builder registry. MUST stay in sync with
 * `apps/web/src/services/ai/element-tool-shims/index.ts`
 * (SUPPORTED_EMBEDDED_ELEMENT_TOOLS) — when extending one, extend
 * the other in the same commit. Both dispatch through pen-core
 * `buildX` so the tree shape is drift-free; this registry exists
 * only to gate unknown tool names + own the sync-state mutation.
 *
 * Coverage gap: elements.md names 42 element tools (the full
 * pen-mcp catalog for external MCP clients). Embedded runtime —
 * shim + this file — covers a subset until more builders are
 * extracted to pen-core. Until then, unsupported names return 404
 * with the canonical supported list and the dispatcher short-
 * circuits before calling us.
 */
const SERVER_BUILDERS: Record<string, BuilderFn> = {
  add_card_row_v0: (a) => buildCardRow(a as Parameters<typeof buildCardRow>[0]),
  add_metric_row_v0: (a) => buildMetricRow(a as Parameters<typeof buildMetricRow>[0]),
  add_bottom_nav_v0: (a) => buildBottomNav(a as Parameters<typeof buildBottomNav>[0]),
  add_section_header_v0: (a) => buildSectionHeader(a as Parameters<typeof buildSectionHeader>[0]),
  add_top_nav_bar_v0: (a) => buildTopNavBar(a as Parameters<typeof buildTopNavBar>[0]),
  add_heading_v0: (a) => buildHeading(a as Parameters<typeof buildHeading>[0]),
  add_heading_v1: (a) => buildHeadingV1(a as Parameters<typeof buildHeadingV1>[0]),
  add_body_text_v0: (a) => buildBodyText(a as Parameters<typeof buildBodyText>[0]),
  add_text_button_v0: (a) => buildTextButton(a as Parameters<typeof buildTextButton>[0]),
  add_search_bar_v0: (a) => buildSearchBar(a as Parameters<typeof buildSearchBar>[0]),
  add_list_row_v0: (a) => buildListRow(a as Parameters<typeof buildListRow>[0]),
  add_divider_v0: (a) => buildDivider(a as Parameters<typeof buildDivider>[0]),
  add_badge_v0: (a) => buildBadge(a as Parameters<typeof buildBadge>[0]),
  add_avatar_v0: (a) => buildAvatar(a as Parameters<typeof buildAvatar>[0]),
  add_icon_button_v0: (a) => buildIconButton(a as Parameters<typeof buildIconButton>[0]),
  add_icon_label_v0: (a) => buildIconLabel(a as Parameters<typeof buildIconLabel>[0]),
  add_stat_grid_v0: (a) => buildStatGrid(a as Parameters<typeof buildStatGrid>[0]),
  add_switch_v0: (a) => buildSwitch(a as Parameters<typeof buildSwitch>[0]),
  add_checkbox_v0: (a) => buildCheckbox(a as Parameters<typeof buildCheckbox>[0]),
  add_radio_v0: (a) => buildRadio(a as Parameters<typeof buildRadio>[0]),
  add_tabs_v0: (a) => buildTabs(a as Parameters<typeof buildTabs>[0]),
  add_segmented_control_v0: (a) =>
    buildSegmentedControl(a as Parameters<typeof buildSegmentedControl>[0]),
  add_empty_state_v0: (a) => buildEmptyState(a as Parameters<typeof buildEmptyState>[0]),
  add_alert_v0: (a) => buildAlert(a as Parameters<typeof buildAlert>[0]),
  add_toast_v0: (a) => buildToast(a as Parameters<typeof buildToast>[0]),
  add_progress_bar_v0: (a) => buildProgressBar(a as Parameters<typeof buildProgressBar>[0]),
  add_fab_v0: (a) => buildFab(a as Parameters<typeof buildFab>[0]),
  add_breadcrumb_v0: (a) => buildBreadcrumb(a as Parameters<typeof buildBreadcrumb>[0]),
  add_stepper_v0: (a) => buildStepper(a as Parameters<typeof buildStepper>[0]),
  add_form_field_v0: (a) => buildFormField(a as Parameters<typeof buildFormField>[0]),
  add_textarea_v0: (a) => buildTextarea(a as Parameters<typeof buildTextarea>[0]),
  add_skeleton_v0: (a) => buildSkeleton(a as Parameters<typeof buildSkeleton>[0]),
  add_select_v0: (a) => buildSelect(a as Parameters<typeof buildSelect>[0]),
  add_chart_line_v0: (a) => buildChartLine(a as Parameters<typeof buildChartLine>[0]),
  add_chart_pie_v0: (a) => buildChartPie(a as Parameters<typeof buildChartPie>[0]),
  add_image_placeholder_v0: (a) =>
    buildImagePlaceholder(a as Parameters<typeof buildImagePlaceholder>[0]),
  add_video_placeholder_v0: (a) =>
    buildVideoPlaceholder(a as Parameters<typeof buildVideoPlaceholder>[0]),
  add_comment_v0: (a) => buildComment(a as Parameters<typeof buildComment>[0]),
  add_modal_shell_v0: (a) => buildModalShell(a as Parameters<typeof buildModalShell>[0]),
  add_status_badge_v0: (a) => buildStatusBadge(a as Parameters<typeof buildStatusBadge>[0]),
  add_spinner_v0: (a) => buildSpinner(a as Parameters<typeof buildSpinner>[0]),
  add_tooltip_v0: (a) => buildTooltip(a as Parameters<typeof buildTooltip>[0]),
  add_metric_comparison_v0: (a) =>
    buildMetricComparison(a as Parameters<typeof buildMetricComparison>[0]),
  add_notification_row_v0: (a) =>
    buildNotificationRow(a as Parameters<typeof buildNotificationRow>[0]),
  add_nav_chip_row_v0: (a) => buildNavChipRow(a as Parameters<typeof buildNavChipRow>[0]),
  add_activity_ring_v0: (a) => buildActivityRing(a as Parameters<typeof buildActivityRing>[0]),
  add_rating_stars_v0: (a) => buildRatingStars(a as Parameters<typeof buildRatingStars>[0]),
  add_carousel_dots_v0: (a) => buildCarouselDots(a as Parameters<typeof buildCarouselDots>[0]),
  add_link_v0: (a) => buildLink(a as Parameters<typeof buildLink>[0]),
  add_kbd_v0: (a) => buildKbd(a as Parameters<typeof buildKbd>[0]),
  add_price_v0: (a) => buildPrice(a as Parameters<typeof buildPrice>[0]),
  add_quote_block_v0: (a) => buildQuoteBlock(a as Parameters<typeof buildQuoteBlock>[0]),
  add_code_block_v0: (a) => buildCodeBlock(a as Parameters<typeof buildCodeBlock>[0]),
  add_color_swatch_v0: (a) => buildColorSwatch(a as Parameters<typeof buildColorSwatch>[0]),
  add_chart_bars_v0: (a) => buildChartBars(a as Parameters<typeof buildChartBars>[0]),
  add_timeline_v0: (a) => buildTimeline(a as Parameters<typeof buildTimeline>[0]),
  add_calendar_grid_v0: (a) => buildCalendarGrid(a as Parameters<typeof buildCalendarGrid>[0]),
  add_pagination_v0: (a) => buildPagination(a as Parameters<typeof buildPagination>[0]),
  add_faq_item_v0: (a) => buildFaqItem(a as Parameters<typeof buildFaqItem>[0]),
  add_chip_input_v0: (a) => buildChipInput(a as Parameters<typeof buildChipInput>[0]),
  add_empty_chart_v0: (a) => buildEmptyChart(a as Parameters<typeof buildEmptyChart>[0]),
  add_action_menu_v0: (a) => buildActionMenu(a as Parameters<typeof buildActionMenu>[0]),
  add_date_picker_v0: (a) => buildDatePicker(a as Parameters<typeof buildDatePicker>[0]),
  add_modal_shell_v1: (a) => buildModalShellV1(a as Parameters<typeof buildModalShellV1>[0]),
  add_upload_dropzone_v0: (a) =>
    buildUploadDropzone(a as Parameters<typeof buildUploadDropzone>[0]),
  add_otp_input_v0: (a) => buildOtpInput(a as Parameters<typeof buildOtpInput>[0]),
  add_attachment_row_v0: (a) => buildAttachmentRow(a as Parameters<typeof buildAttachmentRow>[0]),
  add_chat_bubble_v0: (a) => buildChatBubble(a as Parameters<typeof buildChatBubble>[0]),
  add_stat_card_v0: (a) => buildStatCard(a as Parameters<typeof buildStatCard>[0]),
  add_social_login_row_v0: (a) =>
    buildSocialLoginRow(a as Parameters<typeof buildSocialLoginRow>[0]),
  add_pricing_card_v0: (a) => buildPricingCard(a as Parameters<typeof buildPricingCard>[0]),
  add_toast_v1: (a) => buildToastV1(a as Parameters<typeof buildToastV1>[0]),
  add_range_slider_v0: (a) => buildRangeSlider(a as Parameters<typeof buildRangeSlider>[0]),
  add_empty_chart_v1: (a) => buildEmptyChartV1(a as Parameters<typeof buildEmptyChartV1>[0]),
  add_phone_input_v0: (a) => buildPhoneInput(a as Parameters<typeof buildPhoneInput>[0]),
  add_input_with_action_v0: (a) =>
    buildInputWithAction(a as Parameters<typeof buildInputWithAction>[0]),
  add_cookie_banner_v0: (a) => buildCookieBanner(a as Parameters<typeof buildCookieBanner>[0]),
  add_sidebar_nav_v0: (a) => buildSidebarNav(a as Parameters<typeof buildSidebarNav>[0]),
  add_avatar_group_v0: (a) => buildAvatarGroup(a as Parameters<typeof buildAvatarGroup>[0]),
  add_data_table_row_v0: (a) => buildDataTableRow(a as Parameters<typeof buildDataTableRow>[0]),
  add_tag_v0: (a) => buildTag(a as Parameters<typeof buildTag>[0]),
  add_user_card_v0: (a) => buildUserCard(a as Parameters<typeof buildUserCard>[0]),
  add_drawer_shell_v0: (a) => buildDrawerShell(a as Parameters<typeof buildDrawerShell>[0]),
  add_combobox_v0: (a) => buildCombobox(a as Parameters<typeof buildCombobox>[0]),
  add_toolbar_v0: (a) => buildToolbar(a as Parameters<typeof buildToolbar>[0]),
  add_callout_v0: (a) => buildCallout(a as Parameters<typeof buildCallout>[0]),
  add_share_row_v0: (a) => buildShareRow(a as Parameters<typeof buildShareRow>[0]),
  add_inline_action_v0: (a) => buildInlineAction(a as Parameters<typeof buildInlineAction>[0]),
  add_legend_item_v0: (a) => buildLegendItem(a as Parameters<typeof buildLegendItem>[0]),
  add_inbox_message_v0: (a) => buildInboxMessage(a as Parameters<typeof buildInboxMessage>[0]),
  add_profile_header_v0: (a) => buildProfileHeader(a as Parameters<typeof buildProfileHeader>[0]),
  add_setting_row_v0: (a) => buildSettingRow(a as Parameters<typeof buildSettingRow>[0]),
  add_member_row_v0: (a) => buildMemberRow(a as Parameters<typeof buildMemberRow>[0]),
  add_filter_group_v0: (a) => buildFilterGroup(a as Parameters<typeof buildFilterGroup>[0]),
  add_invite_row_v0: (a) => buildInviteRow(a as Parameters<typeof buildInviteRow>[0]),
  add_activity_log_v0: (a) => buildActivityLog(a as Parameters<typeof buildActivityLog>[0]),
  add_event_card_v0: (a) => buildEventCard(a as Parameters<typeof buildEventCard>[0]),
  add_step_card_v0: (a) => buildStepCard(a as Parameters<typeof buildStepCard>[0]),
  add_card_row_v1: (a) => buildCardRowV1(a as Parameters<typeof buildCardRowV1>[0]),
  add_setting_row_v1: (a) => buildSettingRowV1(a as Parameters<typeof buildSettingRowV1>[0]),
  add_member_row_v1: (a) => buildMemberRowV1(a as Parameters<typeof buildMemberRowV1>[0]),
  add_activity_log_v1: (a) => buildActivityLogV1(a as Parameters<typeof buildActivityLogV1>[0]),
  add_avatar_v1: (a) => buildAvatarV1(a as Parameters<typeof buildAvatarV1>[0]),
  add_badge_v1: (a) => buildBadgeV1(a as Parameters<typeof buildBadgeV1>[0]),
  add_divider_v1: (a) => buildDividerV1(a as Parameters<typeof buildDividerV1>[0]),
  add_body_text_v1: (a) => buildBodyTextV1(a as Parameters<typeof buildBodyTextV1>[0]),
  add_icon_label_v1: (a) => buildIconLabelV1(a as Parameters<typeof buildIconLabelV1>[0]),
  add_alert_v1: (a) => buildAlertV1(a as Parameters<typeof buildAlertV1>[0]),
  add_bottom_nav_v1: (a) => buildBottomNavV1(a as Parameters<typeof buildBottomNavV1>[0]),
  add_breadcrumb_v1: (a) => buildBreadcrumbV1(a as Parameters<typeof buildBreadcrumbV1>[0]),
  add_activity_ring_v1: (a) => buildActivityRingV1(a as Parameters<typeof buildActivityRingV1>[0]),
  add_carousel_dots_v1: (a) => buildCarouselDotsV1(a as Parameters<typeof buildCarouselDotsV1>[0]),
  add_action_menu_v1: (a) => buildActionMenuV1(a as Parameters<typeof buildActionMenuV1>[0]),
  add_attachment_row_v1: (a) =>
    buildAttachmentRowV1(a as Parameters<typeof buildAttachmentRowV1>[0]),
  add_calendar_grid_v1: (a) => buildCalendarGridV1(a as Parameters<typeof buildCalendarGridV1>[0]),
  add_avatar_group_v1: (a) => buildAvatarGroupV1(a as Parameters<typeof buildAvatarGroupV1>[0]),
  add_callout_v1: (a) => buildCalloutV1(a as Parameters<typeof buildCalloutV1>[0]),
  add_chart_bars_v1: (a) => buildChartBarsV1(a as Parameters<typeof buildChartBarsV1>[0]),
  add_chart_line_v1: (a) => buildChartLineV1(a as Parameters<typeof buildChartLineV1>[0]),
  add_chart_pie_v1: (a) => buildChartPieV1(a as Parameters<typeof buildChartPieV1>[0]),
  add_chat_bubble_v1: (a) => buildChatBubbleV1(a as Parameters<typeof buildChatBubbleV1>[0]),
  add_checkbox_v1: (a) => buildCheckboxV1(a as Parameters<typeof buildCheckboxV1>[0]),
  add_chip_input_v1: (a) => buildChipInputV1(a as Parameters<typeof buildChipInputV1>[0]),
  add_code_block_v1: (a) => buildCodeBlockV1(a as Parameters<typeof buildCodeBlockV1>[0]),
  add_color_swatch_v1: (a) => buildColorSwatchV1(a as Parameters<typeof buildColorSwatchV1>[0]),
  add_combobox_v1: (a) => buildComboboxV1(a as Parameters<typeof buildComboboxV1>[0]),
  add_comment_v1: (a) => buildCommentV1(a as Parameters<typeof buildCommentV1>[0]),
  add_cookie_banner_v1: (a) => buildCookieBannerV1(a as Parameters<typeof buildCookieBannerV1>[0]),
  add_data_table_row_v1: (a) => buildDataTableRowV1(a as Parameters<typeof buildDataTableRowV1>[0]),
  add_date_picker_v1: (a) => buildDatePickerV1(a as Parameters<typeof buildDatePickerV1>[0]),
  add_drawer_shell_v1: (a) => buildDrawerShellV1(a as Parameters<typeof buildDrawerShellV1>[0]),
  add_empty_state_v1: (a) => buildEmptyStateV1(a as Parameters<typeof buildEmptyStateV1>[0]),
  add_event_card_v1: (a) => buildEventCardV1(a as Parameters<typeof buildEventCardV1>[0]),
  add_fab_v1: (a) => buildFabV1(a as Parameters<typeof buildFabV1>[0]),
  add_faq_item_v1: (a) => buildFaqItemV1(a as Parameters<typeof buildFaqItemV1>[0]),
  add_filter_group_v1: (a) => buildFilterGroupV1(a as Parameters<typeof buildFilterGroupV1>[0]),
  add_form_field_v1: (a) => buildFormFieldV1(a as Parameters<typeof buildFormFieldV1>[0]),
  add_icon_button_v1: (a) => buildIconButtonV1(a as Parameters<typeof buildIconButtonV1>[0]),
  add_image_placeholder_v1: (a) =>
    buildImagePlaceholderV1(a as Parameters<typeof buildImagePlaceholderV1>[0]),
  add_inbox_message_v1: (a) => buildInboxMessageV1(a as Parameters<typeof buildInboxMessageV1>[0]),
  add_inline_action_v1: (a) => buildInlineActionV1(a as Parameters<typeof buildInlineActionV1>[0]),
  add_input_with_action_v1: (a) =>
    buildInputWithActionV1(a as Parameters<typeof buildInputWithActionV1>[0]),
  add_invite_row_v1: (a) => buildInviteRowV1(a as Parameters<typeof buildInviteRowV1>[0]),
  add_kbd_v1: (a) => buildKbdV1(a as Parameters<typeof buildKbdV1>[0]),
  add_legend_item_v1: (a) => buildLegendItemV1(a as Parameters<typeof buildLegendItemV1>[0]),
  add_link_v1: (a) => buildLinkV1(a as Parameters<typeof buildLinkV1>[0]),
  add_list_row_v1: (a) => buildListRowV1(a as Parameters<typeof buildListRowV1>[0]),
  add_metric_comparison_v1: (a) =>
    buildMetricComparisonV1(a as Parameters<typeof buildMetricComparisonV1>[0]),
  add_metric_row_v1: (a) => buildMetricRowV1(a as Parameters<typeof buildMetricRowV1>[0]),
  add_nav_chip_row_v1: (a) => buildNavChipRowV1(a as Parameters<typeof buildNavChipRowV1>[0]),
  add_notification_row_v1: (a) =>
    buildNotificationRowV1(a as Parameters<typeof buildNotificationRowV1>[0]),
  add_otp_input_v1: (a) => buildOtpInputV1(a as Parameters<typeof buildOtpInputV1>[0]),
  add_pagination_v1: (a) => buildPaginationV1(a as Parameters<typeof buildPaginationV1>[0]),
  add_phone_input_v1: (a) => buildPhoneInputV1(a as Parameters<typeof buildPhoneInputV1>[0]),
  add_price_v1: (a) => buildPriceV1(a as Parameters<typeof buildPriceV1>[0]),
  add_pricing_card_v1: (a) => buildPricingCardV1(a as Parameters<typeof buildPricingCardV1>[0]),
  add_profile_header_v1: (a) =>
    buildProfileHeaderV1(a as Parameters<typeof buildProfileHeaderV1>[0]),
  add_progress_bar_v1: (a) => buildProgressBarV1(a as Parameters<typeof buildProgressBarV1>[0]),
  add_quote_block_v1: (a) => buildQuoteBlockV1(a as Parameters<typeof buildQuoteBlockV1>[0]),
  add_radio_v1: (a) => buildRadioV1(a as Parameters<typeof buildRadioV1>[0]),
  add_range_slider_v1: (a) => buildRangeSliderV1(a as Parameters<typeof buildRangeSliderV1>[0]),
  add_rating_stars_v1: (a) => buildRatingStarsV1(a as Parameters<typeof buildRatingStarsV1>[0]),
  add_search_bar_v1: (a) => buildSearchBarV1(a as Parameters<typeof buildSearchBarV1>[0]),
  add_section_header_v1: (a) =>
    buildSectionHeaderV1(a as Parameters<typeof buildSectionHeaderV1>[0]),
  add_segmented_control_v1: (a) =>
    buildSegmentedControlV1(a as Parameters<typeof buildSegmentedControlV1>[0]),
  add_select_v1: (a) => buildSelectV1(a as Parameters<typeof buildSelectV1>[0]),
  add_share_row_v1: (a) => buildShareRowV1(a as Parameters<typeof buildShareRowV1>[0]),
  add_sidebar_nav_v1: (a) => buildSidebarNavV1(a as Parameters<typeof buildSidebarNavV1>[0]),
  add_skeleton_v1: (a) => buildSkeletonV1(a as Parameters<typeof buildSkeletonV1>[0]),
  add_social_login_row_v1: (a) =>
    buildSocialLoginRowV1(a as Parameters<typeof buildSocialLoginRowV1>[0]),
  add_spinner_v1: (a) => buildSpinnerV1(a as Parameters<typeof buildSpinnerV1>[0]),
  add_stat_card_v1: (a) => buildStatCardV1(a as Parameters<typeof buildStatCardV1>[0]),
  add_stat_grid_v1: (a) => buildStatGridV1(a as Parameters<typeof buildStatGridV1>[0]),
  add_status_badge_v1: (a) => buildStatusBadgeV1(a as Parameters<typeof buildStatusBadgeV1>[0]),
  add_step_card_v1: (a) => buildStepCardV1(a as Parameters<typeof buildStepCardV1>[0]),
  add_stepper_v1: (a) => buildStepperV1(a as Parameters<typeof buildStepperV1>[0]),
  add_switch_v1: (a) => buildSwitchV1(a as Parameters<typeof buildSwitchV1>[0]),
  add_tabs_v1: (a) => buildTabsV1(a as Parameters<typeof buildTabsV1>[0]),
  add_tag_v1: (a) => buildTagV1(a as Parameters<typeof buildTagV1>[0]),
  add_text_button_v1: (a) => buildTextButtonV1(a as Parameters<typeof buildTextButtonV1>[0]),
  add_textarea_v1: (a) => buildTextareaV1(a as Parameters<typeof buildTextareaV1>[0]),
  add_timeline_v1: (a) => buildTimelineV1(a as Parameters<typeof buildTimelineV1>[0]),
  add_toolbar_v1: (a) => buildToolbarV1(a as Parameters<typeof buildToolbarV1>[0]),
  add_tooltip_v1: (a) => buildTooltipV1(a as Parameters<typeof buildTooltipV1>[0]),
  add_top_nav_bar_v1: (a) => buildTopNavBarV1(a as Parameters<typeof buildTopNavBarV1>[0]),
  add_upload_dropzone_v1: (a) =>
    buildUploadDropzoneV1(a as Parameters<typeof buildUploadDropzoneV1>[0]),
  add_user_card_v1: (a) => buildUserCardV1(a as Parameters<typeof buildUserCardV1>[0]),
  add_video_placeholder_v1: (a) =>
    buildVideoPlaceholderV1(a as Parameters<typeof buildVideoPlaceholderV1>[0]),
};

interface ExecToolBody {
  name?: string;
  arguments?: unknown;
  dsl?: string;
  /**
   * Fallback parent id when `arguments.parent_id` is not provided.
   * Forwarded by the client dispatcher from the orchestrator's subtask
   * context (`subtask.parentFrameId ?? plan.rootFrame.id`). Without it
   * rootless payloads would land at page root outside the generation's
   * scope — mirrors the client-shim `ctx.defaultParentId` contract.
   */
  default_parent_id?: string;
}

interface ExecToolError {
  ok: false;
  error: string;
}

interface ExecToolSuccess {
  ok: true;
  document: PenDocument;
  /**
   * Single inserted root id (element-tool path) or the first node
   * produced by a batch_design run. Kept for legacy callers that
   * only read one id.
   */
  insertedNodeId: string;
  /**
   * All inserted root ids. Element-tool path populates exactly one;
   * batch_design DSL can populate many (one per top-level I / C / R
   * binding). Orchestrator uses this to update progress tallies.
   */
  insertedNodeIds: string[];
}

export default defineEventHandler(async (event): Promise<ExecToolSuccess | ExecToolError> => {
  const body = (await readBody(event).catch(() => null)) as ExecToolBody | null;
  if (!body) {
    setResponseStatus(event, 400);
    return { ok: false, error: 'Missing or malformed JSON body' };
  }

  if (body.dsl) {
    const { doc: currentDsl } = getSyncDocument();
    if (!currentDsl) {
      setResponseStatus(event, 409);
      return {
        ok: false,
        error:
          'No live canvas document is currently synced. Open a document before invoking ' +
          '/api/mcp/exec-tool with a DSL payload.',
      };
    }

    // Resolve pageId for the DSL executor. `live://canvas` sentinel +
    // real filePaths are already rejected above; DSL writes always
    // target the in-memory sync-state (which represents the live
    // canvas). Reject real filePaths here too for parity with the
    // element-tool branch.
    const LIVE_CANVAS_SENTINEL_DSL = 'live://canvas';
    const rawDslFilePath =
      typeof (body as Record<string, unknown>).filePath === 'string'
        ? ((body as Record<string, unknown>).filePath as string)
        : null;
    if (
      rawDslFilePath !== null &&
      rawDslFilePath.length > 0 &&
      rawDslFilePath !== LIVE_CANVAS_SENTINEL_DSL
    ) {
      setResponseStatus(event, 501);
      return {
        ok: false,
        error:
          `filePath="${rawDslFilePath}" is not supported by /api/mcp/exec-tool's DSL path — ` +
          `this endpoint mutates the in-memory live canvas only. Route through pen-mcp's ` +
          `stdio / HTTP transport for file-backed DSL.`,
      };
    }
    const dslPageId =
      typeof (body as Record<string, unknown>).pageId === 'string' &&
      ((body as Record<string, unknown>).pageId as string).length > 0
        ? ((body as Record<string, unknown>).pageId as string)
        : undefined;

    // runBatchDesignDsl mutates the cloned doc in place; bindings +
    // per-line errors are collected and surfaced in the response so
    // the dispatcher / user sees exactly which ops failed.
    const nextDsl = structuredClone(currentDsl) as PenDocument;
    const { results: dslResults, errors: dslErrors } = await runBatchDesignDsl(nextDsl, body.dsl, {
      pageId: dslPageId,
    });
    if (dslErrors.length > 0) {
      setResponseStatus(event, 400);
      return {
        ok: false,
        error:
          `batch_design DSL had ${dslErrors.length} failing operation(s): ` +
          dslErrors
            .map((e: { line: string; error: string }) => `${e.line.slice(0, 80)}: ${e.error}`)
            .join('; '),
      };
    }

    setSyncDocument(nextDsl);
    const insertedIds = dslResults
      .map((r: { nodeId: string }) => r.nodeId)
      .filter((id: string) => typeof id === 'string' && id.length > 0);
    const firstId = insertedIds[0] ?? '';
    serverLog.info(
      `[exec-tool] applied batch_design DSL → ${insertedIds.length} op result(s)` +
        (dslPageId ? ` on page ${dslPageId}` : ''),
    );
    return {
      ok: true,
      document: nextDsl,
      insertedNodeId: firstId,
      insertedNodeIds: insertedIds,
    };
  }

  if (!body.name) {
    setResponseStatus(event, 400);
    return { ok: false, error: 'Missing "name" (or "dsl") in request body' };
  }

  const builder = SERVER_BUILDERS[body.name];
  if (!builder) {
    setResponseStatus(event, 404);
    return {
      ok: false,
      error:
        `Element tool "${body.name}" has no server-side builder. Phase 2 M3 currently ` +
        `covers: ${Object.keys(SERVER_BUILDERS).join(', ')}. Extend SERVER_BUILDERS in ` +
        `apps/web/server/api/mcp/exec-tool.post.ts (and the matching shim in ` +
        `apps/web/src/services/ai/element-tool-shims/index.ts) to add more.`,
    };
  }

  // Split meta fields out of the payload before the builder sees them.
  // Builder signatures only accept tool-specific params; leaving
  // parent_id/pageId in would either be silently ignored or rejected
  // as unknown. Mirrors the client shim wrap() contract.
  const rawArgs = (body.arguments ?? {}) as Record<string, unknown>;
  const parentId =
    typeof rawArgs.parent_id === 'string' && rawArgs.parent_id.length > 0
      ? rawArgs.parent_id
      : null;
  const targetPageId =
    typeof rawArgs.pageId === 'string' && rawArgs.pageId.length > 0 ? rawArgs.pageId : null;
  // `live://canvas` is pen-mcp's explicit sentinel for "the live
  // canvas" (document-manager.ts::resolveDocPath treats it the same
  // as an undefined filePath). Normalize to null so the non-live-
  // canvas rejection below only triggers for real file paths.
  const LIVE_CANVAS_SENTINEL = 'live://canvas';
  const rawFilePath =
    typeof rawArgs.filePath === 'string' && rawArgs.filePath.length > 0 ? rawArgs.filePath : null;
  const targetFilePath = rawFilePath === LIVE_CANVAS_SENTINEL ? null : rawFilePath;
  const builderArgs = (() => {
    const { parent_id: _pid, pageId: _pg, filePath: _fp, ...rest } = rawArgs;
    return rest;
  })();

  // filePath is only meaningful for pen-mcp's file-backed handlers
  // (they read/write .op files via document-manager). This endpoint
  // targets the in-memory live document (mcp-sync-state). Silently
  // dropping filePath would report success while the named file stays
  // untouched — surface the mismatch with 501 so the caller routes
  // through pen-mcp's stdio/HTTP transport instead.
  if (targetFilePath !== null) {
    setResponseStatus(event, 501);
    return {
      ok: false,
      error:
        `filePath="${targetFilePath}" is not supported by /api/mcp/exec-tool — this ` +
        `endpoint mutates the in-memory live canvas only. Route through pen-mcp's ` +
        `stdio / HTTP transport (which owns .op file I/O via document-manager), or ` +
        `omit filePath to target the currently-synced live canvas.`,
    };
  }

  let tree: ElementTree;
  try {
    tree = builder(builderArgs);
  } catch (err) {
    setResponseStatus(event, 400);
    return {
      ok: false,
      error: `Builder "${body.name}" rejected arguments: ${err instanceof Error ? err.message : String(err)}`,
    };
  }
  assignIdsRecursively(tree);
  const insertedNodeId = String(tree.id);

  const { doc: current } = getSyncDocument();
  if (!current) {
    setResponseStatus(event, 409);
    return {
      ok: false,
      error:
        'No live canvas document is currently synced. Open a document before invoking ' +
        '/api/mcp/exec-tool.',
    };
  }

  const next = structuredClone(current) as PenDocument;

  // Resolve target page: explicit pageId > first page > legacy children[]
  const pageList = Array.isArray(next.pages) ? next.pages : [];
  let targetPage: { id?: string; children: PenNode[] } | null = null;
  if (targetPageId !== null) {
    const match = pageList.find((p) => p.id === targetPageId);
    if (!match) {
      setResponseStatus(event, 404);
      return {
        ok: false,
        error: `pageId "${targetPageId}" not found in the live document.`,
      };
    }
    targetPage = match;
  } else if (pageList.length > 0) {
    targetPage = pageList[0];
  }

  // Resolve target parent: explicit parent_id > caller-supplied
  // default_parent_id > page root. Explicit parent_id must exist on
  // the chosen page (not silently inserted at root). default_parent_id
  // also must exist (caller is committing to a real target frame).
  const pageChildren: PenNode[] = targetPage
    ? targetPage.children
    : ((next.children ?? []) as PenNode[]);
  if (parentId !== null) {
    const found = findNodeInTree(pageChildren, parentId);
    if (!found) {
      setResponseStatus(event, 404);
      return {
        ok: false,
        error: `parent_id "${parentId}" not found in ${
          targetPageId !== null ? `page "${targetPageId}"` : 'the live document'
        }.`,
      };
    }
  }
  const defaultParentId =
    typeof body.default_parent_id === 'string' && body.default_parent_id.length > 0
      ? body.default_parent_id
      : null;
  if (parentId === null && defaultParentId !== null) {
    const defaultParentNode = findNodeInTree(pageChildren, defaultParentId);
    if (!defaultParentNode) {
      setResponseStatus(event, 404);
      return {
        ok: false,
        error:
          `default_parent_id "${defaultParentId}" not found in ${
            targetPageId !== null ? `page "${targetPageId}"` : 'the live document'
          }. Fix the orchestrator's subtask parent binding or omit default_parent_id ` +
          `to fall through to page-root insertion.`,
      };
    }
  }
  const effectiveParent = parentId ?? defaultParentId;

  // Append (index=Infinity) to match the streaming path's generation-
  // order semantics. Default document-store.addNode prepends (index=0)
  // because new user-created nodes want to be on top of the layer
  // panel; AI-generation wants each element to stack after earlier
  // siblings so multi-call output renders top-to-bottom as emitted.
  const updatedChildren = insertNodeInTree(
    pageChildren,
    effectiveParent,
    tree as unknown as PenNode,
    Infinity,
  );
  if (targetPage) {
    targetPage.children = updatedChildren;
  } else {
    next.children = updatedChildren;
  }

  setSyncDocument(next);
  serverLog.info(
    `[exec-tool] applied ${body.name} → node ${insertedNodeId}` +
      (effectiveParent !== null
        ? ` under ${parentId !== null ? 'parent' : 'default parent'} ${effectiveParent}`
        : '') +
      (targetPageId !== null ? ` on page ${targetPageId}` : ''),
  );

  return {
    ok: true,
    document: next,
    insertedNodeId,
    insertedNodeIds: [insertedNodeId],
  };
});
