import path from 'path';
import { checkTypeReference, isComponentName } from '../utils/index.js';

export default {
  meta: {
    type: 'problem',
    docs: {
      description:
        'Require a specific props type annotation (e.g., IComponentNameProps) for components, supporting React.FC and direct parameter annotation.',
      recommended: 'warn',
    },
    schema: [
      {
        type: 'object',
        properties: {
          requiredTypePrefix: { type: 'string', default: 'I' },
          requiredTypeSuffix: { type: 'string', default: 'Props' },
        },
        additionalProperties: false,
      },
    ],
    messages: {
      propsTypeMissing: `Props type for component '{{componentName}}' must include type '{{targetTypeName}}'.`,
      propsTypeMissingReactFC: `React.FC for component '{{componentName}}' must include props type parameter. Expected type includes '{{targetTypeName}}'.`,
    },
  },
  create(context) {
    const options = context.options[0] || {};
    const requiredTypePrefix = options.requiredTypePrefix ?? 'I';
    const requiredTypeSuffix = options.requiredTypeSuffix ?? 'Props';

    return {
      VariableDeclaration(node) {
        const filename = context.getFilename();
        const componentName = path.basename(filename, '.tsx');
        const targetTypeName = `${requiredTypePrefix}${componentName}${requiredTypeSuffix}`;
        const nodeId = node?.declarations[0]?.id;
        // Early return if no type annotation
        if (!isComponentName(nodeId?.name)) {
          return;
        }

        // Handle React.FC type annotation
        const typeAnnotation = nodeId?.typeAnnotation?.typeAnnotation;
        if (typeAnnotation?.type === 'TSTypeReference') {
          // Check if it's a React.FC
          if (typeAnnotation.typeArguments?.type === 'TSTypeParameterInstantiation' && typeAnnotation.typeArguments?.params.length > 0) {
            const propsTypeParam = typeAnnotation.typeArguments?.params[0];
            let foundTargetPropsType = false;
            // Check for intersection or union types
            if (propsTypeParam.type === 'TSIntersectionType' || propsTypeParam.type === 'TSUnionType') {
              for (const innerType of propsTypeParam.types) {
                if (checkTypeReference(innerType, targetTypeName)) {
                  foundTargetPropsType = true;
                  break;
                }
              }
            } else {
              // Check for direct type reference

              if (checkTypeReference(propsTypeParam, targetTypeName)) {
                foundTargetPropsType = true;
              }
            }

            // Report error if required type not found
            if (!foundTargetPropsType) {
              context.report({
                node: propsTypeParam,
                messageId: 'propsTypeMissing',
                data: {
                  componentName,
                  targetTypeName,
                },
              });
            }
          } else {
            // React.FC without props type parameter
            context.report({
              node: typeAnnotation,
              messageId: 'propsTypeMissingReactFC',
              data: {
                componentName,
                targetTypeName,
              },
            });
          }
        }
        // Handle direct parameter annotation in arrow functions
        else if (nodeId?.parent?.init?.type === 'ArrowFunctionExpression' && nodeId?.name === componentName) {
          // All params are passed to component is combined into a single props object
          const paramTypeAnnotation = nodeId?.parent?.init?.params?.[0]?.typeAnnotation?.typeAnnotation;
          const listTypes = paramTypeAnnotation?.types;
          let foundTargetPropsType = false;

          if (listTypes?.length > 0) {
            for (const typeParam of listTypes) {
              if (checkTypeReference(typeParam, targetTypeName)) {
                foundTargetPropsType = true;
                break;
              }
            }
          } else if (checkTypeReference(paramTypeAnnotation, targetTypeName)) {
            foundTargetPropsType = true;
          }

          if (!foundTargetPropsType) {
            context.report({
              node: paramTypeAnnotation || nodeId,
              messageId: 'propsTypeMissing',
              data: {
                componentName,
                targetTypeName,
              },
            });
          }
        }
      },
    };
  },
};
