/**
 * @fileoverview Response builder utility for MCP tool handlers.
 * Provides a consistent way to build tool responses with proper error handling.
 * @packageDocumentation
 */

import { createLogger } from './logging/logger.js';

const logger = createLogger('DeepSourceMCP:ResponseBuilder');

/**
 * Response structure for MCP tools
 */
export interface ToolResponse {
  content: Array<{
    type: 'text';
    text: string;
  }>;
  structuredContent?: unknown;
  isError: boolean;
}

/**
 * Options for building a response
 */
export interface ResponseBuilderOptions {
  /** Whether to log the response */
  log?: boolean;
  /** Tool name for logging */
  toolName?: string;
  /** Structured content to include */
  structuredContent?: unknown;
}

/**
 * Builder class for creating consistent tool responses
 */
export class ToolResponseBuilder {
  private content: Array<{ type: 'text'; text: string }> = [];
  private isError = false;
  private structuredContent?: unknown;
  private options: ResponseBuilderOptions;

  constructor(options: ResponseBuilderOptions = {}) {
    this.options = options;
  }

  /**
   * Create a success response builder
   */
  static success(data: unknown, options?: ResponseBuilderOptions): ToolResponseBuilder {
    const builder = new ToolResponseBuilder(options);
    return builder.withData(data);
  }

  /**
   * Create an error response builder
   */
  static error(error: Error | string, options?: ResponseBuilderOptions): ToolResponseBuilder {
    const builder = new ToolResponseBuilder(options);
    return builder.withError(error);
  }

  /**
   * Add data to the response
   */
  withData(data: unknown): this {
    this.content.push({
      type: 'text',
      text: JSON.stringify(data),
    });

    if (this.options.log && this.options.toolName) {
      logger.info(`${this.options.toolName} response built successfully`);
    }

    return this;
  }

  /**
   * Add an error to the response
   */
  withError(error: Error | string): this {
    this.isError = true;
    const errorMessage = error instanceof Error ? error.message : error;

    this.content.push({
      type: 'text',
      text: JSON.stringify({
        error: errorMessage,
        details: 'Operation failed',
      }),
    });

    if (this.options.log && this.options.toolName) {
      logger.error(`${this.options.toolName} response contains error`, { error: errorMessage });
    }

    return this;
  }

  /**
   * Set structured content
   */
  withStructuredContent(content: unknown): this {
    this.structuredContent = content;
    return this;
  }

  /**
   * Build the final response
   */
  build(): ToolResponse {
    const response: ToolResponse = {
      content: this.content,
      isError: this.isError,
    };

    if (this.options.structuredContent !== undefined) {
      response.structuredContent = this.options.structuredContent;
    } else if (this.structuredContent !== undefined) {
      response.structuredContent = this.structuredContent;
    }

    return response;
  }
}

/**
 * Helper function to create a success response
 */
export function successResponse(data: unknown, options?: ResponseBuilderOptions): ToolResponse {
  return ToolResponseBuilder.success(data, options).build();
}

/**
 * Helper function to create an error response
 */
export function errorResponse(
  error: Error | string,
  options?: ResponseBuilderOptions
): ToolResponse {
  return ToolResponseBuilder.error(error, options).build();
}

/**
 * Helper function to parse and validate a tool response
 */
export function parseToolResponse<T = unknown>(
  response: ToolResponse,
  validator?: (data: unknown) => data is T
): T {
  if (response.isError) {
    if (!response.content || !response.content[0]) {
      throw new Error('Error response has no content');
    }
    const errorData = JSON.parse(response.content[0].text);
    throw new Error(errorData.error || 'Unknown error');
  }

  if (!response.content || !response.content[0]) {
    throw new Error('Response has no content');
  }
  const data = JSON.parse(response.content[0].text);

  if (validator && !validator(data)) {
    throw new Error('Response data failed validation');
  }

  return data as T;
}
