/**
 * ESLint rule to prefer SDK components over native HTML elements
 * @fileoverview Enforce using Shop Minis SDK components instead of native HTML
 */

module.exports = {
  meta: {
    type: 'suggestion',
    docs: {
      description:
        'Prefer Shop Minis SDK components over native HTML elements for better functionality and styling',
      category: 'Best Practices',
      recommended: true,
    },
    fixable: 'code',
    messages: {
      preferSdkComponent:
        'Use <{{sdkComponent}}> from @shopify/shop-minis-react instead of <{{nativeElement}}>. The SDK component provides optimized performance, consistent styling, and additional features.',
    },
    schema: [
      {
        type: 'object',
        properties: {
          components: {
            type: 'object',
            description: 'Map of native elements to SDK components',
            additionalProperties: {
              type: 'string',
            },
          },
        },
        additionalProperties: false,
      },
    ],
  },

  create(context) {
    // Default component mappings
    const defaultComponents = {
      img: 'Image',
      button: 'Button',
      label: 'Label',
      // Future additions will go here:
      // input: 'Input',
      // a: 'Link',
    }

    // Get user configuration or use defaults
    const options = context.options[0] || {}
    const componentMap = {
      ...defaultComponents,
      ...(options.components || {}),
    }

    // eslint-disable-next-line @shopify/prefer-module-scope-constants
    const SDK_PACKAGE = '@shopify/shop-minis-react'

    return {
      JSXOpeningElement(node) {
        const elementName = node.name.name

        // Check if this is a native element we want to replace
        if (componentMap[elementName]) {
          const sdkComponent = componentMap[elementName]

          context.report({
            node,
            messageId: 'preferSdkComponent',
            data: {
              nativeElement: elementName,
              sdkComponent,
            },
            fix(fixer) {
              const sourceCode = context.getSourceCode()
              const openingElement = node
              const jsxElement = node.parent

              // Get the closing element if it exists
              const closingElement = jsxElement.closingElement

              const fixes = []

              // Fix opening tag
              const openingTagStart = openingElement.name.range[0]
              const openingTagEnd = openingElement.name.range[1]
              fixes.push(
                fixer.replaceTextRange(
                  [openingTagStart, openingTagEnd],
                  sdkComponent
                )
              )

              // Fix closing tag if it exists (not self-closing)
              if (closingElement) {
                const closingTagStart = closingElement.name.range[0]
                const closingTagEnd = closingElement.name.range[1]
                fixes.push(
                  fixer.replaceTextRange(
                    [closingTagStart, closingTagEnd],
                    sdkComponent
                  )
                )
              }

              // Add import if it doesn't exist
              const program = sourceCode.ast
              const imports = program.body.filter(
                importNode => importNode.type === 'ImportDeclaration'
              )

              // Check if we already import from the SDK
              const sdkImport = imports.find(
                importNode => importNode.source.value === SDK_PACKAGE
              )

              if (sdkImport) {
                // Check if this component is already imported
                const hasComponent = sdkImport.specifiers.some(
                  spec =>
                    spec.type === 'ImportSpecifier' &&
                    spec.imported.name === sdkComponent
                )

                if (!hasComponent) {
                  // Add component to existing import
                  const lastSpecifier =
                    sdkImport.specifiers[sdkImport.specifiers.length - 1]
                  fixes.push(
                    fixer.insertTextAfter(lastSpecifier, `, ${sdkComponent}`)
                  )
                }
              } else {
                // Add new import statement
                const firstNode = program.body[0]
                const importStatement = `import {${sdkComponent}} from '${SDK_PACKAGE}'\n`

                if (firstNode) {
                  fixes.push(fixer.insertTextBefore(firstNode, importStatement))
                } else {
                  fixes.push(
                    fixer.insertTextAfterRange([0, 0], importStatement)
                  )
                }
              }

              return fixes
            },
          })
        }
      },
    }
  },
}
