/**
 * @fileoverview Base handler factory implementation for standardized handler creation
 * @packageDocumentation
 */

import {
  BaseHandlerDeps,
  HandlerFactory,
  HandlerFunction,
  HandlerError,
} from './handler.interface.js';
import { ApiResponse } from '../../models/common.js';
import { createLogger } from '../../utils/logging/logger.js';
import { DeepSourceClientFactory } from '../../client/factory.js';
import { getApiKey } from '../../config/index.js';

/**
 * Creates a base handler factory with common functionality
 * @template TParams - The handler parameters type
 * @template TResult - The handler result type
 * @param handlerName - The name of the handler for logging
 * @param handlerLogic - The actual handler implementation
 * @returns A handler factory function
 */
export function createBaseHandlerFactory<TParams = unknown, TResult = ApiResponse>(
  handlerName: string,

  handlerLogic: (deps: BaseHandlerDeps, params: TParams) => Promise<TResult>
): HandlerFactory<BaseHandlerDeps, TParams, TResult> {
  return (deps: BaseHandlerDeps): HandlerFunction<TParams, TResult> => {
    /**
     * The actual handler function that processes the request
     * @param params - The parameters passed to the handler
     * @returns Promise resolving to the handler result
     */
    const handler = async (params: TParams): Promise<TResult> => {
      const startTime = Date.now();

      try {
        // Log handler invocation
        deps.logger.info(`Handler ${handlerName} invoked`, {
          hasParams: params !== undefined && params !== null,
          ...(params && typeof params === 'object' ? { params } : {}),
        });

        // Execute the handler logic
        const result = await handlerLogic(deps, params);

        // Log successful completion
        const duration = Date.now() - startTime;
        deps.logger.info(`Handler ${handlerName} completed successfully`, {
          duration,
          ...(result && typeof result === 'object' && 'data' in result
            ? {
                resultCount: Array.isArray((result as Record<string, unknown>).data)
                  ? ((result as Record<string, unknown>).data as unknown[]).length
                  : 1,
              }
            : {}),
        });

        return result;
      } catch (error) {
        // Log error details
        const duration = Date.now() - startTime;
        deps.logger.error(`Handler ${handlerName} failed`, {
          duration,
          errorType: error instanceof Error ? error.constructor.name : typeof error,
          errorMessage: error instanceof Error ? error.message : String(error),
          errorStack: error instanceof Error ? error.stack : undefined,
        });

        // Re-throw the error for upstream handling
        throw error;
      }
    };
    return handler as HandlerFunction<TParams, TResult>;
  };
}

/**
 * Creates default handler dependencies
 * @param overrides - Optional overrides for specific dependencies
 * @returns The complete handler dependencies
 */
export function createDefaultHandlerDeps(overrides?: Partial<BaseHandlerDeps>): BaseHandlerDeps {
  const apiKey = getApiKey();

  return {
    clientFactory: new DeepSourceClientFactory(apiKey),
    logger: createLogger('Handler'),
    getApiKey,
    ...overrides,
  };
}

/**
 * Wraps a handler result in an ApiResponse format
 * @param data - The data to wrap
 * @returns An ApiResponse with the data as JSON text
 */
export function wrapInApiResponse<T>(data: T): ApiResponse {
  return {
    content: [
      {
        type: 'text' as const,
        text: JSON.stringify(data, null, 2),
      },
    ],
  };
}

/**
 * Creates an error ApiResponse
 * @param error - The error to convert
 * @param defaultMessage - Default message if error parsing fails
 * @returns An ApiResponse with error information
 */
export function createErrorResponse(
  error: unknown,
  defaultMessage = 'An unexpected error occurred'
): ApiResponse {
  let errorData: HandlerError;

  if (error instanceof Error) {
    // Check if it's a structured error with code
    if ('code' in error && typeof error.code === 'string') {
      errorData = {
        code: error.code,
        message: error.message,
      };
      if ('details' in error && error.details) {
        errorData.details = error.details as Record<string, unknown>;
      }
      if ('suggestions' in error && error.suggestions) {
        errorData.suggestions = error.suggestions as string[];
      }
    } else {
      // Generic error
      errorData = {
        code: 'HANDLER_ERROR',
        message: error.message || defaultMessage,
      };
    }
  } else {
    // Unknown error type
    errorData = {
      code: 'UNKNOWN_ERROR',
      message: String(error) || defaultMessage,
    };
  }

  return {
    isError: true,
    content: [
      {
        type: 'text' as const,
        text: JSON.stringify(errorData),
      },
    ],
  };
}

/**
 * Type guard to check if a value is an ApiResponse
 * @param value - The value to check
 * @returns True if the value is an ApiResponse
 */
export function isApiResponse(value: unknown): value is ApiResponse {
  return (
    value !== null &&
    typeof value === 'object' &&
    'content' in value &&
    Array.isArray((value as Record<string, unknown>).content)
  );
}
