///|
/// Global debug mode flag
/// When enabled, logs warnings for unknown HTTP methods, etc.
let debug_enabled : Ref[Bool] = { val: false }

///|
/// Enable or disable debug mode globally
pub fn set_debug(enabled : Bool) -> Unit {
  debug_enabled.val = enabled
}

///|
/// Check if debug mode is enabled
pub fn is_debug() -> Bool {
  debug_enabled.val
}

///|
/// Server HTTP Framework
/// A Hono-inspired HTTP framework for MoonBit
pub(all) struct Server {
  router : @trie.TrieRouter
  handlers : Array[Handler]
  middlewares : Array[Handler]
  /// Registered routes for mount support
  routes : Array[(@router.Method, String, Int)]
}

///|
priv struct DispatchResult {
  response_sent : Bool
  handler_error : Bool
}

///|
priv enum RequestDispatchResult {
  NotFound
  Dispatched(DispatchResult)
}

///|
/// Create a new Server application
pub fn Server::new() -> Server {
  { router: @trie.TrieRouter::new(), handlers: [], middlewares: [], routes: [] }
}

///|
/// Create a new Server application with debug mode enabled
pub fn Server::new_debug() -> Server {
  set_debug(true)
  Server::new()
}

///|
/// Add a middleware to the application
pub fn Server::middleware(self : Server, handler : Handler) -> Unit {
  self.middlewares.push(handler)
}

///|
/// Register a GET route
pub fn Server::get(self : Server, path : String, handler : Handler) -> Unit {
  self.add_route(@router.Method::Get, path, handler)
}

///|
/// Register a POST route
pub fn Server::post(self : Server, path : String, handler : Handler) -> Unit {
  self.add_route(@router.Method::Post, path, handler)
}

///|
/// Register a PUT route
pub fn Server::put(self : Server, path : String, handler : Handler) -> Unit {
  self.add_route(@router.Method::Put, path, handler)
}

///|
/// Register a DELETE route
pub fn Server::delete(self : Server, path : String, handler : Handler) -> Unit {
  self.add_route(@router.Method::Delete, path, handler)
}

///|
/// Register a PATCH route
pub fn Server::patch(self : Server, path : String, handler : Handler) -> Unit {
  self.add_route(@router.Method::Patch, path, handler)
}

///|
/// Register a QUERY route (RFC 9110)
pub fn Server::query(self : Server, path : String, handler : Handler) -> Unit {
  self.add_route(@router.Method::Query, path, handler)
}

///|
/// Register a route for all HTTP methods
pub fn Server::all(self : Server, path : String, handler : Handler) -> Unit {
  self.add_route(@router.Method::All, path, handler)
}

///|
/// Internal: Add a route with method
fn Server::add_route(
  self : Server,
  meth : @router.Method,
  path : String,
  handler : Handler,
) -> Unit {
  let @router.HandlerId(id) = self.router.add(meth, path)
  // Ensure handlers array is large enough
  while self.handlers.length() <= id {
    // Placeholder handler
    self.handlers.push(fn(_ctx) { () })
  }
  self.handlers[id] = handler
  // Record route for mount support
  self.routes.push((meth, path, id))
}

///|
fn Server::match_first_handler(
  self : Server,
  meth : @router.Method,
  path : String,
) -> (@router.HandlerId, @router.Params)? {
  let result = self.router.match_(meth, path)
  result.handlers.get(0)
}

///|
async fn Server::dispatch_to_context(
  self : Server,
  ctx : Context,
  handler_id : Int,
) -> DispatchResult {
  for middleware in self.middlewares {
    if ctx.is_response_sent() {
      break
    }
    let Handler(mw) = middleware
    mw(ctx) catch {
      e => {
        println("Middleware error: \{e}")
        break
      }
    }
  }
  let mut handler_error = false
  if not(ctx.is_response_sent()) && handler_id < self.handlers.length() {
    let Handler(h) = self.handlers[handler_id]
    h(ctx) catch {
      e => {
        println("Handler error: \{e}")
        handler_error = true
      }
    }
  }
  { response_sent: ctx.is_response_sent(), handler_error }
}

///|
async fn Server::match_and_dispatch(
  self : Server,
  meth : @router.Method,
  path : String,
  create_context : (@router.Params) -> Context,
) -> RequestDispatchResult {
  let (@router.HandlerId(id), params) = match
    self.match_first_handler(meth, path) {
    Some(v) => v
    None => return RequestDispatchResult::NotFound
  }
  let ctx = create_context(params)
  RequestDispatchResult::Dispatched(self.dispatch_to_context(ctx, id))
}

///|
fn dispatch_fallback_status(dispatch : DispatchResult) -> Int? {
  if dispatch.handler_error && not(dispatch.response_sent) {
    Some(500)
  } else if not(dispatch.response_sent) {
    Some(404)
  } else {
    None
  }
}

///|
/// Mount a sub-application at the given prefix
pub fn Server::mount(self : Server, prefix : String, sub : Server) -> Unit {
  // Wrap sub handlers with sub's middlewares
  for route in sub.routes {
    let (meth, path, handler_idx) = route
    let full_path = join_mount_paths(prefix, path)
    let handler = sub.handlers[handler_idx]
    // Wrap with sub's middlewares
    let wrapped = wrap_with_middlewares(handler, sub.middlewares)
    self.add_route(meth, full_path, wrapped)
  }
}

///|
/// Join mount prefix and path
fn join_mount_paths(prefix : String, path : String) -> String {
  // Remove trailing slash from prefix
  let prefix_clean = if prefix.length() > 1 && prefix.has_suffix("/") {
    let chars : Array[Char] = []
    for c in prefix {
      chars.push(c)
    }
    let buf = StringBuilder::new()
    for i = 0; i < chars.length() - 1; i = i + 1 {
      buf.write_char(chars[i])
    }
    buf.to_string()
  } else {
    prefix
  }
  // Ensure path starts with /
  if path.length() == 0 || not(path.has_prefix("/")) {
    "\{prefix_clean}/\{path}"
  } else {
    "\{prefix_clean}\{path}"
  }
}

///|
/// Wrap handler with middlewares (compose)
fn wrap_with_middlewares(
  handler : Handler,
  middlewares : Array[Handler],
) -> Handler {
  if middlewares.is_empty() {
    return handler
  }
  // Compose middlewares with handler
  let Handler(h) = handler
  let mut current : async (Context) -> Unit raise Error = h
  // Apply middlewares in reverse order
  for i = middlewares.length() - 1; i >= 0; i = i - 1 {
    let Handler(mw) = middlewares[i]
    let next = current
    current = async fn(ctx) {
      mw(ctx)
      next(ctx)
    }
  }
  Handler(current)
}

///|
/// Helper to create a Handler from an async function
pub fn handler(f : async (Context) -> Unit raise Error) -> Handler {
  Handler(f)
}