/**
 * ESLint rule to enforce Service function format
 *
 * Services in lib/services/ must:
 * 1. Be classes named *Service (not functions)
 * 2. Create their own dependencies (API Client, Logger, ErrorReporter)
 * 3. Return Result types
 * 4. NOT use redirect() or process.exit()
 * 5. CAN use console.error() for logging (allowed)
 */

module.exports = {
  meta: {
    type: 'problem',
    docs: {
      description: 'Enforce proper Service class format',
      category: 'Services',
      recommended: true,
    },
    fixable: null,
    schema: [],
    messages: {
      notAClass: 'Services must be classes named *Service, not functions. Found function "{{name}}" in lib/services/',
      noRedirect: 'Services cannot use redirect(). Use PageQueries or Client Components for navigation.',
      noProcessExit: 'Services cannot use process.exit().',
      multipleExports: 'Service files should only export the Service class.',
      mustReturnResult: 'Service methods must return Result<T, DomainError>.',
    },
  },

  create(context) {
    const filename = context.getFilename();
    const isInServices = filename.includes('/lib/services/');
    let hasRedirect = false;
    let hasProcessExit = false;
    let hasMultipleExports = false;
    let hasFunctionExport = false;
    let functionName = '';
    let hasResultReturningMethod = false;

    return {
      // Track function declarations
      FunctionDeclaration(node) {
        if (isInServices && node.id && node.id.name) {
          hasFunctionExport = true;
          functionName = node.id.name;
        }
      },

      // Track function expressions
      FunctionExpression(node) {
        if (isInServices && node.parent && node.parent.type === 'VariableDeclarator') {
          hasFunctionExport = true;
          functionName = node.parent.id.name;
        }
      },

      // Track arrow functions
      ArrowFunctionExpression(node) {
        if (isInServices && node.parent && node.parent.type === 'VariableDeclarator') {
          hasFunctionExport = true;
          functionName = node.parent.id.name;
        }
      },

      // Track redirect and process.exit calls
      CallExpression(node) {
        if (isInServices) {
          // Check for redirect()
          if (node.callee.type === 'Identifier' && node.callee.name === 'redirect') {
            hasRedirect = true;
          }
          
          // Check for process.exit()
          if (node.callee.type === 'MemberExpression' &&
              node.callee.object.type === 'Identifier' &&
              node.callee.object.name === 'process' &&
              node.callee.property.name === 'exit') {
            hasProcessExit = true;
          }
        }
      },

      // Track exports
      ExportNamedDeclaration(node) {
        if (isInServices) {
          if (node.declaration) {
            if (node.declaration.type === 'ClassDeclaration') {
              const className = node.declaration.id?.name;
              if (className && !className.endsWith('Service')) {
                hasMultipleExports = true;
              }
            } else if (node.declaration.type === 'FunctionDeclaration') {
              hasFunctionExport = true;
              functionName = node.declaration.id?.name || '';
            } else {
              // Interface, type alias, const, etc.
              hasMultipleExports = true;
            }
          } else if (node.specifiers && node.specifiers.length > 0) {
            hasMultipleExports = true;
          }
        }
      },

      // Check for Result-returning methods
      MethodDefinition(node) {
        if (isInServices && node.key.type === 'Identifier') {
          const returnType = node.value?.returnType;
          
          if (returnType &&
              returnType.typeAnnotation &&
              returnType.typeAnnotation.typeName &&
              returnType.typeAnnotation.typeName.name === 'Promise' &&
              returnType.typeAnnotation.typeParameters &&
              returnType.typeAnnotation.typeParameters.params.length > 0) {
            
            const resultType = returnType.typeAnnotation.typeParameters.params[0];
            
            if (resultType.type === 'TSTypeReference' &&
                resultType.typeName &&
                resultType.typeName.type === 'Identifier' &&
                resultType.typeName.name === 'Result') {
              hasResultReturningMethod = true;
            }
          }
        }
      },

      'Program:exit'() {
        if (!isInServices) return;

        // Check for function exports
        if (hasFunctionExport) {
          context.report({
            node: context.getSourceCode().ast,
            messageId: 'notAClass',
            data: { name: functionName },
          });
        }

        // Check for redirect
        if (hasRedirect) {
          context.report({
            node: context.getSourceCode().ast,
            messageId: 'noRedirect',
          });
        }

        // Check for process.exit
        if (hasProcessExit) {
          context.report({
            node: context.getSourceCode().ast,
            messageId: 'noProcessExit',
          });
        }

        // Check for multiple exports
        if (hasMultipleExports && !hasFunctionExport) {
          context.report({
            node: context.getSourceCode().ast,
            messageId: 'multipleExports',
          });
        }

        // Check for Result-returning methods (warn if none found)
        // Note: This is a soft check - services might have private methods that don't return Result
        // The important thing is that the public API methods do
      },
    };
  },
};
