/**
 * MessageUtils.ets
 *
 * 消息工具函数集合
 *
 * 提供常用的批量操作、过滤、查找等实用功能
 *
 * 设计理念:
 * - 纯函数设计,无副作用
 * - 泛型支持,类型安全
 * - 符合 ArkTS 2025 规范
 *
 * Version: 1.0.0
 * ArkTS 2025 兼容
 */

import { Message } from './Message'

/**
 * 消息工具函数类
 *
 * 提供批量操作、过滤、分组等实用功能
 *
 * 所有方法都是静态方法,无需实例化
 */
export class MessageUtils {
  // ========== 批量操作 ==========

  /**
   * 批量序列化消息为二进制
   *
   * @param messages 消息数组
   * @returns 二进制数据数组
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, person2, person3]
   * const binaries = MessageUtils.toBinaryBatch(people)
   * ```
   */
  static toBinaryBatch<T extends Message>(messages: T[]): Uint8Array[] {
    return messages.map(m => m.toBinary())
  }

  /**
   * 批量转换消息为 JSON
   *
   * @param messages 消息数组
   * @returns JSON 对象数组
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, person2, person3]
   * const jsonArray = MessageUtils.toJsonBatch(people)
   * ```
   */
  static toJsonBatch<T extends Message>(messages: T[]): Record<string, Object>[] {
    return messages.map(m => m.toJson())
  }

  /**
   * 批量克隆消息
   *
   * @param messages 消息数组
   * @returns 克隆后的消息数组
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, person2, person3]
   * const clonedPeople = MessageUtils.cloneBatch(people)
   * ```
   */
  static cloneBatch<T extends Message>(messages: T[]): T[] {
    return messages.map(m => m.clone() as T)
  }

  // ========== 合并操作 ==========

  /**
   * 深度合并多个消息(后面的覆盖前面的)
   *
   * 合并语义(Protobuf 标准):
   * - 标量字段:后面的覆盖前面的
   * - repeated 字段:追加(不是替换!)
   * - 嵌套消息:递归合并
   *
   * @param messages 消息数组
   * @returns 合并后的消息,如果数组为空则返回 null
   *
   * 使用示例:
   * ```typescript
   * const base = Person.create({ name: 'Alice', age: 30 })
   * const update1 = Person.create({ age: 31 })
   * const update2 = Person.create({ emails: ['alice@example.com'] })
   * const merged = MessageUtils.mergeAll([base, update1, update2])
   * // merged: { name: 'Alice', age: 31, emails: ['alice@example.com'] }
   * ```
   */
  static mergeAll<T extends Message>(messages: T[]): T | null {
    if (messages.length === 0) {
      return null
    }

    const result = messages[0].clone() as T
    for (let i = 1; i < messages.length; i++) {
      result.mergeFrom(messages[i])
    }
    return result
  }

  // ========== 验证和过滤 ==========

  /**
   * 过滤有效消息
   *
   * @param messages 消息数组
   * @returns 只包含有效消息的数组
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, invalidPerson, person3]
   * const validPeople = MessageUtils.filterValid(people)
   * // validPeople: [person1, person3]
   * ```
   */
  static filterValid<T extends Message>(messages: T[]): T[] {
    return messages.filter(m => m.isValid())
  }

  /**
   * 过滤无效消息
   *
   * @param messages 消息数组
   * @returns 只包含无效消息的数组
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, invalidPerson, person3]
   * const invalidPeople = MessageUtils.filterInvalid(people)
   * // invalidPeople: [invalidPerson]
   * ```
   */
  static filterInvalid<T extends Message>(messages: T[]): T[] {
    return messages.filter(m => !m.isValid())
  }

  /**
   * 过滤非空消息
   *
   * @param messages 消息数组
   * @returns 只包含非空消息的数组
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, emptyPerson, person3]
   * const nonEmptyPeople = MessageUtils.filterNonEmpty(people)
   * // nonEmptyPeople: [person1, person3]
   * ```
   */
  static filterNonEmpty<T extends Message>(messages: T[]): T[] {
    return messages.filter(m => !m.isEmpty())
  }

  // ========== 查找操作 ==========

  /**
   * 查找第一个无效消息
   *
   * @param messages 消息数组
   * @returns 第一个无效消息,如果都有效则返回 null
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, invalidPerson, person3]
   * const invalid = MessageUtils.findInvalid(people)
   * if (invalid !== null) {
   *   console.error('Found invalid message:', invalid.validate())
   * }
   * ```
   */
  static findInvalid<T extends Message>(messages: T[]): T | null {
    const found = messages.find(m => !m.isValid())
    return found !== undefined ? found : null
  }

  /**
   * 查找第一个有效消息
   *
   * @param messages 消息数组
   * @returns 第一个有效消息,如果都无效则返回 null
   *
   * 使用示例:
   * ```typescript
   * const people = [invalidPerson1, validPerson, invalidPerson2]
   * const valid = MessageUtils.findValid(people)
   * ```
   */
  static findValid<T extends Message>(messages: T[]): T | null {
    const found = messages.find(m => m.isValid())
    return found !== undefined ? found : null
  }

