type WindowWithProcess = Window & {
  process?: {
    env?: {
      NODE_ENV?: string
    }
    browser?: boolean
  }
}

type WindowWithGlobal = Window & {
  global?: Window
}

type WindowWithWpIvyApiSettings = Window & {
  wpIvyApiSettings?: {
    root?: string
    namespace?: string
    nonce?: string
  }
}

type BuilderContextSource = 'store' | 'router' | 'url' | 'none'

type BuilderContext = {
  formId: number | null
  source: BuilderContextSource
  isBuilderPage: boolean
  href: string
  hash: string
}

const win = window as unknown as WindowWithProcess & WindowWithGlobal & WindowWithWpIvyApiSettings

// Polyfill for Node.js process object in browser environment
if (typeof win.process === 'undefined' || typeof win.process?.env === 'undefined') {
  win.process = {
    env: {
      NODE_ENV: 'production',
    },
    browser: true,
  }
}

// Polyfill for global object
if (typeof win.global === 'undefined') {
  win.global = window
}

import { AngieMcpSdk } from '@elementor/angie-sdk'
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { z } from 'zod'
import axios from 'axios'

const root = win.wpIvyApiSettings?.root || '/wp-json/'
const namespace = win.wpIvyApiSettings?.namespace || 'ivyforms/v1'
const apiClient = axios.create({
  baseURL: root + namespace + '/',
})

apiClient.interceptors.request.use(
  (config) => {
    config.headers['X-WP-Nonce'] = win.wpIvyApiSettings?.nonce || ''
    return config
  },
  (error) => {
    return Promise.reject(error)
  },
)

async function makeApiRequest(
  endpoint: string,
  params: Record<string, unknown> = {},
  method: 'GET' | 'POST' = 'GET',
  data?: unknown,
) {
  const response = await apiClient.request({
    url: endpoint,
    method,
    params,
    data,
  })

  return response.data
}

function splitText(text: string, chunkSize: number): string[] {
  if (text.length <= chunkSize) return [text]

  const chunks: string[] = []
  for (let i = 0; i < text.length; i += chunkSize) {
    chunks.push(text.slice(i, i + chunkSize))
  }

  return chunks
}

function parseFormIdValue(value: unknown): number | null {
  const normalizedValue = Array.isArray(value) ? value[0] : value
  const parsedValue = Number.parseInt(String(normalizedValue ?? ''), 10)
  return Number.isFinite(parsedValue) && parsedValue > 0 ? parsedValue : null
}

