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

///|
fn print_banner() -> Unit {
  println("=================================================================")
  println("  MoonDNS (chgttyyr/moon_dns) - MoonBit DNS Protocol Core Demo")
  println("  In-memory pipeline | Native UDP/TCP CLI: cmd/moondns")
  println("=================================================================")
}

///|
fn run_demo() -> Unit {
  print_banner()
  println("[1/5] Bootstrapping In-Memory Zone Database for 'example.com.'...")

  let zone = @zone.Zone::new("example.com.", 3600)

  // SOA
  zone.add_record(
    @types.Record::new(
      "example.com.",
      @types.RType::SOA,
      @types.RClass::IN,
      3600,
      @types.RData::SOA(
        "ns1.example.com.", "hostmaster.example.com.", 2026092001, 7200, 3600, 1209600,
        3600,
      ),
    ),
  )

  // NS & Glue
  zone.add_record(
    @types.Record::new(
      "example.com.",
      @types.RType::NS,
      @types.RClass::IN,
      86400,
      @types.RData::NS("ns1.example.com."),
    ),
  )
  zone.add_record(
    @types.Record::new(
      "ns1.example.com.",
      @types.RType::A,
      @types.RClass::IN,
      86400,
      @types.RData::A(
        (192).to_byte(),
        (0).to_byte(),
        (2).to_byte(),
        (1).to_byte(),
      ),
    ),
  )

  // A, CNAME, Wildcard
  zone.add_record(
    @types.Record::new(
      "www.example.com.",
      @types.RType::A,
      @types.RClass::IN,
      300,
      @types.RData::A(
        (93).to_byte(),
        (184).to_byte(),
        (216).to_byte(),
        (34).to_byte(),
      ),
    ),
  )
  zone.add_record(
    @types.Record::new(
      "blog.example.com.",
      @types.RType::CNAME,
      @types.RClass::IN,
      300,
      @types.RData::CNAME("www.example.com."),
    ),
  )
  zone.add_record(
    @types.Record::new(
      "*.dev.example.com.",
      @types.RType::A,
      @types.RClass::IN,
      60,
      @types.RData::A(
        (127).to_byte(),
        (0).to_byte(),
        (0).to_byte(),
        (1).to_byte(),
      ),
    ),
  )

  let server = @transport.DnsServer::new(zone)
  println("  -> Loaded 6 records into authoritative apex 'example.com.'")

  println("\n[2/5] Testing Standard Authoritative Queries...")
  // Query 1: www.example.com. A
  let q1 = @types.Message::new_query(
    0x1001,
    "www.example.com.",
    @types.RType::A,
  )
  match server.process_udp(@codec.encode_message(q1)) {
    Ok(raw_resp) => {
      let resp = match @codec.decode_message(raw_resp) {
        Ok(m) => m
        Err(_) => panic()
      }
      println(
        "  [QUERY] www.example.com. A -> RCODE=" +
        resp.header.rcode.to_wire().to_string() +
        ", AA=" +
        resp.header.aa.to_string(),
      )
      for i = 0; i < resp.answers.length(); i = i + 1 {
        println(
          "    ANSWER: " +
          resp.answers[i].name +
          " " +
          resp.answers[i].ttl.to_string() +
          " IN A " +
          resp.answers[i].rdata.to_presentation(),
        )
      }
    }
    Err(_) => panic()
  }

  // Query 2: blog.example.com. A (CNAME Chasing)
  let q2 = @types.Message::new_query(
    0x1002,
    "blog.example.com.",
    @types.RType::A,
  )
  match server.process_udp(@codec.encode_message(q2)) {
    Ok(raw_resp) => {
      let resp = match @codec.decode_message(raw_resp) {
        Ok(m) => m
        Err(_) => panic()
      }
      println(
        "  [QUERY] blog.example.com. A -> Chased " +
        resp.answers.length().to_string() +
        " records (CNAME + Target)",
      )
      for i = 0; i < resp.answers.length(); i = i + 1 {
        println(
          "    ANSWER: " +
          resp.answers[i].name +
          " -> " +
          resp.answers[i].rdata.to_presentation(),
        )
      }
    }
    Err(_) => panic()
  }

  // Query 3: Wildcard test.dev.example.com. A
  let q3 = @types.Message::new_query(
    0x1003,
    "test.dev.example.com.",
    @types.RType::A,
  )
  match server.process_udp(@codec.encode_message(q3)) {
    Ok(raw_resp) => {
      let resp = match @codec.decode_message(raw_resp) {
        Ok(m) => m
        Err(_) => panic()
      }
      println(
        "  [QUERY] test.dev.example.com. A -> Wildcard Match: " +
        resp.answers[0].rdata.to_presentation(),
      )
    }
    Err(_) => panic()
  }

  println("\n[3/5] Testing RFC Semantics (NODATA & NXDOMAIN)...")
  // Query 4: www.example.com. MX -> NODATA (RCODE=0, ANCOUNT=0, SOA in Authority)
  let q4 = @types.Message::new_query(
    0x1004,
    "www.example.com.",
    @types.RType::MX,
  )
  match server.process_udp(@codec.encode_message(q4)) {
    Ok(raw_resp) => {
      let resp = match @codec.decode_message(raw_resp) {
        Ok(m) => m
        Err(_) => panic()
      }
      println(
        "  [NODATA] RCODE=" +
        resp.header.rcode.to_wire().to_string() +
        ", Answers=" +
        resp.answers.length().to_string() +
        ", Authority=" +
        resp.authorities[0].rtype.to_string(),
      )
    }
    Err(_) => panic()
  }

  // Query 5: ghost.example.com. A -> NXDOMAIN (RCODE=3, ANCOUNT=0, SOA in Authority)
  let q5 = @types.Message::new_query(
    0x1005,
    "ghost.example.com.",
    @types.RType::A,
  )
  match server.process_udp(@codec.encode_message(q5)) {
    Ok(raw_resp) => {
      let resp = match @codec.decode_message(raw_resp) {
        Ok(m) => m
        Err(_) => panic()
      }
      println(
        "  [NXDOMAIN] RCODE=" +
        resp.header.rcode.to_wire().to_string() +
        " (Name Error), Authority=" +
        resp.authorities[0].name,
      )
    }
    Err(_) => panic()
  }

  println("\n[4/5] Security Testing: Malicious Pointer Attacks Injection...")
  // Inject malicious self-loop pointer packet
  let writer = @bytes_io.ByteWriter::new()
  let bad_header = @types.Header::new_query(0x6666)
  @codec.encode_header(writer, bad_header)
  // Inject cyclic pointer 0xc00c pointing to self
  writer.write_byte((0xc0).to_byte())
  writer.write_byte((0x0c).to_byte())
  writer.write_uint16(1) // QTYPE A
  writer.write_uint16(1) // QCLASS IN

  let attack_payload = writer.to_bytes()
  match server.process_udp(attack_payload) {
    Ok(_) => panic()
    Err(err) => {
      println(
        "  [SUCCESS] Defense Layer Active: Intercepted attack safely: " +
        err.message(),
      )
      println("  Demo continued after rejecting the malformed packet.")
    }
  }

  println("\n[5/5] In-memory smoke loop (10,000 iterations)...")
  let bench_q = @types.Message::new_query(
    0x9999,
    "www.example.com.",
    @types.RType::A,
  )
  let bench_raw = @codec.encode_message(bench_q)
  let mut bench_success = 0
  for i = 0; i < 10000; i = i + 1 {
    match server.process_udp(bench_raw) {
      Ok(_) => bench_success = bench_success + 1
      Err(_) => ()
    }
  }
  println(
    "  [SMOKE] Processed 10,000 in-memory requests: " +
    bench_success.to_string() +
    "/10000 success (not a network benchmark or memory profile)",
  )

  println(
    "\nAll demo stages executed successfully. Total queries processed: " +
    server.query_count.to_string(),
  )
}

///|
fn main {
  run_demo()
}