// Server Islands - Deferred server-side rendering
//
// Server Islands allow components to be rendered lazily on the server.
// The initial response contains a fallback placeholder, and the client
// fetches the actual rendered HTML from a dedicated endpoint.

// ============================================================================
// Server Island Types
// ============================================================================

///|
/// Definition of a server island component
pub(all) struct ServerIslandDef {
  /// Unique identifier for the island
  id : String
  /// Async render function that takes JSON props and returns ServerNode
  render : async (Json) -> @server_dom.ServerNode
  /// Optional revalidation interval in seconds for Cache-Control
  revalidate : Int?
}

///|
/// Registry of server island components
pub(all) struct ServerIslandRegistry {
  /// Map of island ID to its definition
  islands : Map[String, ServerIslandDef]
}

///|
/// Create an empty server island registry
pub fn ServerIslandRegistry::new() -> ServerIslandRegistry {
  { islands: {} }
}

///|
/// Register a server island component
pub fn ServerIslandRegistry::register(
  self : ServerIslandRegistry,
  def : ServerIslandDef,
) -> Unit {
  self.islands[def.id] = def
}

///|
/// Get a server island definition by ID
pub fn ServerIslandRegistry::get(
  self : ServerIslandRegistry,
  id : String,
) -> ServerIslandDef? {
  self.islands.get(id)
}

///|
/// Check if the registry has any islands registered
pub fn ServerIslandRegistry::is_empty(self : ServerIslandRegistry) -> Bool {
  self.islands.is_empty()
}

// ============================================================================
// Defer Endpoint Registration
// ============================================================================

///|
/// Register the `/_sol/defer/:id` endpoint for server islands.
/// Called from `register_compiled_sol_routes` when a registry is provided.
fn register_defer_endpoint(
  app : App,
  registry : ServerIslandRegistry,
) -> Unit {
  app.get(
    "/_sol/defer/:id",
    @mars.handler(async fn(c) {
      let id = c.param("id").unwrap_or("")
      match registry.get(id) {
        None => c.text("Server island not found: \{id}", status=404)
        Some(def) => {
          // Parse props from query parameter
          let props_str = c.query("props").unwrap_or("{}")
          let props : Json = @json.parse(props_str) catch {
            _ => ().to_json()
          }
          // Render the island
          let node : @server_dom.ServerNode = (def.render)(props)
          // Resolve async node and render to HTML
          let resolved = node.resolve()
          let html = @render.render_to_string(resolved).html
          // Set cache headers if revalidate is configured
          match def.revalidate {
            Some(seconds) =>
              c.set_header(
                "Cache-Control",
                "s-maxage=\{seconds}, stale-while-revalidate",
              )
            None => ()
          }
          c.set_header("Content-Type", "text/html; charset=utf-8")
          c.text(html)
        }
      }
    }),
  )
}