/**
 * Message.ets
 *
 * Protobuf 消息抽象基类 - SwiftProtobuf 架构对齐
 *
 * 设计理念(基于 SwiftProtobuf):
 * 1. ⭐ Visitor 模式为核心 - traverse() 是最重要的方法
 * 2. 实例方法为主,API 自然流畅
 * 3. 支持消息合并(Protobuf 正确语义)
 * 4. 递归深度保护(安全性)
 * 5. 保留未知字段(兼容性)
 *
 * 符合 ArkTS 2025 规范:
 * - 不使用 any 类型
 * - 对象布局固定,不动态添加属性
 * - 支持抽象类和泛型
 *
 * Version: 1.0.0
 * ArkTS 2025 兼容
 */

import { Visitor } from './Visitor'
import { UnknownFields } from './UnknownFields'
import { Reader } from './Reader'
import { BinaryEncodingVisitor } from './BinaryEncodingVisitor'
import { JsonEncodingVisitor } from './JsonEncodingVisitor'

/**
 * 所有 Protobuf 消息的抽象基类
 *
 * 所有生成的消息类都必须继承此类,并实现:
 * 1. traverse(visitor: Visitor): void - 遍历所有字段
 * 2. decodeFrom(reader: Reader, length?: number): void - 从 Reader 解码
 *
 * 使用示例:
 * ```typescript
 * const person = Person.create({ name: 'Alice', age: 30 })
 * const binary = person.toBinary()
 * const json = person.toJson()
 * const cloned = person.clone()
 * ```
 */
export abstract class Message {
  /**
   * 消息类型名称(如 "google.protobuf.Timestamp")
   *
   * 子类必须实现此属性
   */
  abstract readonly $typeName: string

  /**
   * 未知字段存储(用于前后兼容)
   *
   * 当解码消息时遇到未知的字段编号,会将原始数据保存在此。
   * 重新编码时,这些数据会被完整保留。
   */
  unknownFields: UnknownFields = new UnknownFields()

  // ========== 抽象方法(子类必须实现) ==========

  /**
   * ⭐ 核心方法:遍历所有字段(Visitor 模式)
   *
   * SwiftProtobuf 设计:
   * "Conceptually, serializers create visitor objects that are
   *  then passed recursively to every message and field via generated
   *  traverse methods."
   *
   * 这是代码生成器需要生成的主要方法!
   * 其他方法(toBinary/toJson等)都是基于这个方法实现的。
   *
   * 实现示例:
   * ```typescript
   * traverse(v: Visitor): void {
   *   if (this.name !== '') v.visitString(this.name, 1)
   *   if (this.age !== 0) v.visitInt32(this.age, 2)
   *   if (this.address !== null) v.visitMessage(this.address, 3)
   * }
   * ```
   *
   * @param visitor 字段访问者对象
   */
  abstract traverse(visitor: Visitor): void
  
  /**
   * 从 Reader 解码(子类实现)
   *
   * @internal 子类实现,外部不直接调用
   *
   * @param reader 二进制读取器
   * @param length 可选的长度限制(用于嵌套消息)
   */
  abstract decodeFrom(reader: Reader, length?: number): void

  // ========== 序列化方法(使用 Visitor) ==========

  /**
   * 序列化为二进制(Protobuf wire format)
   *
   * 使用 BinaryEncodingVisitor 遍历所有字段并编码
   *
   * @param partial 是否允许部分序列化(跳过 required 字段检查)
   * @returns 二进制数据
   * @throws 如果 partial=false 且 required 字段未设置
   *
   * 使用示例:
   * ```typescript
   * const binary = person.toBinary()
   * const partialBinary = person.toBinary(true) // 跳过验证
   * ```
   */
  toBinary(partial: boolean = false): Uint8Array {
    // 验证消息(如果不是 partial 模式)
    if (!partial) {
      const error = this.validate()
      if (error !== null) {
        throw new Error(`Message validation failed: ${error}`)
      }
    }

    // ⭐ 使用 BinaryEncodingVisitor 编码
    const visitor = new BinaryEncodingVisitor()
    this.traverse(visitor)
    return visitor.finish()
  }