  /**
   * 查找第一个空消息
   *
   * @param messages 消息数组
   * @returns 第一个空消息,如果都非空则返回 null
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, emptyPerson, person3]
   * const empty = MessageUtils.findEmpty(people)
   * ```
   */
  static findEmpty<T extends Message>(messages: T[]): T | null {
    const found = messages.find(m => m.isEmpty())
    return found !== undefined ? found : null
  }

  // ========== 判断操作 ==========

  /**
   * 判断所有消息是否都有效
   *
   * @param messages 消息数组
   * @returns true 如果所有消息都有效
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, person2, person3]
   * if (MessageUtils.allValid(people)) {
   *   console.log('All messages are valid')
   * }
   * ```
   */
  static allValid<T extends Message>(messages: T[]): boolean {
    return messages.every(m => m.isValid())
  }

  /**
   * 判断是否存在无效消息
   *
   * @param messages 消息数组
   * @returns true 如果存在至少一个无效消息
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, invalidPerson, person3]
   * if (MessageUtils.hasInvalid(people)) {
   *   console.warn('Found invalid messages')
   * }
   * ```
   */
  static hasInvalid<T extends Message>(messages: T[]): boolean {
    return messages.some(m => !m.isValid())
  }

  /**
   * 判断所有消息是否都为空
   *
   * @param messages 消息数组
   * @returns true 如果所有消息都为空
   *
   * 使用示例:
   * ```typescript
   * const people = [emptyPerson1, emptyPerson2]
   * if (MessageUtils.allEmpty(people)) {
   *   console.log('All messages are empty')
   * }
   * ```
   */
  static allEmpty<T extends Message>(messages: T[]): boolean {
    return messages.every(m => m.isEmpty())
  }

  /**
   * 判断是否存在非空消息
   *
   * @param messages 消息数组
   * @returns true 如果存在至少一个非空消息
   *
   * 使用示例:
   * ```typescript
   * const people = [emptyPerson, person1, emptyPerson2]
   * if (MessageUtils.hasNonEmpty(people)) {
   *   console.log('Found non-empty messages')
   * }
   * ```
   */
  static hasNonEmpty<T extends Message>(messages: T[]): boolean {
    return messages.some(m => !m.isEmpty())
  }

  // ========== 分组操作 ==========
  
  // groupBy 和 countBy 被移除,因为 ArkTS 不支持动态索引访问和 Keyof 泛型索引

  // ========== 统计操作 ==========

  /**
   * 统计有效消息数量
   *
   * @param messages 消息数组
   * @returns 有效消息的数量
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, invalidPerson, person3]
   * const validCount = MessageUtils.countValid(people)
   * // validCount: 2
   * ```
   */
  static countValid<T extends Message>(messages: T[]): number {
    return messages.filter(m => m.isValid()).length
  }

  /**
   * 统计无效消息数量
   *
   * @param messages 消息数组
   * @returns 无效消息的数量
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, invalidPerson, person3]
   * const invalidCount = MessageUtils.countInvalid(people)
   * // invalidCount: 1
   * ```
   */
  static countInvalid<T extends Message>(messages: T[]): number {
    return messages.filter(m => !m.isValid()).length
  }

  /**
   * 统计空消息数量
   *
   * @param messages 消息数组
   * @returns 空消息的数量
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, emptyPerson, person3]
   * const emptyCount = MessageUtils.countEmpty(people)
   * // emptyCount: 1
   * ```
   */
  static countEmpty<T extends Message>(messages: T[]): number {
    return messages.filter(m => m.isEmpty()).length
  }

  /**
   * 统计非空消息数量
   *
   * @param messages 消息数组
   * @returns 非空消息的数量
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, emptyPerson, person3]
   * const nonEmptyCount = MessageUtils.countNonEmpty(people)
   * // nonEmptyCount: 2
   * ```
   */
  static countNonEmpty<T extends Message>(messages: T[]): number {
    return messages.filter(m => !m.isEmpty()).length
  }

  // ========== 转换操作 ==========
  
  // pluck 被移除,因为 ArkTS 不支持动态索引访问

  /**
   * 去重(基于二进制比较)
   *
   * @param messages 消息数组
   * @returns 去重后的消息数组
   *
   * 使用示例:
   * ```typescript
   * const people = [person1, person2, person1Clone, person3]
   * const uniquePeople = MessageUtils.unique(people)
   * // uniquePeople: [person1, person2, person3]
   * ```
   */
  static unique<T extends Message>(messages: T[]): T[] {
    const seen = new Set<string>()
    const result: T[] = []

    for (const msg of messages) {
      // 使用二进制数据作为唯一标识
      try {
        const binary = msg.toBinary(true)
        const key = MessageUtils.binaryToString(binary)

        if (!seen.has(key)) {
          seen.add(key)
          result.push(msg)
        }
      } catch (e) {
        // 如果序列化失败,直接添加(避免丢失数据)
        result.push(msg)
      }
    }

    return result
  }

  /**
   * 辅助方法:将 Uint8Array 转换为字符串(用于 Set 比较)
   */
  private static binaryToString(binary: Uint8Array): string {
    let result = ''
    for (let i = 0; i < binary.length; i++) {
      result += String.fromCharCode(binary[i])
    }
    return result
  }
}