// TLS Record Tree Formatter and Hex-Dumper utility

///|
pub fn TlsRecord::dump_tree(self : TlsRecord) -> String {
  let sb = StringBuilder()
  match self {
    ClientHelloRecord(hello) => {
      sb.write_string("[-] TLS Record: Handshake (ClientHello)\n")
      sb.write_string(
        "  ├─ Legacy Version: \{uint16_to_hex4(hello.legacy_version)} (\{hello.legacy_version.to_int()})\n",
      )
      sb.write_string(
        "  ├─ Record Version: \{uint16_to_hex4(hello.record_version)} (\{hello.record_version.to_int()})\n",
      )
      let sni = hello.server_name.unwrap_or("-")
      sb.write_string("  ├─ SNI (Server Name): \{sni}\n")
      let alpn = hello.alpn_protocols.join(", ")
      sb.write_string("  ├─ ALPN Protocols: [\{alpn}]\n")
      sb.write_string(
        "  ├─ Cipher Suites (count: \{hello.cipher_suites.length()}):\n",
      )
      for c in hello.cipher_suites {
        sb.write_string("  │   ├─ \{uint16_to_hex4(c)}\n")
      }
      sb.write_string(
        "  ├─ Extensions (count: \{hello.extensions.length()}):\n",
      )
      for e in hello.extensions {
        sb.write_string("  │   ├─ \{uint16_to_hex4(e)}\n")
      }
      sb.write_string(
        "  ├─ Supported Groups (count: \{hello.supported_groups.length()}): ",
      )
      let groups_str = hello.supported_groups
        .map(fn(g) { g.to_string() })
        .join(", ")
      sb.write_string("[\{groups_str}]\n")
      sb.write_string(
        "  ├─ JA3 Fingerprint String: \{hello.ja3_string()}\n",
      )
      sb.write_string("  ├─ JA3 Digest (MD5): \{hello.ja3_digest()}\n")
      sb.write_string("  └─ JA4 Fingerprint: \{hello.ja4()}\n")
    }
    ServerHelloRecord(hello) => {
      sb.write_string("[-] TLS Record: Handshake (ServerHello)\n")
      sb.write_string(
        "  ├─ Handshake Version: \{uint16_to_hex4(hello.version)} (\{hello.version.to_int()})\n",
      )
      sb.write_string(
        "  ├─ Cipher Suite: \{uint16_to_hex4(hello.cipher_suite)}\n",
      )
      sb.write_string(
        "  ├─ Compression Method: \{hello.compression_method.to_int()}\n",
      )
      let alpn = hello.selected_alpn.unwrap_or("-")
      sb.write_string("  ├─ Selected ALPN: \{alpn}\n")
      sb.write_string(
        "  ├─ Extensions (count: \{hello.extensions.length()}):\n",
      )
      for e in hello.extensions {
        sb.write_string("  │   ├─ \{uint16_to_hex4(e)}\n")
      }
      sb.write_string("  ├─ JA4S-a Fingerprint Part A: \{hello.ja4s_a()}\n")
      sb.write_string("  └─ JA4S Fingerprint: \{hello.ja4s()}\n")
    }
    AlertRecord(alert) => {
      sb.write_string("[-] TLS Record: Alert\n")
      sb.write_string(
        "  ├─ Level: \{alert.level_string()} (\{alert.level.to_int()})\n",
      )
      sb.write_string(
        "  └─ Description: \{alert.description_string()} (\{alert.description.to_int()})\n",
      )
    }
    CertificateRecord(cert) => {
      sb.write_string("[-] TLS Record: Handshake (Certificate)\n")
      sb.write_string(
        "  └─ Certificate Chains (count: \{cert.cert_lengths.length()}):\n",
      )
      for i in 0.. {
      sb.write_string("[-] TLS Record: Handshake (ClientKeyExchange)\n")
      sb.write_string(
        "  └─ Key Exchange Payload Length: \{cke.raw.length()} bytes\n",
      )
    }
    ServerKeyExchangeRecord(ske) => {
      sb.write_string("[-] TLS Record: Handshake (ServerKeyExchange)\n")
      sb.write_string(
        "  └─ Key Exchange Payload Length: \{ske.raw.length()} bytes\n",
      )
    }
    NewSessionTicketRecord(nst) => {
      sb.write_string("[-] TLS Record: Handshake (NewSessionTicket)\n")
      sb.write_string(
        "  ├─ Ticket Lifetime: \{nst.lifetime.reinterpret_as_int()} seconds\n",
      )
      sb.write_string(
        "  ├─ Ticket Age Add: \{nst.age_add.reinterpret_as_int()}\n",
      )
      sb.write_string("  └─ Ticket Length: \{nst.ticket.length()} bytes\n")
    }
    EncryptedExtensionsRecord(ee) => {
      sb.write_string("[-] TLS Record: Handshake (EncryptedExtensions)\n")
      sb.write_string(
        "  └─ Extensions (count: \{ee.extensions.length()}):\n",
      )
      for e in ee.extensions {
        sb.write_string("      ├─ \{uint16_to_hex4(e)}\n")
      }
    }
    HelloRequestRecord(_) => {
      sb.write_string("[-] TLS Record: Handshake (HelloRequest)\n")
      sb.write_string("  └─ Body: Empty\n")
    }
    HelloVerifyRequestRecord(hvr) => {
      sb.write_string("[-] TLS Record: Handshake (HelloVerifyRequest)\n")
      sb.write_string(
        "  ├─ Handshake Version: \{uint16_to_hex4(hvr.version)} (\{hvr.version.to_int()})\n",
      )
      sb.write_string("  └─ Cookie Length: \{hvr.cookie.length()} bytes\n")
    }
    CertificateRequestRecord(cr) => {
      sb.write_string("[-] TLS Record: Handshake (CertificateRequest)\n")
      let types_str = cr.certificate_types
        .map(fn(t) { t.to_int().to_string() })
        .join(", ")
      sb.write_string("  ├─ Cert Types: [\{types_str}]\n")
      let algs_str = cr.supported_signature_algorithms
        .map(fn(a) { uint16_to_hex4(a) })
        .join(", ")
      sb.write_string("  └─ Sig Algs: [\{algs_str}]\n")
    }
    CertificateVerifyRecord(cv) => {
      sb.write_string("[-] TLS Record: Handshake (CertificateVerify)\n")
      sb.write_string(
        "  ├─ Sig Alg: \{uint16_to_hex4(cv.signature_algorithm)}\n",
      )
      sb.write_string(
        "  └─ Signature Length: \{cv.signature.length()} bytes\n",
      )
    }
    FinishedRecord(fn_) => {
      sb.write_string("[-] TLS Record: Handshake (Finished)\n")
      sb.write_string(
        "  └─ Verify Data Length: \{fn_.verify_data.length()} bytes\n",
      )
    }
    GenericRecord(ty, payload) => {
      let ty_str = match ty {
        ChangeCipherSpec => "ChangeCipherSpec"
        Handshake => "Handshake (Generic)"
        ApplicationData => "ApplicationData"
        Unknown(b) => "Unknown (0x\{b.to_int().to_string(radix=16)})"
      }
      sb.write_string("[-] TLS Record: \{ty_str}\n")
      sb.write_string("  └─ Payload Length: \{payload.length()} bytes\n")
    }
  }
  sb.to_string()
}

///|
pub fn hex_dump(data : BytesView) -> String {
  let sb = StringBuilder()
  let len = data.length()
  let mut offset = 0
  while offset < len {
    // Print offset
    let off_str = offset.to_string(radix=16).pad_start(4, '0')
    sb.write_string(off_str)
    sb.write_string("  ")

    // Print hex values
    let mut i = 0
    while i < 16 {
      if offset + i < len {
        let b = data[offset + i]
        let hex = b.to_int().to_string(radix=16).pad_start(2, '0')
        sb.write_string(hex)
        sb.write_string(" ")
      } else {
        sb.write_string("   ")
      }
      if i == 7 {
        sb.write_string(" ")
      }
      i = i + 1
    }

    sb.write_string(" |")
    // Print ASCII representation
    i = 0
    while i < 16 {
      if offset + i < len {
        let b = data[offset + i].to_int()
        if b >= 32 && b <= 126 {
          match b.to_char() {
            Some(c) => sb.write_char(c)
            None => sb.write_string(".")
          }
        } else {
          sb.write_string(".")
        }
      }
      i = i + 1
    }
    sb.write_string("|\n")
    offset = offset + 16
  }
  sb.to_string()
}