  /**
   * 从二进制反序列化(修改当前实例)
   *
   * ⚠️ 注意:这是合并操作,不会清空现有字段
   * - 标量字段:覆盖
   * - repeated 字段:追加
   * - 嵌套消息:递归合并
   *
   * @param data 二进制数据
   * @param partial 是否允许部分解码(跳过 required 字段检查)
   * @returns this(支持链式调用)
   * @throws 如果 partial=false 且 required 字段未设置
   *
   * 使用示例:
   * ```typescript
   * const person = new Person()
   * person.fromBinary(binary)
   * ```
   */
  fromBinary(data: Uint8Array, partial: boolean = false): Message {
    const reader = new Reader(data)
    this.decodeFrom(reader)

    // 验证消息(如果不是 partial 模式)
    if (!partial) {
      const error = this.validate()
      if (error !== null) {
        throw new Error(`Message validation failed after decode: ${error}`)
      }
    }

    return this
  }

  /**
   * 转换为 JSON 对象(Protobuf JSON mapping)
   *
   * 使用 JsonEncodingVisitor 遍历所有字段并转换
   *
   * ArkTS 注意:返回类型使用 Record<string, Object>
   * 而不是 Record<string, any>
   *
   * @returns JSON 对象
   *
   * 使用示例:
   * ```typescript
   * const json = person.toJson()
   * console.log(JSON.stringify(json))
   * ```
   */
  toJson(): Record<string, Object> {
    // ⭐ 使用 JsonEncodingVisitor 编码
    const visitor = new JsonEncodingVisitor()
    this.traverse(visitor)
    return visitor.finish()
  }

  /**
   * 从 JSON 对象反序列化(修改当前实例)
   *
   * ⚠️ 设计说明:
   * 本方法故意未实现,这是一个**架构决策**而非疏漏。
   * 生成的消息类提供**静态方法** `static fromJson(j: MessageJSON): Message`
   * 而非实例方法,以提供更好的类型安全。
   *
   * 推荐使用方式:
   * ```typescript
   * // ✅ 使用静态方法(类型安全)
   * const person = Person.fromJson(json)
   *
   * // ❌ 不要使用实例方法(会抛出异常)
   * const person = new Person()
   * person.fromJson(json)  // Error!
   * ```
   *
   * 为什么选择静态方法?
   * 1. 类型安全:返回具体类型(Person),而非基类(Message)
   * 2. 符合工厂模式:静态方法作为构造器更自然
   * 3. 避免先创建实例:不需要 `new Person()` 再填充数据
   * 4. ArkTS 兼容:不依赖多态或复杂类型推导
   *
   * 详见:ARCHITECTURE.md > 关键设计决策 > 1
   *
   * ArkTS 注意:参数类型使用 Record<string, Object>
   *
   * @param json JSON 对象
   * @returns this(支持链式调用)
   */
  fromJson(json: Record<string, Object>): Message {
    throw new Error('fromJson() not implemented for ' + this.$typeName +
                    '. Use static method: ' + this.$typeName + '.fromJson() instead.')
  }

  // ========== 实用方法 ==========

  /**
   * 深拷贝消息
   *
   * 通过序列化和反序列化实现深拷贝
   *
   * @returns 新的消息对象(深拷贝)
   *
   * 使用示例:
   * ```typescript
   * const personCopy = person.clone()
   * ```
   */
  abstract clone(): Message

  /**
   * 从另一个消息合并字段(覆盖当前值)
   *
   * 合并语义(Protobuf 标准):
   * - 标量字段:other 覆盖 this
   * - repeated 字段:追加(不是替换!)
   * - 嵌套消息:递归合并
   *
   * @param other 要合并的消息
   * @returns this(支持链式调用)
   *
   * 使用示例:
   * ```typescript
   * const base = Person.create({ name: 'Alice', age: 30 })
   * const update = Person.create({ age: 31, emails: ['new@example.com'] })
   * base.mergeFrom(update) // age 覆盖,emails 追加
   * ```
   */
  mergeFrom(other: Message): Message {
    try {
      return this.fromBinary(other.toBinary(true)) // partial=true
    } catch (e) {
      throw new Error(`Merge failed: ${e}`)
    }
  }

