/**
 * ESLint Rule: Server Actions Must Return Result Type
 *
 * Ensures server actions return Result<T, E> types instead of arbitrary objects
 * This enforces the standardized error handling pattern across all server actions
 */

module.exports = {
  meta: {
    type: 'problem',
    docs: {
      description: 'Ensure server actions return Result<T, E> types from lib/contracts/Result.ts',
      category: 'Server Actions',
      recommended: true,
    },
    messages: {
      mustReturnResult: 'Server actions must return Result<T, E> type. Expected: Promise<Result<SuccessType, ErrorType>>',
      invalidReturnType: 'Return type must be Result<T, E> or Promise<Result<T, E>>',
      missingResultImport: 'Server actions must import Result from @/lib/contracts/Result',
    },
    schema: [],
  },

  create(context) {
    const filename = context.getFilename();
    const isServerActionFile = filename.includes('/app/') && 
                               (filename.endsWith('.ts') || filename.endsWith('.tsx')) &&
                               !filename.endsWith('.test.ts') &&
                               !filename.endsWith('.test.tsx');

    if (!isServerActionFile) {
      return {};
    }

    let hasUseServerDirective = false;
    let hasResultImport = false;
    const functionDeclarations = [];

    return {
      // Check for 'use server' directive
      ExpressionStatement(node) {
        if (node.expression.type === 'Literal' && node.expression.value === 'use server') {
          hasUseServerDirective = true;
        }
      },

      // Check for Result import
      ImportDeclaration(node) {
        const importPath = node.source.value;
        if (importPath === '@/lib/contracts/Result' || importPath === '@/lib/contracts/Result.ts') {
          hasResultImport = true;
        }
      },

      // Track function declarations and exports
      FunctionDeclaration(node) {
        if (node.async && node.id && node.id.name) {
          functionDeclarations.push({
            name: node.id.name,
            node: node,
            returnType: node.returnType,
            body: node.body,
          });
        }
      },

      // Track arrow function exports
      ExportNamedDeclaration(node) {
        if (node.declaration && node.declaration.type === 'FunctionDeclaration') {
          if (node.declaration.async && node.declaration.id) {
            functionDeclarations.push({
              name: node.declaration.id.name,
              node: node.declaration,
              returnType: node.declaration.returnType,
              body: node.declaration.body,
            });
          }
        } else if (node.declaration && node.declaration.type === 'VariableDeclaration') {
          node.declaration.declarations.forEach(decl => {
            if (decl.init && decl.init.type === 'ArrowFunctionExpression' && decl.init.async) {
              functionDeclarations.push({
                name: decl.id.name,
                node: decl.init,
                returnType: decl.init.returnType,
                body: decl.init.body,
              });
            }
          });
        }
      },

      'Program:exit'() {
        // Only check files with 'use server' directive
        if (!hasUseServerDirective) return;

        // Report if no Result import
        if (!hasResultImport) {
          context.report({
            node: context.getSourceCode().ast,
            messageId: 'missingResultImport',
          });
        }

        // Check each server action function
        functionDeclarations.forEach(func => {
          const returnType = func.returnType;

          // Check if return type annotation exists and is correct
          if (!returnType) {
            context.report({
              node: func.node,
              messageId: 'mustReturnResult',
            });
            return;
          }

          // Helper function to check if a type is Result
          function isResultType(typeNode) {
            if (!typeNode) return false;
            
            // Direct Result type
            if (typeNode.typeName && typeNode.typeName.name === 'Result') {
              return true;
            }
            
            // Promise<Result<...>>
            if (typeNode.typeName && typeNode.typeName.name === 'Promise') {
              const typeParams = typeNode.typeParameters || typeNode.typeArguments;
              if (typeParams && typeParams.params && typeParams.params[0]) {
                return isResultType(typeParams.params[0]);
              }
            }
            
            return false;
          }

          // Check if it's a Promise<Result<...>> or Result<...>
          if (returnType.typeAnnotation) {
            const typeAnnotation = returnType.typeAnnotation;
            
            if (isResultType(typeAnnotation)) {
              // Valid: Result<...> or Promise<Result<...>>
              return;
            } else if (typeAnnotation.type === 'TSUnionType') {
              // Check if union contains only Result types
              const hasNonResult = typeAnnotation.types.some(type => !isResultType(type));
              if (hasNonResult) {
                context.report({
                  node: returnType,
                  messageId: 'invalidReturnType',
                });
              }
            } else {
              context.report({
                node: returnType,
                messageId: 'invalidReturnType',
              });
            }
          } else {
            context.report({
              node: returnType,
              messageId: 'invalidReturnType',
            });
          }
        });
      },
    };
  },
};