// Sol ISR Middleware
//
// Middleware for handling ISR (Incremental Static Regeneration) in Sol.
// Integrates ISR handler with Sol's middleware pipeline.

// =============================================================================
// ISR Middleware
// =============================================================================

///|
/// ISR middleware configuration
pub struct ISRMiddlewareConfig {
  /// Distribution directory (where static files are)
  dist_dir : String
  /// Whether to enable ISR
  enabled : Bool
}

///|
/// Default ISR middleware configuration
pub fn ISRMiddlewareConfig::default() -> ISRMiddlewareConfig {
  { dist_dir: "dist", enabled: true }
}

// =============================================================================
// Global ISR Handler (singleton for the server)
// =============================================================================

///|
let isr_handler_store : Ref[ISRHandler[MemoryCache]?] = Ref(None)

///|
/// Initialize ISR handler (call once at server startup)
pub async fn init_isr(dist_dir : String) -> ISRHandler[MemoryCache] {
  let cache = MemoryCache::new()
  let manifest = load_manifest(dist_dir)
  let handler = ISRHandler::new(cache, manifest, dist_dir)
  isr_handler_store.val = Some(handler)
  handler
}

///|
/// Get the global ISR handler
pub fn get_isr_handler() -> ISRHandler[MemoryCache]? {
  isr_handler_store.val
}

// =============================================================================
// ISR Request Handler
// =============================================================================

///|
/// Handle ISR for a request path
/// Returns Some(html) if ISR handled, None otherwise
pub async fn handle_isr_request(path : String) -> (String?, Bool) {
  match get_isr_handler() {
    Some(handler) => handler.handle(path)
    None => (None, false)
  }
}

///|
/// Schedule background revalidation for a path
pub fn schedule_revalidation(path : String) -> Unit {
  match get_isr_handler() {
    Some(handler) =>
      handler.cache.schedule_revalidation(async fn() {
        // In a real implementation, this would call SSG to regenerate
        // For now, just log
        println("ISR: Revalidating \{path}")
        // Read fresh content from disk (assumes SSG has regenerated)
        let fresh_html = read_static_page(handler.dist_dir, path)
        match fresh_html {
          Some(html) => handler.update_cache(path, html)
          None => ()
        }
      })
    None => ()
  }
}

// =============================================================================
// Hono Integration
// =============================================================================

///|
/// Create ISR handler for Hono
/// Returns a function that can be used as Hono middleware
pub async fn create_isr_middleware(
  dist_dir : String,
) -> (@hono.Context[Unit, Unit]) -> @js.Promise[Unit]? {
  // Initialize ISR handler
  let _ = init_isr(dist_dir)

  // Return middleware function — note: the returned closure is sync
  // because Hono expects sync middleware. ISR handle is called via
  // handle_isr_request_sync which uses the pre-loaded cache.
  fn(ctx : @hono.Context[Unit, Unit]) -> @js.Promise[Unit]? {
    let path = ffi_get_req_path(ctx.as_any())

    // Check ISR from cache (sync path — cache is already populated)
    let handler = match get_isr_handler() {
      Some(h) => h
      None => return None
    }
    let page_meta = match handler.manifest.get_page(path) {
      Some(meta) => meta
      None => return None
    }
    let key = cache_key(path, [])
    let entry = handler.cache.get(key)
    let now = now_ms()
    let status = check_status(entry, now)
    let (html, needs_revalidation) = match status {
      Fresh =>
        match entry {
          Some(e) => (Some(e.html), false)
          None => (None, false)
        }
      Stale =>
        match entry {
          Some(e) => (Some(e.html), true)
          None => (None, true)
        }
      Miss => {
        // On cache miss, we can't do async file read in sync context
        // Return None to fall through to next handler
        ignore(page_meta)
        (None, false)
      }
    }
    match html {
      Some(content) => {
        if needs_revalidation {
          schedule_revalidation(path)
        }
        Some(ffi_return_html(ctx.as_any(), content))
      }
      None => None
    }
  }
}

///|
extern "js" fn ffi_get_req_path(ctx : @js.Any) -> String =
  #| (c) => new URL(c.req.url).pathname

///|
extern "js" fn ffi_return_html(
  ctx : @js.Any,
  html : String,
) -> @js.Promise[Unit] =
  #| (c, html) => c.html(html)