/**
 * 类型守卫和类型断言工具
 * 用于替代 `any` 类型，提供更安全的类型检查
 */

/**
 * 检查值是否为普通对象（非 null、非数组）
 */
export function isPlainObject(value: unknown): value is Record<string, unknown> {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}

/**
 * 检查值是否为字符串
 */
export function isString(value: unknown): value is string {
  return typeof value === "string";
}

/**
 * 检查值是否为数字（有限）
 */
export function isFiniteNumber(value: unknown): value is number {
  return typeof value === "number" && Number.isFinite(value);
}

/**
 * 检查值是否为数组
 */
export function isArray<T = unknown>(value: unknown, itemGuard?: (item: unknown) => item is T): value is T[] {
  if (!Array.isArray(value)) return false;
  if (itemGuard) {
    return value.every(itemGuard);
  }
  return true;
}

/**
 * 检查对象是否包含指定的属性
 */
export function hasProperty<K extends string>(
  obj: unknown,
  key: K,
): obj is Record<K, unknown> {
  return isPlainObject(obj) && key in obj;
}

/**
 * 检查对象是否包含多个指定的属性
 */
export function hasProperties<K extends string>(
  obj: unknown,
  keys: K[],
): obj is Record<K, unknown> {
  if (!isPlainObject(obj)) return false;
  return keys.every(key => key in obj);
}

/**
 * 从对象中安全地提取字符串属性
 */
export function getStringProperty(obj: unknown, key: string, defaultValue: string = ""): string {
  if (!isPlainObject(obj)) return defaultValue;
  const value = obj[key];
  return isString(value) ? value : defaultValue;
}

/**
 * 从对象中安全地提取数字属性
 */
export function getNumberProperty(obj: unknown, key: string, defaultValue: number = 0): number {
  if (!isPlainObject(obj)) return defaultValue;
  const value = obj[key];
  return isFiniteNumber(value) ? value : defaultValue;
}

/**
 * 从对象中安全地提取布尔属性
 */
export function getBooleanProperty(obj: unknown, key: string, defaultValue: boolean = false): boolean {
  if (!isPlainObject(obj)) return defaultValue;
  const value = obj[key];
  return typeof value === "boolean" ? value : defaultValue;
}

/**
 * 从对象中安全地提取数组属性
 */
export function getArrayProperty<T = unknown>(
  obj: unknown,
  key: string,
  defaultValue: T[] = [],
): T[] {
  if (!isPlainObject(obj)) return defaultValue;
  const value = obj[key];
  return Array.isArray(value) ? value as T[] : defaultValue;
}

/**
 * 检查是否为 Supabase 行对象（包含 id 属性）
 */
export function isDatabaseRow(value: unknown): value is { id: string | number; [key: string]: unknown } {
  return isPlainObject(value) && ("id" in value);
}

/**
 * 检查是否为 Supabase 行数组
 */
export function isDatabaseRowArray(value: unknown): value is Array<{ id: string | number; [key: string]: unknown }> {
  return isArray(value) && value.every(isDatabaseRow);
}

/**
 * 类型断言：确保值不为 null/undefined
 */
export function assertNotNullOrUndefined<T>(value: T | null | undefined, message?: string): T {
  if (value === null || value === undefined) {
    throw new Error(message ?? "值不能为 null 或 undefined");
  }
  return value;
}

/**
 * 将 unknown 转换为 Record<string, unknown>，如果类型不匹配则返回空对象
 */
export function toRecord(value: unknown): Record<string, unknown> {
  return isPlainObject(value) ? value : {};
}

/**
 * 安全地访问嵌套对象属性
 * @example getNestedValue(obj, 'a.b.c') === obj?.a?.b?.c
 */
export function getNestedValue<T = unknown>(
  obj: unknown,
  path: string,
  defaultValue?: T,
): T | undefined {
  const keys = path.split(".");
  let current: unknown = obj;

  for (const key of keys) {
    if (!isPlainObject(current)) {
      return defaultValue;
    }
    current = current[key];
  }

  return current as T ?? defaultValue;
}

/**
 * 检查响应是否为错误响应
 */
export function isErrorResponse(value: unknown): value is { error: string; details?: unknown } {
  return isPlainObject(value) && isString(value.error);
}

/**
 * 从 unknown 类型中提取工具参数
 * 用于 AI agent 工具调用时的类型安全
 */
export function getToolArgs(args: unknown): Record<string, unknown> {
  if (isPlainObject(args)) {
    return args;
  }
  // 如果是数组或其他类型，返回空对象
  return {};
}

/**
 * 检查是否为 AI Agent 消息
 */
export function isAgentMessage(value: unknown): value is { role: "user" | "assistant"; content: string } {
  return (
    isPlainObject(value) &&
    (value.role === "user" || value.role === "assistant") &&
    isString(value.content)
  );
}

/**
 * 检查是否为 AI Agent 消息数组
 */
export function isAgentMessageArray(value: unknown): value is Array<{ role: "user" | "assistant"; content: string }> {
  return isArray(value) && value.every(isAgentMessage);
}
