import { OpenAPIV3 } from 'openapi-types';
import { RenderableSpecObject, RenderContext, RenderResultItem } from './types.js'; // Add .js
import { getOperationSummary, createErrorResult, generateListHint } from './utils.js'; // Add .js

/**
 * Wraps an OpenAPIV3.PathItemObject to make it renderable.
 * Handles rendering the list of methods for a specific path and
 * the details of specific operations (methods).
 */
export class RenderablePathItem implements RenderableSpecObject {
  constructor(
    private pathItem: OpenAPIV3.PathItemObject | undefined,
    private path: string, // The raw, decoded path string e.g., "/users/{userId}"
    private pathUriSuffix: string // Built using buildPathItemUriSuffix(path) e.g., 'paths/users%7BuserId%7D'
  ) {}

  /**
   * Renders a token-efficient list of methods available for this path.
   * Corresponds to the `openapi://paths/{path}` URI.
   */
  renderList(context: RenderContext): RenderResultItem[] {
    if (!this.pathItem) {
      return createErrorResult(this.pathUriSuffix, 'Path item not found.');
    }

    // Correctly check if the lowercase key is one of the enum values
    const methods = Object.keys(this.pathItem).filter(key =>
      Object.values(OpenAPIV3.HttpMethods).includes(key.toLowerCase() as OpenAPIV3.HttpMethods)
    ) as OpenAPIV3.HttpMethods[];

    // Check if methods array is empty *after* filtering
    if (methods.length === 0) {
      // Return a specific non-error message indicating no methods were found
      return [
        {
          uriSuffix: this.pathUriSuffix,
          data: `No standard HTTP methods found for path: ${decodeURIComponent(
            this.pathUriSuffix.substring('paths/'.length) // Get original path for display
          )}`,
          renderAsList: true,
          // isError is implicitly false here
        },
      ];
    }

    // Sort methods first to get the correct example
    methods.sort();
    const firstMethodExample = methods.length > 0 ? methods[0] : undefined;

    // Generate hint using the new structure, providing the first *sorted* method as an example
    const hint = generateListHint(context, {
      itemType: 'pathMethod',
      parentPath: this.path, // Use the stored raw path
      firstItemExample: firstMethodExample,
    });
    // Hint includes leading newline, so start output with it directly
    let outputLines: string[] = [hint.trim(), '']; // Trim leading newline from hint for first line

    // Iterate over the already sorted methods
    methods.forEach(method => {
      const operation = this.getOperation(method);
      // Use summary or operationId (via getOperationSummary)
      const summaryText = getOperationSummary(operation);
      // Format as METHOD: Summary or just METHOD if no summary/opId
      outputLines.push(`${method.toUpperCase()}${summaryText ? `: ${summaryText}` : ''}`);
    });

    return [
      {
        uriSuffix: this.pathUriSuffix,
        data: outputLines.join('\n'), // Join lines into a single string
        renderAsList: true,
      },
    ];
  }

  /**
   * Renders the detail view for one or more specific operations (methods)
   * Renders the detail view. For a PathItem, this usually means listing
   * the methods, similar to renderList. The handler should call
   * `renderOperationDetail` for specific method details.
   */
  renderDetail(context: RenderContext): RenderResultItem[] {
    // Delegate to renderList as the primary view for a path item itself.
    return this.renderList(context);
  }

  /**
   * Renders the detail view for one or more specific operations (methods)
   * within this path item.
   * Corresponds to the `openapi://paths/{path}/{method*}` URI.
   * This is called by the handler after identifying the method(s).
   *
   * @param context - The rendering context.
   * @param methods - Array of method names (e.g., ['get', 'post']).
   * @returns An array of RenderResultItem representing the operation details.
   */
  renderOperationDetail(
    _context: RenderContext, // Context might be needed later
    methods: string[]
  ): RenderResultItem[] {
    if (!this.pathItem) {
      // Create error results for all requested methods if path item is missing
      return methods.map(method => ({
        uriSuffix: `${this.pathUriSuffix}/${method}`,
        data: null,
        isError: true,
        errorText: 'Path item not found.',
        renderAsList: true,
      }));
    }

    const results: RenderResultItem[] = [];

    for (const method of methods) {
      const operation = this.getOperation(method);
      const operationUriSuffix = `${this.pathUriSuffix}/${method}`;

      if (!operation) {
        results.push({
          uriSuffix: operationUriSuffix,
          data: null,
          isError: true,
          errorText: `Method "${method.toUpperCase()}" not found for path.`,
          renderAsList: true,
        });
      } else {
        // Return the raw operation object; handler will format it
        results.push({
          uriSuffix: operationUriSuffix,
          data: operation,
          // isError: false (default)
          // renderAsList: false (default)
        });
      }
    }
    return results;
  }

  /**
   * Gets the OperationObject for a specific HTTP method within this path item.
   * Performs case-insensitive lookup.
   * @param method - The HTTP method string (e.g., 'get', 'POST').
   * @returns The OperationObject or undefined if not found.
   */
  getOperation(method: string): OpenAPIV3.OperationObject | undefined {
    if (!this.pathItem) {
      return undefined;
    }
    const lowerMethod = method.toLowerCase();

    // Check if the key is a standard HTTP method defined in the enum
    if (Object.values(OpenAPIV3.HttpMethods).includes(lowerMethod as OpenAPIV3.HttpMethods)) {
      const operation = this.pathItem[lowerMethod as keyof OpenAPIV3.PathItemObject];
      // Basic check to ensure it looks like an operation object
      if (typeof operation === 'object' && operation !== null && 'responses' in operation) {
        // The check above narrows the type sufficiently, assertion is redundant
        return operation;
      }
    }
    return undefined; // Not a valid method or not an operation object
  }
}