function getCurrentBuilderContext(): BuilderContext {
  const href = window.location.href
  const hash = window.location.hash || ''
  const currentUrl = new URL(href)
  const isBuilderPage = currentUrl.searchParams.get('page') === 'ivyforms-builder'

  const ivyFormsGlobal = (
    window as Window & {
      IvyForms?: {
        formBuilder?: { formId?: string | number | null }
        _router?: {
          currentRoute?: {
            value?: {
              params?: Record<string, unknown>
            }
          }
        }
      }
    }
  ).IvyForms

  const storeFormId = parseFormIdValue(ivyFormsGlobal?.formBuilder?.formId)
  if (storeFormId) {
    return { formId: storeFormId, source: 'store', isBuilderPage, href, hash }
  }

  const routerFormId = parseFormIdValue(
    ivyFormsGlobal?._router?.currentRoute?.value?.params?.formId,
  )
  if (routerFormId) {
    return { formId: routerFormId, source: 'router', isBuilderPage, href, hash }
  }

  const hashMatch = hash.match(/#\/manage\/(\d+)(?:\/|$)/)
  const urlFormId = parseFormIdValue(hashMatch?.[1])
  if (urlFormId) {
    return { formId: urlFormId, source: 'url', isBuilderPage, href, hash }
  }

  return { formId: null, source: 'none', isBuilderPage, href, hash }
}

function navigateToFormBuilder(formId: number, section?: string): string {
  const normalizedSection = section?.trim().replace(/^\/+|\/+$/g, '')
  const canonicalSection =
    normalizedSection === 'settings/notifications' ? 'settings/notification' : normalizedSection
  const routePath = canonicalSection ? `/manage/${formId}/${canonicalSection}` : `/manage/${formId}`

  // Map section paths to Vue named routes for reliable nested navigation
  const sectionToNamedRoute: Record<string, string> = {
    'settings/general': 'ivyforms-form-setting',
    'settings/notification': 'ivyforms-form-notifications',
    'settings/notifications': 'ivyforms-form-notifications',
    'settings/integrations': 'ivyforms-form-integrations',
    'results/entries': 'ivyforms-form-results',
  }

  const ivyFormsGlobal = (
    window as Window & {
      IvyForms?: {
        _router?: {
          push?: (
            route: { path: string } | { name: string; params: Record<string, unknown> },
          ) => unknown
        }
      }
    }
  ).IvyForms

  // Use window.top so navigation targets the parent admin page, not the Angie iframe.
  // Guard against cross-origin SecurityError when the iframe is sandboxed.
  let topWindow: Window & typeof globalThis
  try {
    topWindow = (window.top !== null && window.top !== undefined ? window.top : window) as Window &
      typeof globalThis
    // Probe for cross-origin restriction before using it
    void topWindow.location.href
  } catch (error) {
    console.warn(
      '[IvyForms MCP] Could not access window.top, falling back to iframe window:',
      error,
    )
    topWindow = window as Window & typeof globalThis
  }
  const currentUrl = new URL(topWindow.location.href)

  if (currentUrl.searchParams.get('page') === 'ivyforms-builder') {
    const router = ivyFormsGlobal?._router
    if (router && typeof router.push === 'function') {
      const namedRoute = canonicalSection ? sectionToNamedRoute[canonicalSection] : undefined
      try {
        const pushResult = namedRoute
          ? router.push({ name: namedRoute, params: { formId } })
          : router.push({ path: routePath })
        if (pushResult && typeof (pushResult as Promise<unknown>).catch === 'function') {
          ;(pushResult as Promise<unknown>).catch(() => {
            topWindow.location.hash = routePath
          })
        }
      } catch (error) {
        console.warn(
          '[IvyForms MCP] Router push to form builder failed, falling back to hash navigation:',
          error,
        )
        topWindow.location.hash = routePath
      }
    } else {
      topWindow.location.hash = routePath
    }

    currentUrl.hash = `#${routePath}`
    return currentUrl.toString()
  }

  currentUrl.search = '?page=ivyforms-builder'
  currentUrl.hash = `#${routePath}`
  topWindow.location.href = currentUrl.toString()
  return currentUrl.toString()
}

function navigateToEntryDetails(entryId: number): string {
  const routePath = `/details/${entryId}`

  const ivyFormsGlobal = (
    window as Window & {
      IvyForms?: {
        _router?: {
          push?: (route: { path: string }) => unknown
        }
      }
    }
  ).IvyForms

  // Use window.top so navigation targets the parent admin page, not the Angie iframe.
  // Guard against cross-origin SecurityError when the iframe is sandboxed.
  let topWindow: Window & typeof globalThis
  try {
    topWindow = (window.top !== null && window.top !== undefined ? window.top : window) as Window &
      typeof globalThis
    // Probe for cross-origin restriction before using it
    void topWindow.location.href
  } catch (error) {
    console.warn(
      '[IvyForms MCP] Could not access window.top, falling back to iframe window:',
      error,
    )
    topWindow = window as Window & typeof globalThis
  }
  const currentUrl = new URL(topWindow.location.href)

  if (currentUrl.searchParams.get('page') === 'ivyforms-entries') {
    const router = ivyFormsGlobal?._router
    if (router && typeof router.push === 'function') {
      try {
        const pushResult = router.push({ path: routePath })
        if (pushResult && typeof (pushResult as Promise<unknown>).catch === 'function') {
          ;(pushResult as Promise<unknown>).catch(() => {
            topWindow.location.hash = routePath
          })
        }
      } catch (error) {
        console.warn(
          '[IvyForms MCP] Router push to entry details failed, falling back to hash navigation:',
          error,
        )
        topWindow.location.hash = routePath
      }
    } else {
      topWindow.location.hash = routePath
    }

    currentUrl.hash = `#${routePath}`
    return currentUrl.toString()
  }

  currentUrl.search = '?page=ivyforms-entries'
  currentUrl.hash = `#${routePath}`
  topWindow.location.href = currentUrl.toString()
  return currentUrl.toString()
}

function getFormAdminUrl(formId: number): string {
  return `${window.location.origin}/wp-admin/admin.php?page=ivyforms-builder#/manage/${formId}`
}

function getEntryAdminUrl(entryId: number): string {
  return `${window.location.origin}/wp-admin/admin.php?page=ivyforms-entries#/details/${entryId}`
}

function getFormDisplayName(form: { name?: string | null }): string {
  return form.name || 'Untitled'
}

function getFormResourceLink(form: { id?: number | null; name?: string | null }) {
  const formId = form.id && form.id > 0 ? form.id : null
  if (!formId) {
    return null
  }

  const formName = getFormDisplayName(form)
  const adminLink = getFormAdminUrl(formId)

  return {
    type: 'resource_link' as const,
    name: `ivyforms-form-${formId}`,
    title: `${formName} (ID: ${formId})`,
    uri: adminLink,
    description: `Open form ${formName} in the IvyForms builder`,
    mimeType: 'text/html',
  }
}

const SUPPORTED_FIELD_TYPES = [
  'text',
  'email',
  'textarea',
  'number',
  'phone',
  'website',
  'name',
  'radio',
  'checkbox',
  'address',
  'select',
  'multi-select',
  'time',
  'date',
  'rating',
  'recaptcha',
  'turnstile',
  'hcaptcha',
  'password',
  'signature',
] as const

type SupportedFieldType = (typeof SUPPORTED_FIELD_TYPES)[number]
type SecurityFieldType = 'recaptcha' | 'turnstile' | 'hcaptcha'

type FieldOptionInput = {
  label: string
  value?: string
  isDefault?: boolean
}

type CreateFieldInput = {
  type: SupportedFieldType
  label?: string
  required?: boolean
  placeholder?: string
  description?: string
  defaultValue?: string
  fieldOptions?: FieldOptionInput[]
  rows?: number
  minValue?: number
  maxValue?: number
  step?: number
  showPasswordIcon?: boolean
  confirmFieldEnabled?: boolean
  confirmFieldLabel?: string
  confirmFieldPlaceholder?: string
  signatureWidth?: number
  signatureHeight?: number
}

function isSecurityFieldType(type: string): type is SecurityFieldType {
  return (['recaptcha', 'turnstile', 'hcaptcha'] as const).includes(type as SecurityFieldType)
}

type FieldRecord = {
  id?: number
  formId?: number
  fieldIndex?: number
  rowIndex?: number
  columnIndex?: number
  width?: number
  type?: string
  label?: string
  required?: boolean
  placeholder?: string
  defaultValue?: string
  description?: string
  readOnly?: boolean
  hideLabel?: boolean
  limitMaxLength?: boolean
  maxLength?: number
  labelPosition?: string
  noDuplicates?: boolean
  inputPrefix?: string
  inputSuffix?: string
  confirmFieldEnabled?: boolean
  confirmFieldLabel?: string
  confirmFieldPlaceholder?: string
  confirmFieldHideLabel?: boolean
  position?: number
  parentId?: number
  subFieldIndex?: number
  addressType?: string
  visible?: boolean
  requiredMessage?: string
  fieldOptions?: Array<{
    id: number
    label: string
    value: string
    isDefault: boolean
    position: number
  }>
  rows?: number
  minValue?: number
  maxValue?: number
  step?: number
  showPasswordIcon?: boolean
  signatureWidth?: number
  signatureHeight?: number
}

type FormRecord = {
  id?: number
  name?: string
  description?: string
  published?: boolean
  showTitle?: boolean
  showDescription?: boolean
  storeEntries?: boolean
  integrationSettings?: Record<string, unknown>
  fields?: FieldRecord[]
  formActionButtons?: { submitButtonSettings?: { label: string; position: string } }
  confirmationId?: number
}

type EntryRecord = {
  id?: number | string
  form_id?: number | string | null
  formId?: number | string | null
  form?: { id?: number; name?: string } | null
  form_name?: string | null
  formName?: string | null
  created_at?: string
  [key: string]: unknown
}

function buildDefaultFieldLabel(type: string, providedLabel?: string): string {
  return providedLabel || type.replace(/-/g, ' ').replace(/\b\w/g, (char) => char.toUpperCase())
}

function buildFieldRecordsFromInput(params: {
  formId: number
  fieldIndex: number
  rowIndex: number
  field: CreateFieldInput
}): FieldRecord[] {
  const { formId, fieldIndex, rowIndex, field } = params
  const defaultLabel = buildDefaultFieldLabel(field.type, field.label)

  const newFieldBase: FieldRecord = {
    id: 0,
    formId,
    fieldIndex,
    type: field.type,
    label: defaultLabel,
    required: field.required || false,
    placeholder: field.placeholder || '',
    defaultValue: field.defaultValue || '',
    description: field.description || '',
    readOnly: false,
    hideLabel: false,
    limitMaxLength: false,
    maxLength: 255,
    labelPosition: 'default',
    noDuplicates: false,
    inputPrefix: '',
    inputSuffix: '',
    confirmFieldEnabled: false,
    confirmFieldLabel: '',
    confirmFieldPlaceholder: '',
    confirmFieldHideLabel: false,
    rowIndex,
    columnIndex: 0,
    width: 100,
  }

  if (
    ['radio', 'checkbox', 'select', 'multi-select'].includes(field.type) &&
    field.fieldOptions &&
    field.fieldOptions.length > 0
  ) {
    newFieldBase.fieldOptions = field.fieldOptions.map((opt, idx) => ({
      id: 0,
      label: opt.label,
      value: opt.value || opt.label,
      isDefault: opt.isDefault || false,
      position: idx + 1,
    }))
  } else if (['radio', 'checkbox', 'select', 'multi-select'].includes(field.type)) {
    newFieldBase.fieldOptions = [
      { id: 0, label: 'Option 1', value: 'Option 1', isDefault: false, position: 1 },
      { id: 0, label: 'Option 2', value: 'Option 2', isDefault: false, position: 2 },
      { id: 0, label: 'Option 3', value: 'Option 3', isDefault: false, position: 3 },
    ]
  }

  if (field.type === 'textarea') {
    newFieldBase.rows = field.rows || 3
  }

  if (field.type === 'number') {
    if (field.minValue !== undefined) newFieldBase.minValue = field.minValue
    if (field.maxValue !== undefined) newFieldBase.maxValue = field.maxValue
    if (field.step !== undefined) newFieldBase.step = field.step
  }

  if (field.type === 'password') {
    newFieldBase.showPasswordIcon =
      field.showPasswordIcon !== undefined ? field.showPasswordIcon : true
    if (field.confirmFieldEnabled !== undefined)
      newFieldBase.confirmFieldEnabled = field.confirmFieldEnabled
    if (field.confirmFieldLabel !== undefined)
      newFieldBase.confirmFieldLabel = field.confirmFieldLabel
    if (field.confirmFieldPlaceholder !== undefined) {
      newFieldBase.confirmFieldPlaceholder = field.confirmFieldPlaceholder
    }
  }

  if (field.type === 'signature') {
    if (field.signatureWidth !== undefined) newFieldBase.signatureWidth = field.signatureWidth
    if (field.signatureHeight !== undefined) newFieldBase.signatureHeight = field.signatureHeight
  }

  const newFieldRecords: FieldRecord[] = []

  if (field.type === 'name') {
    newFieldRecords.push(newFieldBase)
    const nameSubFields = [
      { label: 'First Name', subFieldIndex: 0 },
      { label: 'Last Name', subFieldIndex: 1 },
    ]

    for (const sub of nameSubFields) {
      newFieldRecords.push({
        id: 0,
        formId,
        fieldIndex,
        type: 'text',
        label: sub.label,
        defaultValue: '',
        required: false,
        placeholder: '',
        position: 0,
        hideLabel: false,
        description: '',
        requiredMessage: '',
        parentId: 0,
        subFieldIndex: sub.subFieldIndex,
        rowIndex,
        columnIndex: 0,
        width: 100,
      })
    }

    return newFieldRecords
  }

  if (field.type === 'address') {
    newFieldRecords.push(newFieldBase)
    const addressSubFields = [
      { label: 'Street Address', addressType: 'streetAddress' },
      { label: 'Address Line 2', addressType: 'addressLine2' },
      { label: 'City', addressType: 'city' },
      { label: 'State', addressType: 'state' },
      { label: 'Zip', addressType: 'zip' },
      { label: 'Country', addressType: 'country' },
    ]

    for (let i = 0; i < addressSubFields.length; i++) {
      const sub = addressSubFields[i]
      newFieldRecords.push({
        id: 0,
        formId,
        fieldIndex,
        type: 'text',
        label: sub.label,
        defaultValue: '',
        required: false,
        placeholder: '',
        position: 0,
        hideLabel: false,
        description: '',
        requiredMessage: '',
        parentId: 0,
        addressType: sub.addressType,
        subFieldIndex: i,
        visible: true,
        rowIndex,
        columnIndex: 0,
        width: 100,
      })
    }

    return newFieldRecords
  }

  return [newFieldBase]
}

function createIvyFormsMcpServer() {
  const server = new McpServer(
    { name: 'ivyforms-service', version: '1.0.0' },
    { capabilities: { tools: {} } },
  )

  // ──────────────────────────────────────────
  // Forms
  // ──────────────────────────────────────────

  server.tool(
    'get-current-form-builder-context',
    'Get current IvyForms builder context from URL/router/store. Use this before editing when formId is not explicit.',
    {},
    async () => {
      const context = getCurrentBuilderContext()
      return {
        content: [
          {
            type: 'text' as const,
            text: JSON.stringify(context, null, 2),
          },
        ],
      }
    },
  )

  server.tool(
    'open-form-builder',
    'Open a specific form in IvyForms builder edit view. Always use this tool when user asks to open/edit/go to a form, its settings, or its results. Use section parameter for direct navigation: "settings/general" for general settings, "settings/notification" (or "settings/notifications") for notifications, "settings/integrations" for integrations, "results/entries" for form entries/submissions.',
    {
      formId: z.number().describe('Form ID to open in builder edit view (required)'),
      section: z
        .string()
        .optional()
        .describe(
          'Builder section path for direct navigation. Examples: "settings/general", "settings/notification" (alias: "settings/notifications"), "settings/integrations", "results/entries"',
        ),
    },
    async ({ formId, section }) => {
      const targetUrl = navigateToFormBuilder(formId, section)

      return {
        content: [
          {
            type: 'text' as const,
            text: `Opened form ${formId} in builder.`,
          },
          {
            type: 'resource_link' as const,
            name: `ivyforms-open-form-${formId}`,
            title: `Edit form ${formId}`,
            uri: targetUrl,
            description: `IvyForms builder route for form ${formId}`,
            mimeType: 'text/html',
          },
        ],
        structuredContent: {
          formId,
          section: section ?? null,
          targetUrl,
        },
      }
    },
  )

  server.tool(
    'open-entry',
    'Open a specific entry/submission details page by its ID. Use this when the user asks to open, view, or go to a specific entry.',
    {
      entryId: z.number().describe('Entry ID to open (required)'),
    },
    async ({ entryId }) => {
      const targetUrl = navigateToEntryDetails(entryId)

      return {
        content: [
          {
            type: 'text' as const,
            text: `Opened entry ${entryId} details.`,
          },
          {
            type: 'resource_link' as const,
            name: `ivyforms-open-entry-${entryId}`,
            title: `Entry #${entryId} details`,
            uri: targetUrl,
            description: `IvyForms entry details page for entry ${entryId}`,
            mimeType: 'text/html',
          },
        ],
        structuredContent: {
          entryId,
          targetUrl,
        },
      }
    },
  )

  const listIvyForms = async () => {
    const response = await makeApiRequest('forms/search', { perPage: 100 })
    const forms =
      response?.data?.data?.data || response?.data?.data || response?.data || response?.forms

    if (forms && Array.isArray(forms)) {
      const formsWithLinks = forms
        .map((form: FormRecord) => {
          const formId = parseFormIdValue(form.id)
          const formName = getFormDisplayName(form)
          const adminLink = formId ? getFormAdminUrl(formId) : null

          return {
            ...form,
            formId,
            adminLink,
            markdownLink: adminLink ? `[${formName} (ID: ${formId})](${adminLink})` : formName,
          }
        })
        .filter((form) => typeof form.adminLink === 'string' && form.adminLink.length > 0)

      const linkedFormsMarkdown = formsWithLinks
        .map((form) => `- ${form.markdownLink}\n  ${form.adminLink}`)
        .join('\n')

      const formResourceLinks = formsWithLinks.map((form) => ({
        type: 'resource_link' as const,
        name: `ivyforms-form-${form.formId}`,
        title: `${getFormDisplayName(form)} (ID: ${form.formId})`,
        uri: form.adminLink,
        description: `Open form ${getFormDisplayName(form)} in the IvyForms builder`,
        mimeType: 'text/html',
      }))

      return {
        content: [
          ...formResourceLinks,
          {
            type: 'text' as const,
            text:
              `Return this list exactly as written (do not paraphrase names, keep links clickable):\n` +
              `${linkedFormsMarkdown}`,
          },
        ],
        structuredContent: {
          source: 'ivyforms',
          totalCount: formsWithLinks.length,
        },
      }
    }

    throw new Error('No forms found in response')
  }

  server.tool(
    'list-forms',
    'Get all available forms from IvyForms only. Use this when user asks: list forms, list all forms, show all forms, or what forms exist in IvyForms. IMPORTANT: when answering, output the returned linked list verbatim so links stay clickable.',
    listIvyForms,
  )

  server.tool(
    'list-all-forms',
    'Alias for list-forms. Always use this for prompts like "list all forms" in IvyForms context.',
    listIvyForms,
  )

  server.tool(
    'get-form',
    'Get a single form by its ID, including all fields and configuration.',
    {
      formId: z.number().describe('Form ID (required)'),
    },
    async ({ formId }) => {
      try {
        const response = await makeApiRequest(`form/${formId}`)

        // Response format: { message, data: { ...form, confirmationId } }
        const form: FormRecord | undefined = response?.data

        if (form) {
          const formName = getFormDisplayName(form)
          const resolvedFormId = form.id && form.id > 0 ? form.id : null
          const adminLink = resolvedFormId ? getFormAdminUrl(resolvedFormId) : null
          const formLink = getFormResourceLink(form)
          const formWithLink = {
            ...form,
            adminLink,
            markdownLink: adminLink
              ? `[${formName} (ID: ${resolvedFormId})](${adminLink})`
              : `${formName}`,
          }
          return {
            content: [
              ...(formLink ? [formLink] : []),
              {
                type: 'text' as const,
                text: JSON.stringify(formWithLink, null, 2),
              },
            ],
          }
        }

        return {
          content: [
            {
              type: 'text' as const,
              text: `Form with ID ${formId} not found.`,
            },
          ],
        }
      } catch (error) {
        console.warn('[IvyForms MCP] get-form failed:', error)
        return {
          content: [
            {
              type: 'text' as const,
              text: `Form with ID ${formId} not found or an error occurred.`,
            },
          ],
        }
      }
    },
  )

  server.tool(
    'create-form',
    'Creates a brand new form from a template. Supports optional initial fields so the form can be created and pre-populated in one step. Defaults to blank_form template if none specified.',
    {
      name: z
        .string()
        .optional()
        .describe('Custom form name. If provided, it is applied after form creation.'),
      templateId: z
        .string()
        .optional()
        .describe(
          'Template ID to create the form from (e.g. "blank_form", "contact_form", "event_registration"). Defaults to "blank_form". Use list-templates to see all available template IDs.',
        ),
      fields: z
        .array(
          z.object({
            type: z
              .enum(SUPPORTED_FIELD_TYPES)
              .describe(
                'Field type. Security types: recaptcha, turnstile, hcaptcha. Pro-only types: password, signature.',
              ),
            label: z.string().optional().describe('Field label'),
            required: z.boolean().optional().describe('Whether the field is required'),
            placeholder: z.string().optional().describe('Placeholder text'),
            description: z.string().optional().describe('Help text below the field'),
            defaultValue: z.string().optional().describe('Default value'),
            fieldOptions: z
              .array(
                z.object({
                  label: z.string().describe('Option label'),
                  value: z.string().optional().describe('Option value (defaults to label)'),
                  isDefault: z.boolean().optional().describe('Default selected option'),
                }),
              )
              .optional()
              .describe('Options for radio, checkbox, select, multi-select fields'),
            rows: z.number().optional().describe('Textarea rows'),
            minValue: z.number().optional().describe('Minimum value for number fields'),
            maxValue: z.number().optional().describe('Maximum value for number fields'),
            step: z.number().optional().describe('Step for number fields'),
            showPasswordIcon: z
              .boolean()
              .optional()
              .describe('Show password toggle icon (password field, Pro only)'),
            confirmFieldEnabled: z
              .boolean()
              .optional()
              .describe('Enable confirm password field (password field, Pro only)'),
            confirmFieldLabel: z
              .string()
              .optional()
              .describe('Confirm password field label (password field, Pro only)'),
            confirmFieldPlaceholder: z
              .string()
              .optional()
              .describe('Confirm password placeholder (password field, Pro only)'),
            signatureWidth: z
              .number()
              .optional()
              .describe('Signature canvas width in px (signature field, Pro only)'),
            signatureHeight: z
              .number()
              .optional()
              .describe('Signature canvas height in px (signature field, Pro only)'),
          }),
        )
        .optional()
        .describe('Optional list of fields to create immediately after the form is created.'),
    },
    async ({ name, templateId, fields }) => {
      const formData: Record<string, unknown> = {
        template_id: templateId || 'blank_form',
      }

      const createResult = await makeApiRequest('form/add/', {}, 'POST', formData)
      const createdForm = createResult?.data?.data || createResult?.data || createResult
      const createdFormId = parseFormIdValue(createdForm?.id)

      if (!createdFormId) {
        return {
          content: [
            {
              type: 'text' as const,
              text: JSON.stringify(createResult, null, 2),
            },
          ],
        }
      }

      const formResponse = await makeApiRequest(`form/${createdFormId}`)
      const fetchedFormData = formResponse?.data?.data ?? formResponse?.data ?? {}
      const existingFields: FieldRecord[] = Array.isArray(fetchedFormData.fields)
        ? fetchedFormData.fields
        : []

      const normalizedFields: CreateFieldInput[] = Array.isArray(fields)
        ? fields.map((field) => ({ ...field }))
        : []

      const existingSecurityTypes = new Set(
        existingFields
          .map((field) => field.type ?? '')
          .filter((fieldType) => isSecurityFieldType(fieldType)),
      )

      const requestedSecurityTypes = normalizedFields
        .map((field) => field.type)
        .filter((fieldType) => isSecurityFieldType(fieldType))

      const conflictingSecurityType = requestedSecurityTypes.find((requestedType) =>
        Array.from(existingSecurityTypes).some((existingType) => existingType !== requestedType),
      )

      if (conflictingSecurityType) {
        return {
          content: [
            {
              type: 'text' as const,
              text: JSON.stringify(
                {
                  message:
                    'Form was created, but requested security fields conflict with an existing security provider on this form. Only one of recaptcha, turnstile, or hcaptcha can exist at a time.',
                  formId: createdFormId,
                  adminLink: getFormAdminUrl(createdFormId),
                  addedFields: 0,
                  requestedSecurityTypes,
                  existingSecurityTypes: Array.from(existingSecurityTypes),
                  created: true,
                },
                null,
                2,
              ),
            },
          ],
        }
      }

      const uniqueRequestedSecurityTypes = new Set(requestedSecurityTypes)
      if (uniqueRequestedSecurityTypes.size > 1) {
        return {
          content: [
            {
              type: 'text' as const,
              text: JSON.stringify(
                {
                  message:
                    'Form was created, but multiple security providers were requested. Add only one of recaptcha, turnstile, or hcaptcha.',
                  formId: createdFormId,
                  adminLink: getFormAdminUrl(createdFormId),
                  addedFields: 0,
                  requestedSecurityTypes: Array.from(uniqueRequestedSecurityTypes),
                  created: true,
                },
                null,
                2,
              ),
            },
          ],
        }
      }

      let nextFieldIndex = existingFields.reduce(
        (max: number, field: FieldRecord) => Math.max(max, field.fieldIndex ?? 0),
        0,
      )
      let nextRowIndex = existingFields.reduce(
        (max: number, field: FieldRecord) => Math.max(max, field.rowIndex ?? 0),
        0,
      )

      const createdFieldRecords: FieldRecord[] = []
      for (const field of normalizedFields) {
        nextFieldIndex += 1
        nextRowIndex += 1
        const builtRecords = buildFieldRecordsFromInput({
          formId: createdFormId,
          fieldIndex: nextFieldIndex,
          rowIndex: nextRowIndex,
          field,
        })
        createdFieldRecords.push(...builtRecords)
      }

      let updateResult: unknown = null
      if (name || createdFieldRecords.length > 0) {
        const allFields = [...existingFields, ...createdFieldRecords]
        allFields.forEach((field, idx) => {
          field.position = idx + 1
        })

        const updatePayload = {
          id: createdFormId,
          name: name || fetchedFormData.name || createdForm.name || 'Untitled',
          description: fetchedFormData.description || '',
          published: fetchedFormData.published ?? false,
          showTitle: fetchedFormData.showTitle ?? false,
          showDescription: fetchedFormData.showDescription ?? false,
          storeEntries: fetchedFormData.storeEntries ?? false,
          integrationSettings: fetchedFormData.integrationSettings || {},
          fields: allFields,
          formActionButtons: fetchedFormData.formActionButtons || {
            submitButtonSettings: { label: 'Submit', position: 'default' },
          },
        }

        updateResult = await makeApiRequest(
          `form/update/${createdFormId}/`,
          {},
          'POST',
          updatePayload,
        )
      }

      const responsePayload = {
        message:
          createdFieldRecords.length > 0
            ? `Form created successfully with ${normalizedFields.length} initial field(s).`
            : 'Form created successfully.',
        formId: createdFormId,
        adminLink: getFormAdminUrl(createdFormId),
        templateId: formData.template_id,
        name: name || fetchedFormData.name || createdForm.name || null,
        addedFields: normalizedFields.length,
        createResponse: createResult,
        updateResponse: updateResult,
      }

      return {
        content: [
          {
            type: 'text' as const,
            text: JSON.stringify(responsePayload, null, 2),
          },
        ],
      }
    },
  )

  server.tool(
    'duplicate-form',
    'Duplicates an existing form by its ID. Use this when the user wants to copy/clone a form.',
    {
      formId: z.number().describe('Form ID to duplicate (required)'),
    },
    async ({ formId }) => {
      const result = await makeApiRequest(`form/duplicate/${formId}`, {}, 'POST')
      const duplicatedForm = result?.data?.data || result?.data || result
      if (duplicatedForm && typeof duplicatedForm.id === 'number' && duplicatedForm.id > 0) {
        duplicatedForm.adminLink = getFormAdminUrl(duplicatedForm.id)
      }

      return {
        content: [
          {
            type: 'text' as const,
            text: JSON.stringify(result, null, 2),
          },
        ],
      }
    },
  )

  server.tool(
    'delete-form',
    'Deletes a form by its ID. Use this when the user wants to remove a form.',
    {
      formId: z.number().describe('Form ID to delete (required)'),
    },
    async ({ formId }) => {
      const result = await makeApiRequest(`form/delete/${formId}`, {}, 'POST')

      return {
        content: [
          {
            type: 'text' as const,
            text: JSON.stringify(result, null, 2),
          },
        ],
      }
    },
  )

  // ──────────────────────────────────────────
  // Fields
  // ──────────────────────────────────────────

  server.tool(
    'add-field-to-form',
    'Add a new field to an existing form and save it. Automatically detects the current form from the builder URL if formId is not provided. After saving, the user should reload the page to see changes. Use this when the user asks to add a field (e.g. "add a text field", "add an email field to this form").',
    {
      formId: z
        .number()
        .optional()
        .describe(
          'Form ID to add the field to. If omitted, auto-detects from the current builder page URL.',
        ),
      type: z
        .enum(SUPPORTED_FIELD_TYPES)
        .describe(
          'Field type (required). Security types: recaptcha, turnstile, hcaptcha. Pro-only types: password, signature (requires IvyForms Pro).',
        ),
      label: z.string().optional().describe('Field label. Defaults to the capitalized field type.'),
      required: z.boolean().optional().describe('Whether the field is required (default: false)'),
      placeholder: z.string().optional().describe('Placeholder text for the field'),
      description: z.string().optional().describe('Help text / description shown below the field'),
      defaultValue: z.string().optional().describe('Default value for the field'),
      position: z
        .number()
        .optional()
        .describe(
          'Position index (1-based) where the field should be inserted among existing fields. If omitted, the field is appended at the end.',
        ),
      fieldOptions: z
        .array(
          z.object({
            label: z.string().describe('Option label'),
            value: z.string().optional().describe('Option value (defaults to label)'),
            isDefault: z
              .boolean()
              .optional()
              .describe('Whether this option is selected by default'),
          }),
        )
        .optional()
        .describe(
          'Options/choices for radio, checkbox, select, and multi-select fields. Each option has a label and optional value.',
        ),
      rows: z.number().optional().describe('Number of rows for textarea fields (default: 3)'),
      minValue: z.number().optional().describe('Minimum value for number fields'),
      maxValue: z.number().optional().describe('Maximum value for number fields'),
      step: z.number().optional().describe('Step increment for number fields'),
      // Password field options (Pro)
      showPasswordIcon: z
        .boolean()
        .optional()
        .describe('Show/hide password toggle icon for password fields (default: true). Pro only.'),
      confirmFieldEnabled: z
        .boolean()
        .optional()
        .describe('Enable confirm password field (default: false). Pro only.'),
      confirmFieldLabel: z
        .string()
        .optional()
        .describe('Label for the confirm password field. Pro only.'),
      confirmFieldPlaceholder: z
        .string()
        .optional()
        .describe('Placeholder for the confirm password field. Pro only.'),
      // Signature field options (Pro)
      signatureWidth: z
        .number()
        .optional()
        .describe('Canvas width in pixels for signature fields. Pro only.'),
      signatureHeight: z
        .number()
        .optional()
        .describe('Canvas height in pixels for signature fields (min 100). Pro only.'),
    },
    async (params) => {
      try {
        // 1. Resolve form ID
        let resolvedFormId = params.formId
        if (!resolvedFormId) {
          const context = getCurrentBuilderContext()
          resolvedFormId = context.formId ?? undefined
        }
        if (!resolvedFormId) {
          return {
            content: [
              {
                type: 'text' as const,
                text: 'Could not determine the form ID. Please provide a formId or navigate to a form in the builder first.',
              },
            ],
          }
        }

        // 2. Fetch existing form data (response is double-wrapped by Controller __invoke)
        const formResponse = await makeApiRequest(`form/${resolvedFormId}`)
        const formData = formResponse?.data?.data ?? formResponse?.data
        if (!formData || !formData.name) {
          return {
            content: [
              {
                type: 'text' as const,
                text: `Form with ID ${resolvedFormId} not found.`,
              },
            ],
          }
        }

        // 3. Get existing fields (already in flat/denormalized API format)
        const existingFields: FieldRecord[] = Array.isArray(formData.fields) ? formData.fields : []

        // Match builder behavior: only one CAPTCHA provider field can exist per form.
        const requestedType = params.type
        if (isSecurityFieldType(requestedType)) {
          const existingSecurityField = existingFields.find((field) =>
            isSecurityFieldType(field.type ?? ''),
          )

          if (existingSecurityField) {
            const existingType = existingSecurityField.type ?? 'security'

            return {
              content: [
                {
                  type: 'text' as const,
                  text: JSON.stringify(
                    {
                      message: `This form already has a ${existingType} security field. Only one of recaptcha, turnstile, or hcaptcha can be added at a time.`,
                      formId: resolvedFormId,
                      requestedFieldType: requestedType,
                      existingSecurityFieldType: existingType,
                      added: false,
                    },
                    null,
                    2,
                  ),
                },
              ],
            }
          }
        }

        // Calculate next fieldIndex
        const maxFieldIndex = existingFields.reduce(
          (max: number, field: FieldRecord) => Math.max(max, field.fieldIndex ?? 0),
          0,
        )

        // Calculate layout: new row after all existing rows
        const maxRowIndex = existingFields.reduce(
          (max: number, field: FieldRecord) => Math.max(max, field.rowIndex ?? 0),
          0,
        )

        // 4. Build the new field(s) in flat API format
        const newFieldRecords = buildFieldRecordsFromInput({
          formId: resolvedFormId,
          fieldIndex: maxFieldIndex + 1,
          rowIndex: maxRowIndex + 1,
          field: params,
        })
        const newFieldBase = newFieldRecords[0]
        const defaultLabel = newFieldBase.label as string

        // 5. Insert at specified position or append
        // For position insertion, we only consider parent fields (no parentId)
        const parentFields = existingFields.filter(
          (field) => !field.parentId || field.parentId === 0,
        )
        const insertIndex =
          params.position && params.position >= 1 && params.position <= parentFields.length + 1
            ? params.position - 1
            : parentFields.length

        // If inserting at a specific position, shift rowIndex of fields at and after
        if (params.position && insertIndex < parentFields.length) {
          const targetRowIndex = parentFields[insertIndex]?.rowIndex
          if (typeof targetRowIndex === 'number') {
            newFieldBase.rowIndex = targetRowIndex
            for (const rec of newFieldRecords) {
              rec.rowIndex = targetRowIndex
            }
            for (const field of existingFields) {
              if (field.rowIndex !== undefined && field.rowIndex >= targetRowIndex) {
                field.rowIndex = field.rowIndex + 1
              }
            }
          }
        }

        // Build the final fields array: existing fields + new field records
        // Find the insertion point in the flat array (after parent + its children)
        let flatInsertIndex = existingFields.length
        if (params.position && insertIndex < parentFields.length) {
          const targetParent = parentFields[insertIndex]
          flatInsertIndex = existingFields.indexOf(targetParent)
          if (flatInsertIndex === -1) flatInsertIndex = existingFields.length
        }

        const allFields = [
          ...existingFields.slice(0, flatInsertIndex),
          ...newFieldRecords,
          ...existingFields.slice(flatInsertIndex),
        ]

        // Recalculate positions for all fields
        allFields.forEach((field, index) => {
          field.position = index + 1
        })

        // 6. Build payload and save
        const updatePayload = {
          name: formData.name ?? '',
          description: formData.description || '',
          published: formData.published ?? false,
          showTitle: formData.showTitle ?? false,
          showDescription: formData.showDescription ?? false,
          storeEntries: formData.storeEntries ?? false,
          integrationSettings: formData.integrationSettings || {},
          fields: allFields,
          formActionButtons: formData.formActionButtons || {
            submitButtonSettings: { label: 'Submit', position: 'default' },
          },
        }
        const updateResult = await makeApiRequest(
          `form/update/${resolvedFormId}/`,
          {},
          'POST',
          updatePayload,
        )

        const success = updateResult?.data || updateResult

        let securityFieldInfo: Record<string, unknown> | null = null
        if (isSecurityFieldType(params.type)) {
          try {
            const settingsResponse = await makeApiRequest('settings/all')
            const settingsData =
              settingsResponse?.data?.data || settingsResponse?.data || settingsResponse || {}
            const providerSettings = settingsData?.security?.[params.type] || {}
            const siteKey =
              typeof providerSettings.siteKey === 'string' ? providerSettings.siteKey.trim() : ''
            const secretKey =
              typeof providerSettings.secretKey === 'string'
                ? providerSettings.secretKey.trim()
                : ''
            const isConfigured = siteKey.length > 0 && secretKey.length > 0

            securityFieldInfo = {
              provider: params.type,
              isConfigured,
              note: isConfigured
                ? 'Security provider appears configured (siteKey + secretKey found).'
                : 'Security provider is not configured yet. Field was added and will show the same not-configured warning state as in the manual builder until keys are set in Settings > Security.',
            }
          } catch (error) {
            console.warn('[IvyForms MCP] Could not verify security provider configuration:', error)
            securityFieldInfo = {
              provider: params.type,
              isConfigured: null,
              note: 'Security field was added, but provider configuration could not be verified automatically.',
            }
          }
        }

        return {
          content: [
            {
              type: 'text' as const,
              text: JSON.stringify(
                {
                  message: `Successfully added a "${params.type}" field ("${defaultLabel}") to form ${resolvedFormId} at position ${insertIndex + 1}. Please reload the page to see the changes.`,
                  formId: resolvedFormId,
                  adminLink: `${window.location.origin}/wp-admin/admin.php?page=ivyforms-builder#/manage/${resolvedFormId}`,
                  fieldType: params.type,
                  fieldLabel: defaultLabel,
                  position: insertIndex + 1,
                  totalFields: allFields.length,
                  reloadRequired: true,
                  securityFieldInfo,
                  apiResponse: success,
                },
                null,
                2,
              ),
            },
          ],
        }
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error)
        let apiError = ''
        if (typeof error === 'object' && error !== null && 'response' in error) {
          const axiosError = error as { response?: { data?: { message?: string } } }
          apiError = axiosError.response?.data?.message
            ? ` Server response: ${axiosError.response.data.message}`
            : ''
        }
        return {
          content: [
            {
              type: 'text' as const,
              text: `Failed to add field: ${errorMessage}${apiError}`,
            },
          ],
        }
      }
    },
  )

  // ──────────────────────────────────────────
  // Update form general settings
  // ──────────────────────────────────────────

  server.tool(
    'update-form-settings',
    'Update general settings for the current form or any form by ID. Automatically detects the current form from the builder context when formId is not provided. Settings: name, description, published, show title, show description, store entries. Only provided settings are changed — everything else is preserved. Do NOT call get-current-form-builder-context or wp-get-post before this tool — it handles context detection internally.',
    {
      formId: z
        .number()
        .optional()
        .describe(
          'Form ID to update. If omitted, auto-detects the form currently open in the builder.',
        ),
      name: z.string().optional().describe('New form name / title'),
      description: z.string().optional().describe('New form description'),
      published: z
        .boolean()
        .optional()
        .describe('Whether the form is published (true) or draft (false)'),
      showTitle: z.boolean().optional().describe('Show the form title on the frontend'),
      showDescription: z.boolean().optional().describe('Show the form description on the frontend'),
      storeEntries: z
        .boolean()
        .optional()
        .describe('Store form submissions/entries in the database'),
    },
    async (params) => {
      try {
        // 1. Resolve form ID — use provided or auto-detect from builder context
        let resolvedFormId = params.formId ?? null
        if (!resolvedFormId) {
          const ctx = getCurrentBuilderContext()
          resolvedFormId = ctx.formId
        }
        if (!resolvedFormId) {
          return {
            content: [
              {
                type: 'text' as const,
                text: 'Could not determine which form to update. Please provide a formId or navigate to a form in the builder first.',
              },
            ],
          }
        }

        // 2. Fetch current form data to preserve unchanged fields
        const formResponse = await makeApiRequest(`form/${resolvedFormId}`)
        const formData = formResponse?.data?.data ?? formResponse?.data
        if (!formData) {
          return {
            content: [{ type: 'text' as const, text: `Form with ID ${resolvedFormId} not found.` }],
          }
        }

        // 3. Merge only provided settings
        const updatedName = params.name ?? formData.name ?? ''
        const updatedDescription = params.description ?? formData.description ?? ''
        const updatedPublished = params.published ?? formData.published ?? false
        const updatedShowTitle = params.showTitle ?? formData.showTitle ?? false
        const updatedShowDescription = params.showDescription ?? formData.showDescription ?? false
        const updatedStoreEntries = params.storeEntries ?? formData.storeEntries ?? false

        // 4. Build full update payload preserving fields, integrations, buttons
        const updatePayload = {
          name: updatedName,
          description: updatedDescription,
          published: updatedPublished,
          showTitle: updatedShowTitle,
          showDescription: updatedShowDescription,
          storeEntries: updatedStoreEntries,
          integrationSettings: formData.integrationSettings || {},
          fields: formData.fields || [],
          formActionButtons: formData.formActionButtons || {
            submitButtonSettings: { label: 'Submit', position: 'default' },
          },
        }

        const updateResult = await makeApiRequest(
          `form/update/${resolvedFormId}/`,
          {},
          'POST',
          updatePayload,
        )

        // 5. Build a summary of what changed
        const changes: string[] = []
        if (params.name !== undefined) changes.push(`Name → "${updatedName}"`)
        if (params.description !== undefined) changes.push(`Description → "${updatedDescription}"`)
        if (params.published !== undefined) changes.push(`Published → ${updatedPublished}`)
        if (params.showTitle !== undefined) changes.push(`Show Title → ${updatedShowTitle}`)
        if (params.showDescription !== undefined)
          changes.push(`Show Description → ${updatedShowDescription}`)
        if (params.storeEntries !== undefined)
          changes.push(`Store Entries → ${updatedStoreEntries}`)

        // 6. Navigate to settings/general so the user sees the updated settings
        const settingsUrl = navigateToFormBuilder(resolvedFormId, 'settings/general')
        const formDisplayName = getFormDisplayName({ name: updatedName })

        return {
          content: [
            {
              type: 'text' as const,
              text: `Updated general settings for [${formDisplayName} (ID: ${resolvedFormId})](${settingsUrl}):\n${changes.map((change) => `- ${change}`).join('\n')}`,
            },
            {
              type: 'resource_link' as const,
              name: `ivyforms-form-settings-${resolvedFormId}`,
              title: `${formDisplayName} — Settings (ID: ${resolvedFormId})`,
              uri: settingsUrl,
              description: `Open general settings for form ${formDisplayName}`,
              mimeType: 'text/html',
            },
          ],
          structuredContent: {
            formId: resolvedFormId,
            settingsUrl,
            updatedSettings: {
              name: updatedName,
              description: updatedDescription,
              published: updatedPublished,
              showTitle: updatedShowTitle,
              showDescription: updatedShowDescription,
              storeEntries: updatedStoreEntries,
            },
            updateResponse: updateResult?.data || updateResult,
          },
        }
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error)
        let apiError = ''
        if (typeof error === 'object' && error !== null && 'response' in error) {
          const axiosError = error as { response?: { data?: { message?: string } } }
          apiError = axiosError.response?.data?.message
            ? ` Server response: ${axiosError.response.data.message}`
            : ''
        }
        return {
          content: [
            {
              type: 'text' as const,
              text: `Failed to update form settings: ${errorMessage}${apiError}`,
            },
          ],
        }
      }
    },
  )

  // ──────────────────────────────────────────
  // Entries (form submissions)
  // ──────────────────────────────────────────

  server.tool(
    'list-entries',
    'Get form entries/submissions. Use this when the user asks about form submissions, responses, or data collected through forms. IMPORTANT: present the returned linked list verbatim so each entry is a clickable link.',
    {
      formId: z.number().optional().describe('Filter entries by form ID'),
      page: z.number().min(1).optional().describe('Page number for pagination (default 1)'),
      perPage: z
        .number()
        .min(1)
        .max(100)
        .optional()
        .describe('Number of entries per page (default 20)'),
      search: z.string().optional().describe('Search entries'),
      orderBy: z.string().optional().describe('Field to order by'),
      order: z.enum(['ASC', 'DESC']).optional().describe('Sort direction'),
    },
    async ({ formId, page, perPage, search, orderBy, order }) => {
      const queryParams: Record<string, unknown> = {}

      if (formId) queryParams['filters[formId]'] = formId
      if (page) queryParams.page = page
      if (perPage) queryParams.perPage = perPage
      if (search) queryParams.search = search
      if (orderBy) queryParams.orderBy = orderBy
      if (order) queryParams.order = order

      const response = await makeApiRequest('entries/search', queryParams)

      // Response format: { message, data: { data: [...entries], meta, filterCount, entryFields, formIdToName } }
      const dataPayload = response?.data?.data ?? response?.data ?? response
      const entries = Array.isArray(dataPayload?.data)
        ? dataPayload.data
        : Array.isArray(dataPayload)
          ? dataPayload
          : null
      const meta = response?.data?.meta ?? dataPayload?.meta
      const filterCount = response?.data?.filterCount ?? dataPayload?.filterCount
      const formIdToName: Record<string, string> =
        response?.data?.formIdToName ?? dataPayload?.formIdToName ?? response?.formIdToName ?? {}

      const normalizedFormIdToName = Object.fromEntries(
        Object.entries(formIdToName)
          .map(([id, name]) => [parseFormIdValue(id), name])
          .filter(
            (pair): pair is [number, string] =>
              typeof pair[0] === 'number' &&
              pair[0] > 0 &&
              typeof pair[1] === 'string' &&
              pair[1].length > 0,
          ),
      )

      if (entries && Array.isArray(entries)) {
        const entriesWithLinks = entries
          .map((entry: EntryRecord) => {
            const entryId = typeof entry.id === 'number' ? entry.id : parseInt(String(entry.id), 10)
            if (isNaN(entryId)) return null

            const resolvedFormId = parseFormIdValue(entry.form_id ?? entry.formId ?? entry.form?.id)
            const formNameFromEntry =
              (typeof entry.form_name === 'string' && entry.form_name.trim().length > 0
                ? entry.form_name
                : null) ??
              (typeof entry.formName === 'string' && entry.formName.trim().length > 0
                ? entry.formName
                : null) ??
              (typeof entry.form?.name === 'string' && entry.form.name.trim().length > 0
                ? entry.form.name
                : null)

            const adminLink = getEntryAdminUrl(entryId)
            const formName =
              formNameFromEntry ??
              (resolvedFormId ? normalizedFormIdToName[resolvedFormId] : null) ??
              `Form ${resolvedFormId ?? '?'}`
            const createdAt =
              typeof entry.created_at === 'string' ? entry.created_at.split('T')[0] : ''
            const displayLabel = `Entry #${entryId} — ${formName}${createdAt ? ` (${createdAt})` : ''}`
            return {
              ...entry,
              entryId,
              formId: resolvedFormId,
              formName,
              adminLink,
              markdownLink: `[${displayLabel}](${adminLink})`,
            }
          })
          .filter(Boolean) as Array<Record<string, unknown>>

        const linkedEntriesMarkdown = entriesWithLinks
          .map((entry) => `- ${entry.markdownLink}\n  ${entry.adminLink}`)
          .join('\n')

        const entryResourceLinks = entriesWithLinks.map((entry) => ({
          type: 'resource_link' as const,
          name: `ivyforms-entry-${entry.entryId}`,
          title: String(entry.markdownLink).replace(/\[([^\]]+)\].*/, '$1'),
          uri: entry.adminLink as string,
          description: `Open entry #${entry.entryId} details`,
          mimeType: 'text/html',
        }))

        return {
          content: [
            ...entryResourceLinks,
            {
              type: 'text' as const,
              text:
                `Return this list exactly as written (do not paraphrase, keep links clickable):\n` +
                linkedEntriesMarkdown,
            },
          ],
          structuredContent: {
            totalCount: filterCount,
            meta,
          },
        }
      }

      const fallback = response ? JSON.stringify(response, null, 2) : 'No response payload.'

      return {
        content: [
          {
            type: 'text' as const,
            text: fallback,
          },
        ],
      }
    },
  )

  server.tool(
    'get-entry',
    'Get a single form entry/submission by its ID, including all field values.',
    {
      entryId: z.number().describe('Entry ID (required)'),
    },
    async ({ entryId }) => {
      try {
        const response = await makeApiRequest(`entry/${entryId}`)

        // Response format: { entry: {...}, fields: {...} }
        const entry = response?.entry
        const fields = response?.fields

        if (entry) {
          const adminLink = getEntryAdminUrl(entryId)
          return {
            content: [
              {
                type: 'text' as const,
                text: JSON.stringify({ entry: { ...entry, adminLink }, fields }, null, 2),
              },
            ],
          }
        }

        return {
          content: [
            {
              type: 'text' as const,
              text: `Entry with ID ${entryId} not found.`,
            },
          ],
        }
      } catch (error) {
        console.warn('[IvyForms MCP] get-entry failed:', error)
        return {
          content: [
            {
              type: 'text' as const,
              text: `Entry with ID ${entryId} not found or an error occurred.`,
            },
          ],
        }
      }
    },
  )

  server.tool(
    'get-entry-count',
    'Get the total number of entries/submissions for one or more form IDs. Use this for statistics or overview.',
    {
      formIds: z
        .array(z.number())
        .describe('One or more form IDs to get entry counts for (required)'),
    },
    async ({ formIds }) => {
      const queryParams: Record<string, unknown> = {
        id: formIds,
      }

      const response = await makeApiRequest('entries/count', queryParams)

      // Response format: { message, data: { counts: { formId: count } } }
      return {
        content: [
          {
            type: 'text' as const,
            text: JSON.stringify(response, null, 2),
          },
        ],
      }
    },
  )

  server.tool(
    'delete-entry',
    'Deletes a single entry/submission by its ID.',
    {
      entryId: z.number().describe('Entry ID to delete (required)'),
    },
    async ({ entryId }) => {
      const result = await makeApiRequest(`entry/delete/${entryId}`, {}, 'POST')

      return {
        content: [
          {
            type: 'text' as const,
            text: JSON.stringify(result, null, 2),
          },
        ],
      }
    },
  )

  // ──────────────────────────────────────────
  // Notifications
  // ──────────────────────────────────────────

  server.tool(
    'list-notifications',
    'Get all notifications configured for a specific form. Use this to see email notification settings.',
    {
      formId: z.number().describe('Form ID to get notifications for (required)'),
    },
    async ({ formId }) => {
      const response = await makeApiRequest(`notifications/${formId}`)

      // Response format: { message, data: [...notifications] }
      const notifications = response?.data

      if (notifications && Array.isArray(notifications)) {
        return {
          content: [
            {
              type: 'text' as const,
              text: JSON.stringify(notifications, null, 2),
            },
          ],
        }
      }
      const fallback = response ? JSON.stringify(response, null, 2) : 'No response payload.'

      return {
        content: [
          {
            type: 'text' as const,
            text: fallback,
          },
        ],
      }
    },
  )

  server.tool(
    'create-notification',
    'Creates a new email notification for a form. Use this when user wants to add email alerts on form submission.',
    {
      formId: z.number().describe('Form ID to add notification to (required)'),
      name: z.string().describe('Notification name (required)'),
      sender: z.string().optional().describe('Sender email address (default: {admin_email})'),
      receiver: z.string().optional().describe('Recipient email address (default: {admin_email})'),
      replyTo: z.string().optional().describe('Reply-to email address'),
      subject: z.string().optional().describe('Email subject line'),
      message: z.string().optional().describe('Email body/message (HTML allowed)'),
      enabled: z.boolean().optional().describe('Whether notification is enabled (default: true)'),
    },
    async ({ formId, name, sender, receiver, replyTo, subject, message, enabled }) => {
      const notificationData: Record<string, unknown> = {
        formId,
        name,
        sender: sender || '{admin_email}',
        receiver: receiver || '{admin_email}',
        replyTo: replyTo || '',
        subject: subject || 'New form submission: {form_name}',
        message: message || '{all_fields}',
        enabled: enabled !== false,
      }

      const result = await makeApiRequest('notification/add/', {}, 'POST', notificationData)

      return {
        content: [
          {
            type: 'text' as const,
            text: JSON.stringify(result, null, 2),
          },
        ],
      }
    },
  )

  server.tool(
    'get-settings',
    'Get all IvyForms plugin settings. Use this to check current configuration.',
    {},
    async () => {
      const response = await makeApiRequest('settings/all')

      return {
        content: [
          {
            type: 'text' as const,
            text: JSON.stringify(response, null, 2),
          },
        ],
      }
    },
  )

  // ──────────────────────────────────────────
  // Templates
  // ──────────────────────────────────────────

  server.tool(
    'list-templates',
    'Get all available form templates metadata (id, name, description, category, is_pro, screenshot). Use this to browse templates or find a template ID for create-form. For full template data including fields, use get-template.',
    {},
    async () => {
      const response = await makeApiRequest('templates')

      // Template endpoints are wrapped by Controller::__invoke, so payload can be nested.
      const templates =
        response?.data?.data?.templates || response?.data?.templates || response?.templates

      if (!templates || typeof templates !== 'object') {
        return {
          content: [
            {
              type: 'text' as const,
              text: 'Could not retrieve templates.',
            },
          ],
        }
      }

      // Backend returns an object keyed by template ID; normalize to array to help Angie parse it reliably.
      const normalizedTemplates = Array.isArray(templates)
        ? templates
        : Object.entries(templates as Record<string, Record<string, unknown>>).map(
            ([templateId, templateMeta]) => ({
              id: templateId,
              ...(templateMeta || {}),
            }),
          )

      const resultText = JSON.stringify(normalizedTemplates, null, 2)
      const chunks = splitText(resultText, 5000)

      return {
        content: chunks.map((chunk) => ({
          type: 'text' as const,
          text: chunk,
        })),
      }
    },
  )

  server.tool(
    'get-template',
    "Get full template data by ID, including all form fields and configuration. Use this when you need to inspect a specific template's structure before creating a form from it.",
    {
      templateId: z
        .string()
        .describe(
          'Template ID (e.g. "contact_form", "event_registration"). Use list-templates to see available IDs.',
        ),
    },
    async ({ templateId }) => {
      try {
        const response = await makeApiRequest(`template/${templateId}`)

        // Template endpoint is also wrapped by Controller::__invoke.
        const template = response?.data?.data || response?.data || response

        if (template) {
          return {
            content: [
              {
                type: 'text' as const,
                text: JSON.stringify(template, null, 2),
              },
            ],
          }
        }

        return {
          content: [
            {
              type: 'text' as const,
              text: `Template "${templateId}" not found. Use list-templates to see available template IDs.`,
            },
          ],
        }
      } catch (error) {
        console.warn('[IvyForms MCP] get-template failed:', error)
        return {
          content: [
            {
              type: 'text' as const,
              text: `Template "${templateId}" not found or an error occurred. Use list-templates to see available template IDs.`,
            },
          ],
        }
      }
    },
  )

  return server
}

