import { Observable, firstValueFrom } from 'rxjs';
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
import { logger } from '@isa/core/logging';

// Lazy logger initialization to avoid injection context issues at module load time
const getApiLogger = () => logger(() => ({ module: 'AvailabilityApiHelpers' }));

/**
 * Context information for error logging during API calls.
 */
export interface AvailabilityApiErrorContext {
  /** Order type being fetched (e.g., 'Versand', 'DIG-Versand') */
  orderType: string;
  /** Item IDs being requested */
  itemIds: number[];
  /** Additional context (e.g., branchId, shopId) */
  additional?: Record<string, unknown>;
}

/**
 * Generic API response structure from generated services.
 */
export interface ApiResponse<T> {
  result?: T | null;
  error?: unknown;
}

/**
 * Executes an availability API call with standardized error handling and abort support.
 *
 * This helper centralizes the common pattern of:
 * 1. Adding abort signal support to the request
 * 2. Awaiting the Observable response
 * 3. Checking for errors and throwing ResponseArgsError
 * 4. Logging errors with context
 * 5. Returning the result
 *
 * @param request$ - Observable API request to execute
 * @param abortSignal - Optional abort signal for request cancellation
 * @param errorContext - Context information for error logging
 * @returns The API response result
 * @throws ResponseArgsError if the API returns an error
 *
 * @example
 * ```typescript
 * const availabilities = await executeAvailabilityApiCall(
 *   this.#service.AvailabilityShippingAvailability(request),
 *   abortSignal,
 *   { orderType: 'Versand', itemIds: [123, 456] }
 * );
 * ```
 */
export async function executeAvailabilityApiCall<T>(
  request$: Observable<ApiResponse<T>>,
  abortSignal: AbortSignal | undefined,
  errorContext: AvailabilityApiErrorContext,
): Promise<T> {
  // Add abort signal support if provided
  let req$ = request$;
  if (abortSignal) {
    req$ = req$.pipe(takeUntilAborted(abortSignal));
  }

  // Execute the request
  const res = await firstValueFrom(req$);

  // Check for errors
  if (res.error) {
    const err = new ResponseArgsError({
      error: true,
      message: typeof res.error === 'string' ? res.error : 'An error occurred',
    });
    getApiLogger().error(
      `Failed to get ${errorContext.orderType} availability`,
      err,
      () => ({
        orderType: errorContext.orderType,
        itemIds: errorContext.itemIds,
        ...errorContext.additional,
      }),
    );
    throw err;
  }

  // Return result (cast needed because API response might be null)
  return res.result as T;
}

/**
 * Safely converts an itemId to a string for use as dictionary key.
 *
 * This helper ensures consistent string conversion of itemIds across the service.
 * Returns empty string if itemId is undefined (should be filtered out earlier).
 *
 * @param itemId - Item ID to convert
 * @returns String representation of itemId
 *
 * @example
 * ```typescript
 * const key = convertItemIdToString(123); // Returns: '123'
 * const invalid = convertItemIdToString(undefined); // Returns: ''
 * ```
 */
export function convertItemIdToString(itemId: number | undefined): string {
  return String(itemId ?? '');
}
