/**
 * test/Person.ets
 *
 * Manually generated code for testing Visitor pattern V2.0
 */

import { Message, Visitor, Reader } from '../runtime/arkpb'
import { Address } from './Address'

/**
 * Person message
 */
export class Person extends Message {
  // Type name for reflection
  readonly $typeName: string = 'test.Person'
  static readonly typeName: string = 'test.Person'

  // Fields
  name: string = ''
  age: number = 0
  emails: string[] = []
  address: Address | null = null

  // Constructor
  constructor() {
    super()
  }

  // ⭐ Core: traverse method for Visitor pattern
  traverse(v: Visitor): void {
    if (this.name !== '') {
      v.visitString(this.name, 1)
    }
    if (this.age !== 0) {
      v.visitInt32(this.age, 2)
    }
    if (this.emails.length > 0) {
      v.visitRepeatedString(this.emails, 3)
    }
    if (this.address !== null) {
      v.visitMessage(this.address, 4)
    }
  }

  // Decode from Reader
  protected decodeFrom(r: Reader, len?: number): void {
    const endPos = len === undefined ? r.len : r.pos + len

    while (r.pos < endPos) {
      const tag = r.uint32()
      const fieldNum = tag >>> 3

      switch (fieldNum) {
        case 1:
          this.name = r.string()
          break
        case 2:
          this.age = r.int32()
          break
        case 3:
          this.emails.push(r.string())  // ⚠️ push, not replace!
          break
        case 4: {
          const msgLen = r.uint32()
          this.address = new Address()
          this.address.decodeFrom(r, msgLen)
          break
        }
        default: {
          // Save unknown fields
          const wireType = tag & 7
          const start = r.pos
          r.skipType(wireType)
          this.unknownFields.append(r.view(start, r.pos))
        }
      }
    }
  }

  // Static factory methods
  static create(init?: Partial<Person>): Person {
    const msg = new Person()
    if (init) {
      if (init.name !== undefined) msg.name = init.name
      if (init.age !== undefined) msg.age = init.age
      if (init.emails !== undefined) msg.emails = [...init.emails]
      if (init.address !== undefined) {
        msg.address = init.address instanceof Address
          ? init.address
          : Address.create(init.address)
      }
    }
    return msg
  }

  static build(builder: (msg: Person) => void): Person {
    const msg = new Person()
    builder(msg)
    return msg
  }

  static fromBinary(data: Uint8Array): Person {
    return new Person().fromBinary(data) as Person
  }

  static fromJson(json: Record<string, Object>): Person {
    return new Person().fromJson(json) as Person
  }

  // Validation
  validate(): string | null {
    // Example validation: check nested message
    if (this.address !== null) {
      const err = this.address.validate()
      if (err !== null) {
        return 'address: ' + err
      }
    }
    return null
  }

  // Clear all fields
  clear(): this {
    this.name = ''
    this.age = 0
    this.emails = []
    this.address = null
    this.unknownFields.clear()
    return this
  }

  // Check if all fields are default
  isEmpty(): boolean {
    return this.name === '' &&
           this.age === 0 &&
           this.emails.length === 0 &&
           this.address === null &&
           this.unknownFields.isEmpty()
  }
}