module.exports = {
  meta: {
    docs: {
      description:
        'next/script components with inline content must specify an `id` attribute.',
      recommended: true,
      url: 'https://nextjs.org/docs/messages/inline-script-id',
    },
  },
  create: function (context) {
    let nextScriptImportName = null

    return {
      ImportDeclaration(node) {
        if (node.source.value === 'next/script') {
          nextScriptImportName = node.specifiers[0].local.name
        }
      },
      JSXElement(node) {
        if (nextScriptImportName == null) return

        if (
          node.openingElement &&
          node.openingElement.name &&
          node.openingElement.name.name !== nextScriptImportName
        ) {
          return
        }

        const attributeNames = new Set()

        let hasNonCheckableSpreadAttribute = false
        node.openingElement.attributes.forEach((attribute) => {
          // Early return if we already have a non-checkable spread attribute, for better performance
          if (hasNonCheckableSpreadAttribute) return

          if (attribute.type === 'JSXAttribute') {
            attributeNames.add(attribute.name.name)
          } else if (attribute.type === 'JSXSpreadAttribute') {
            if (attribute.argument && attribute.argument.properties) {
              attribute.argument.properties.forEach((property) => {
                attributeNames.add(property.key.name)
              })
            } else {
              // JSXSpreadAttribute without properties is not checkable
              hasNonCheckableSpreadAttribute = true
            }
          }
        })

        // https://github.com/vercel/next.js/issues/34030
        // If there is a non-checkable spread attribute, we simply ignore them
        if (hasNonCheckableSpreadAttribute) return

        if (
          node.children.length > 0 ||
          attributeNames.has('dangerouslySetInnerHTML')
        ) {
          if (!attributeNames.has('id')) {
            context.report({
              node,
              message:
                'next/script components with inline content must specify an `id` attribute. See: https://nextjs.org/docs/messages/inline-script-id',
            })
          }
        }
      },
    }
  },
}
