// Sol Routes - Compilation logic
//
// Compiles SolRoutes DSL into optimized CompiledSolRoute format.

///|
fn push_api_route(
  result : Array[CompiledSolRoute],
  prefix : String,
  path : String,
  handler : ApiHandler,
  kind : SolRouteKind,
  inherited_middlewares : Array[@middleware.Middleware],
) -> Unit {
  let full_path = normalize_path(prefix + path)
  let param_names = extract_param_names(full_path)
  let catch_all = extract_catch_all(full_path)
  result.push({
    pattern: full_path,
    param_names,
    page_handler: None,
    api_handler: Some(handler),
    layouts: [],
    middlewares: inherited_middlewares.copy(),
    kind,
    title: "",
    meta: [],
    catch_all,
    revalidate: None,
    cache_strategy: CacheStrategy::AlwaysFetch,
    rendered_meta: "",
  })
}

///|
fn render_meta_tags(meta : Array[(String, String)]) -> String {
  if meta.is_empty() {
    return ""
  }
  let buf = StringBuilder::new()
  for pair in meta {
    let key = @page_shell.escape_html_text(pair.0)
    let value = @page_shell.escape_html_text(pair.1)
    buf.write_string("")
  }
  buf.to_string()
}

///|
/// Compile SolRoutes to optimized format
pub fn compile_sol_routes(
  routes : Array[SolRoutes],
  base? : String = "",
) -> Array[CompiledSolRoute] {
  let result : Array[CompiledSolRoute] = []
  compile_sol_routes_inner(routes, base, [], [], result)
  result
}

///|
fn compile_sol_routes_inner(
  routes : Array[SolRoutes],
  prefix : String,
  inherited_layouts : Array[
    (PageProps, @server_dom.ServerNode) -> @server_dom.ServerNode raise Error,
  ],
  inherited_middlewares : Array[@middleware.Middleware],
  result : Array[CompiledSolRoute],
) -> Unit {
  for route in routes {
    match route {
      Page(path~, handler~, title~, meta~, revalidate~, cache~) => {
        let full_path = normalize_path(prefix + path)
        let param_names = extract_param_names(full_path)
        let catch_all = extract_catch_all(full_path)
        result.push({
          pattern: full_path,
          param_names,
          page_handler: Some(handler),
          api_handler: None,
          layouts: inherited_layouts.copy(),
          middlewares: inherited_middlewares.copy(),
          kind: SolRouteKind::Page,
          title,
          meta,
          catch_all,
          revalidate,
          cache_strategy: cache.unwrap_or(CacheStrategy::AlwaysFetch),
          rendered_meta: render_meta_tags(meta),
        })
      }
      Layout(segment~, layout~, children~) => {
        let new_prefix = normalize_path(prefix + segment)
        let new_layouts = inherited_layouts.copy()
        new_layouts.push(layout)
        compile_sol_routes_inner(
          children, new_prefix, new_layouts, inherited_middlewares, result,
        )
      }
      Get(path~, handler~) =>
        push_api_route(result, prefix, path, handler, GetApi, inherited_middlewares)
      Post(path~, handler~) =>
        push_api_route(result, prefix, path, handler, PostApi, inherited_middlewares)
      Put(path~, handler~) =>
        push_api_route(result, prefix, path, handler, PutApi, inherited_middlewares)
      Delete(path~, handler~) =>
        push_api_route(result, prefix, path, handler, DeleteApi, inherited_middlewares)
      Patch(path~, handler~) =>
        push_api_route(result, prefix, path, handler, PatchApi, inherited_middlewares)
      WithMiddleware(middleware~, children~) => {
        let new_middlewares = inherited_middlewares + middleware
        compile_sol_routes_inner(
          children, prefix, inherited_layouts, new_middlewares, result,
        )
      }
    }
  }
}