import path from 'path';
import { isHookName } from '../utils/index.js';

/**
 * Rule: component/require-usememo-for-function-returns-jsx
 * Enforces the use of useMemo for functions that return JSX
 */
export default {
  meta: {
    type: 'suggestion',
    docs: {
      description: 'Enforces the use of useMemo for functions that return JSX',
    },
    messages: {
      wrapWithUseMemo:
        "Arrow function '{{ functionName }}' defined inside component '{{ componentName }}' should be wrapped in useMemo to ensure reference stability because it returns a JSX element.",
    },
  },
  create(context) {
    return {
      // Check for functions inside components
      VariableDeclarator(node) {
        const filename = context.getFilename();
        const componentName = path.basename(filename, '.tsx');

        // Skip if not the main component variable
        if (node.id?.name !== componentName) {
          return;
        }

        // Find functions that return JSX in the component body
        const componentBody = node?.init?.body?.body;
        if (!componentBody || !Array.isArray(componentBody)) {
          return;
        }

        // Check each statement in the component body
        for (const item of componentBody) {
          // Skip if not a variable declaration
          if (item.type !== 'VariableDeclaration' || !item.declarations || item.declarations.length === 0) {
            continue;
          }

          const declaration = item.declarations[0];

          // Check if it's a function wrapped in useCallback that returns JSX
          if (
            declaration?.init?.type === 'CallExpression' &&
            !isHookName(declaration?.id?.name) &&
            declaration?.init?.callee?.name === 'useCallback'
          ) {
            // Check if the function returns JSX
            const fnBody = declaration?.init?.arguments?.[0];
            const hasParams = fnBody?.params?.length > 0;
            if (hasParams) {
              continue;
            }
            const isReturnJSX =
              fnBody?.body?.type === 'JSXElement' || // Direct JSX return
              (fnBody?.body?.type === 'BlockStatement' &&
                fnBody?.body?.body?.find(item => item.type === 'ReturnStatement')?.argument?.type === 'JSXElement');
            if (isReturnJSX) {
              context.report({
                node: item,
                messageId: 'wrapWithUseMemo',
                data: {
                  functionName: declaration.id.name,
                  componentName,
                },
              });
            }
          }
        }
      },
    };
  },
};
