import { extractReactTypes } from '../utils/index.js';

// Extract React types once at loading time
const reactTypes = extractReactTypes();

/**
 * Rule: react/proper-import-and-usage
 * Enforces proper import and usage of React types
 */
export default {
  meta: {
    type: 'problem',
    docs: {
      description: 'Enforces proper import and usage of React types',
    },
    messages: {
      notAllowed:
        'Named imports of React types like "{{ importedName }}" are not allowed. Use "import React from \'react\'" and reference the type as "React.{{ importedName }}".',
      missNamespace: 'Type "{{ typeName }}" must be used with namespace alias like React.{{ typeName }}.',
      missImportAlias:
        'Type "{{ typeName }}" must be used with namespace alias like React.{{ typeName }}. Import React with "import React from \'react\'" and use "React.{{ typeName }}".',
      missingImportReact: 'File uses React types but is missing "import React from \'react\';".',
    },
  },
  create(context) {
    let usesReactTypes = false;
    let hasReactImport = false;

    return {
      // Check for imports from 'react'
      ImportDeclaration(node) {
        if (node.source.value === 'react') {
          // Check for default import (import React from 'react')
          const hasDefaultImport = node.specifiers.some(specifier => specifier.type === 'ImportDefaultSpecifier' && specifier.local.name === 'React');

          if (hasDefaultImport) {
            hasReactImport = true;
          }

          // Check for named imports and disallow them for React types
          node.specifiers.forEach(specifier => {
            if (specifier.type === 'ImportSpecifier') {
              const importedName = specifier.imported.name;
              if (reactTypes.includes(`React.${importedName}`)) {
                context.report({
                  node: specifier,
                  messageId: 'notAllowed',
                  data: { importedName },
                });
              }
            }
          });
        }
      },

      // Check for React types in type references
      TSTypeReference(node) {
        // Skip nodes without typeName
        if (!node.typeName) {
          return;
        }

        // Handle qualified names like React.FC
        if (node.typeName.type === 'TSQualifiedName') {
          const left = node.typeName.left;
          const right = node.typeName.right;

          if (left.type === 'Identifier' && left.name === 'React' && right.type === 'Identifier') {
            const fullTypeName = `React.${right.name}`;
            if (reactTypes.includes(fullTypeName)) {
              usesReactTypes = true;
            }
          }
        }
        // Handle direct React types like FC (without namespace)
        else if (node.typeName.type === 'Identifier') {
          const typeNameStr = node.typeName.name;
          if (reactTypes.includes(`React.${typeNameStr}`)) {
            usesReactTypes = true;
            context.report({
              node,
              messageId: 'missNamespace',
              data: { typeName: typeNameStr },
            });
          }
        }
      },

      // Check for React types in variable declarations
      VariableDeclaration(node) {
        node.declarations.forEach(decl => {
          if (!decl.id.typeAnnotation) {
            return;
          }

          const typeAnnotation = decl.id.typeAnnotation.typeAnnotation;
          if (typeAnnotation.type === 'TSTypeReference') {
            const typeName = typeAnnotation.typeName;

            // Check for React.X type
            if (typeName.type === 'TSQualifiedName') {
              const left = typeName.left;
              const right = typeName.right;

              if (left.type === 'Identifier' && left.name === 'React' && right.type === 'Identifier') {
                const fullTypeName = `React.${right.name}`;
                if (reactTypes.includes(fullTypeName)) {
                  usesReactTypes = true;
                }
              }
            }
            // Check for direct React type without namespace
            else if (typeName.type === 'Identifier') {
              const typeNameStr = typeName.name;
              if (reactTypes.includes(`React.${typeNameStr}`)) {
                usesReactTypes = true;
                context.report({
                  node,
                  messageId: 'missImportAlias',
                  data: { typeName: typeNameStr },
                });
              }
            }
          }
        });
      },

      // Final check after processing the file
      'Program:exit'(node) {
        if (usesReactTypes && !hasReactImport) {
          context.report({
            node,
            messageId: 'missingImportReact',
          });
        }
      },
    };
  },
};