  /**
   * 从二进制数据合并
   *
   * @param data 二进制数据
   * @returns this(支持链式调用)
   */
  mergeFromBinary(data: Uint8Array): Message {
    try {
      return this.fromBinary(data, true) // partial=true
    } catch (e) {
      throw new Error(`Merge from binary failed: ${e}`)
    }
  }

  /**
   * 验证消息(返回错误信息,或 null 表示有效)
   *
   * 子类可覆盖以实现自定义验证逻辑:
   * - Proto2 required 字段检查
   * - 业务逻辑验证
   *
   * @returns 错误信息,或 null 表示有效
   *
   * 使用示例:
   * ```typescript
   * const error = person.validate()
   * if (error !== null) {
   *   console.error('Validation failed:', error)
   * }
   * ```
   */
  validate(): string | null {
    // 默认实现:无验证
    // 子类可覆盖此方法
    return null
  }

  /**
   * 判断消息是否有效
   *
   * @returns true 如果消息有效
   */
  isValid(): boolean {
    return this.validate() === null
  }

  /**
   * 检查所有 required 字段是否已设置(递归检查)
   *
   * 用于 proto2 语法
   *
   * @returns true 如果所有 required 字段都已设置
   */
  isInitialized(): boolean {
    return this.isValid()
  }

  /**
   * 清空所有字段为默认值
   *
   * @returns this(支持链式调用)
   *
   * 注意:子类应覆盖此方法以清空所有字段
   */
  clear(): Message {
    // 默认实现:只清空未知字段
    this.unknownFields.clear()
    return this
  }

  /**
   * 判断消息是否为空(所有字段都是默认值)
   *
   * @returns true 如果所有字段都是默认值
   *
   * 注意:子类应覆盖此方法以检查所有字段
   */
  isEmpty(): boolean {
    // 默认实现:只检查未知字段
    return this.unknownFields.isEmpty()
  }

  /**
   * 判断两个消息是否相等(二进制比较)
   *
   * @param other 要比较的消息
   * @returns true 如果内容完全相同
   *
   * 使用示例:
   * ```typescript
   * if (person1.equals(person2)) {
   *   console.log('Messages are equal')
   * }
   * ```
   */
  equals(other: Message): boolean {
    // 类型检查
    if (this.$typeName !== other.$typeName) {
      return false
    }

    try {
      // 二进制比较
      const a = this.toBinary(true)
      const b = other.toBinary(true)

      if (a.length !== b.length) {
        return false
      }

      for (let i = 0; i < a.length; i++) {
        if (a[i] !== b[i]) {
          return false
        }
      }

      return true
    } catch (e) {
      return false
    }
  }

  /**
   * 转换为可读字符串(用于调试)
   *
   * @returns JSON 格式的字符串
   */
  toString(): string {
    try {
      return JSON.stringify(this.toJson(), null, 2)
    } catch (e) {
      return `[${this.$typeName}]`
    }
  }
}

/**
 * 消息构造器接口,用于泛型约束
 *
 * ArkTS 注意:使用 Object 而不是 any
 *
 * 使用示例:
 * ```typescript
 * function deserialize<T extends Message>(
 *   ctor: MessageConstructor<T>,
 *   data: Uint8Array
 * ): T {
 *   return ctor.fromBinary(data)
 * }
 * ```
 */
export interface MessageConstructor<T extends Message> {
  readonly typeName: string

  // 静态工厂方法 - 不使用 Partial<T>(ArkTS 不支持)
  create(init?: Record<string, Object>): T

  // 从二进制创建(静态方法)
  fromBinary(data: Uint8Array): T

  // 从 JSON 创建(静态方法)
  fromJson(json: Record<string, Object>): T
}