const init = async () => {
  try {
    const server = createIvyFormsMcpServer()
    const sdk = new AngieMcpSdk()

    if (typeof sdk.waitForReady === 'function') {
      try {
        await sdk.waitForReady()
      } catch (error) {
        console.warn('[IvyForms MCP] waitForReady failed, continuing registration:', error)
      }
    }

    await sdk.registerServer({
      name: 'IvyForms',
      version: '1.0.0',
      description:
        'IvyForms - Contact Form Builder for WordPress. Manage forms, entries/submissions, notifications, settings, and templates. CRITICAL FORMATTING RULE: Whenever you list or mention forms (including filtered results like "forms with text fields"), always render each form as a clickable markdown link using adminLink/markdownLink from tool outputs; never return plain-text form names when a link exists. This rule applies even when user does not explicitly ask for links. For user prompts like "list all forms", call list-forms (or alias list-all-forms) first and present the returned linked list verbatim. Same rule applies to entries: when listing entries via list-entries, present the returned linked list verbatim so each entry is a clickable link. If the user asks to open or go to a specific form, use open-form-builder. If user asks to go to form settings, use open-form-builder with section="settings/general". If user asks to see form results/entries in the builder, use open-form-builder with section="results/entries". If the user asks to open or view a specific entry, use open-entry. If the user asks to add a field to a form, use add-field-to-form. If the user asks to change form settings (name, description, published, show title, show description, store entries), use update-form-settings. If the user asks to switch to dark mode, light mode, or change theme. Tools: list-forms, list-all-forms, get-current-form-builder-context, open-form-builder, get-form, create-form, duplicate-form, delete-form, add-field-to-form, update-form-settings, list-entries, get-entry, open-entry, get-entry-count, delete-entry, list-notifications, create-notification, get-settings, list-templates, get-template.',
      server,
    })
  } catch (error) {
    console.error('❌ [IvyForms MCP] Registration failed:', error)
  }
}

if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', init)
} else {
  init()
}
