import type { ErrorContext } from './types';

/**
 * E2E 测试专用错误类
 *
 * @description
 * 提供结构化的错误上下文信息，帮助开发者快速定位问题。
 *
 * @example
 * ```ts
 * throw new E2ETestError({
 *   operation: 'selectRadixOption',
 *   target: '残疾类型',
 *   expected: '视力残疾',
 *   available: ['听力残疾', '言语残疾', '肢体残疾']
 * });
 * ```
 */
export class E2ETestError extends Error {
  /**
   * 创建一个 E2E 测试错误实例
   *
   * @param context - 结构化的错误上下文
   * @param message - 自定义错误消息（可选，默认自动生成）
   */
  constructor(
    public readonly context: ErrorContext,
    message?: string
  ) {
    super(message || formatErrorMessage(context));
    this.name = 'E2ETestError';
  }
}

/**
 * 格式化错误消息为友好格式
 *
 * @description
 * 内部函数，用于将 ErrorContext 转换为易读的错误消息。
 *
 * @internal
 *
 * @param context - 错误上下文
 * @returns 格式化后的错误消息
 */
function formatErrorMessage(context: ErrorContext): string {
  const parts: string[] = [
    `❌ ${context.operation} failed`,
    `Target: ${context.target}`
  ];

  if (context.expected) {
    parts.push(`Expected: ${context.expected}`);
  }

  if (context.actual) {
    parts.push(`Actual: ${context.actual}`);
  }

  if (context.available && context.available.length > 0) {
    parts.push(`Available: ${context.available.join(', ')}`);
  }

  if (context.suggestion) {
    parts.push(`\n💡 ${context.suggestion}`);
  }

  return parts.join('\n');
}

/**
 * 抛出 E2E 测试错误的辅助函数
 *
 * @description
 * 便捷函数，用于抛出带上下文的 E2E 测试错误。永远抛出错误，返回类型为 `never`。
 *
 * @example
 * ```ts
 * if (!optionFound) {
 *   throwError({
 *     operation: 'selectRadixOption',
 *     target: label,
 *     expected: value,
 *     available: availableOptions,
 *     suggestion: '检查选项值是否正确'
 *   });
 * }
 * ```
 *
 * @param context - 错误上下文
 * @throws {E2ETestError} 永远抛出错误
 */
export function throwError(context: ErrorContext): never {
  throw new E2ETestError(context);
}
