// MoonDNS - Pure MoonBit Authoritative DNS Server
// Copyright 2026 chgttyyr
// Licensed under the Apache-2.0 License.

///|
/// DNS Response Codes (RFC 1035 / RFC 6891)
pub(all) enum RCode {
  NoError // 0: No error condition
  FormErr // 1: Format error in query
  ServFail // 2: Server failure
  NXDomain // 3: Non-existent domain (Name Error)
  NotImp // 4: Not implemented
  Refused // 5: Query refused by policy
  YXDomain // 6: Name exists when it should not (RFC 2136)
  YXRRSet // 7: RR set exists when it should not
  NXRRSet // 8: RR set that should exist does not
  NotAuth // 9: Server not authoritative for zone
  NotZone // 10: Name not contained in zone
  BadVers // 16: Bad EDNS version (RFC 6891)
  Unknown(UInt16)
} derive(Debug, Eq)

///|
/// Convert RCode to wire protocol integer
pub fn RCode::to_wire(self : RCode) -> UInt16 {
  match self {
    NoError => 0
    FormErr => 1
    ServFail => 2
    NXDomain => 3
    NotImp => 4
    Refused => 5
    YXDomain => 6
    YXRRSet => 7
    NXRRSet => 8
    NotAuth => 9
    NotZone => 10
    BadVers => 16
    Unknown(code) => code
  }
}

///|
/// Parse RCode from wire protocol integer
pub fn RCode::from_wire(code : UInt16) -> RCode {
  match code {
    0 => NoError
    1 => FormErr
    2 => ServFail
    3 => NXDomain
    4 => NotImp
    5 => Refused
    6 => YXDomain
    7 => YXRRSet
    8 => NXRRSet
    9 => NotAuth
    10 => NotZone
    16 => BadVers
    other => Unknown(other)
  }
}

///|
/// DNS Operation Codes (RFC 1035)
pub(all) enum OpCode {
  Query // 0: Standard query
  IQuery // 1: Inverse query (obsolete)
  Status // 2: Server status request
  Notify // 4: Zone change notification (RFC 1996)
  Update // 5: Dynamic update (RFC 2136)
  Unknown(Byte)
} derive(Debug, Eq)

///|
/// Convert OpCode to wire protocol byte
pub fn OpCode::to_wire(self : OpCode) -> Byte {
  match self {
    Query => 0
    IQuery => 1
    Status => 2
    Notify => 4
    Update => 5
    Unknown(val) => val
  }
}

///|
/// Parse OpCode from wire protocol byte
pub fn OpCode::from_wire(val : Byte) -> OpCode {
  match val.to_int() {
    0 => Query
    1 => IQuery
    2 => Status
    4 => Notify
    5 => Update
    _ => Unknown(val)
  }
}

///|
/// DNS Message Header (12 bytes fixed size, RFC 1035 Section 4.1.1)
pub(all) struct Header {
  mut id : UInt16 // 16-bit identifier assigned by query generator
  mut qr : Bool // Query (false) or Response (true)
  mut opcode : OpCode // 4-bit operation code
  mut aa : Bool // Authoritative Answer
  mut tc : Bool // Truncation flag
  mut rd : Bool // Recursion Desired
  mut ra : Bool // Recursion Available
  mut z : Byte // 3-bit reserved field, must be zero
  mut rcode : RCode // 4-bit response code
  mut qdcount : UInt16 // Number of entries in Question section
  mut ancount : UInt16 // Number of Resource Records in Answer section
  mut nscount : UInt16 // Number of Resource Records in Authority section
  mut arcount : UInt16 // Number of Resource Records in Additional section
} derive(Debug, Eq)

///|
/// Default constructor for a new DNS query header
pub fn Header::new_query(id : UInt16) -> Header {
  {
    id,
    qr: false,
    opcode: Query,
    aa: false,
    tc: false,
    rd: true,
    ra: false,
    z: 0,
    rcode: NoError,
    qdcount: 1,
    ancount: 0,
    nscount: 0,
    arcount: 0,
  }
}

///|
/// Construct an authoritative response header responding to a query
pub fn Header::new_response(
  id : UInt16,
  aa : Bool,
  rcode : RCode,
  qdcount : UInt16,
  ancount : UInt16,
  nscount : UInt16,
  arcount : UInt16,
) -> Header {
  {
    id,
    qr: true,
    opcode: Query,
    aa,
    tc: false,
    rd: false,
    ra: false,
    z: 0,
    rcode,
    qdcount,
    ancount,
    nscount,
    arcount,
  }
}