//! End-to-end proof that a plugin observes a real `ctx_read` event.
//!
//! This is its own integration-test binary, so the process-global plugin
//! registry (`OnceLock`) is fresh and uncontended: we point it at an isolated
//! plugins root via `LEAN_CTX_PLUGINS_DIR`, perform a genuine read through the
//! public `ctx_read::handle` entry, and assert the plugin's `pre_read` hook
//! actually ran (it writes a sentinel file). Unix-only: the hook is a `sh`
//! script.

#![cfg(unix)]

use std::fs;
use std::time::{Duration, Instant};

use lean_ctx::core::cache::SessionCache;
use lean_ctx::core::plugins::PluginManager;
use lean_ctx::core::protocol::CrpMode;
use lean_ctx::tools::ctx_read;

#[test]
fn plugin_observes_real_read_event() {
    let root = tempfile::tempdir().expect("tempdir");
    let plugin_dir = root.path().join("sentinel-plugin");
    fs::create_dir_all(&plugin_dir).expect("plugin dir");

    // The hook writes a sentinel into the plugin's own directory; the executor
    // exports LEAN_CTX_PLUGIN_DIR (the single plugin's path) for the child.
    let script = plugin_dir.join("hook.sh");
    fs::write(
        &script,
        "#!/bin/sh\nprintf fired > \"$LEAN_CTX_PLUGIN_DIR/fired\"\n",
    )
    .expect("script");

    fs::write(
        plugin_dir.join("plugin.toml"),
        format!(
            "[plugin]\nname = \"sentinel-plugin\"\nversion = \"1.0.0\"\n\n\
             [hooks.pre_read]\ncommand = \"sh {}\"\ntimeout_ms = 5000\n",
            script.display()
        ),
    )
    .expect("manifest");

    // Point the global registry at our isolated root, then activate it.
    // TODO: Audit that the environment access only happens in single-threaded code.
    unsafe { std::env::set_var("LEAN_CTX_PLUGINS_DIR", root.path()) };
    PluginManager::init();
    assert!(
        PluginManager::has_listener("pre_read"),
        "the installed plugin should register a pre_read listener"
    );

    // Perform a genuine read through the public read entry point.
    let target = root.path().join("target.rs");
    fs::write(&target, "fn main() { println!(\"hi\"); }\n").expect("target");
    let mut cache = SessionCache::new();
    let _ = ctx_read::handle(&mut cache, target.to_str().unwrap(), "full", CrpMode::Off);

    // Hooks fire in the background; poll for the sentinel the hook writes.
    let sentinel = plugin_dir.join("fired");
    let deadline = Instant::now() + Duration::from_secs(10);
    while Instant::now() < deadline && !sentinel.exists() {
        std::thread::sleep(Duration::from_millis(50));
    }

    assert!(
        sentinel.exists(),
        "pre_read hook should have executed and written the sentinel"
    );
    assert_eq!(fs::read_to_string(&sentinel).expect("sentinel"), "fired");
}
