//! The `Plugin` trait: every plugin in Folk implements this.

use anyhow::Result;
use async_trait::async_trait;

use crate::context::PluginContext;
use crate::role::Placement;
use crate::rpc::RpcMethodDef;

/// Lifecycle of a Folk plugin.
///
/// At server startup, plugins are booted in registration order. At shutdown,
/// they are stopped in reverse order. A plugin that holds long-running tasks
/// should consider implementing [`crate::ServerPlugin`] instead — the wrapper
/// handles the boilerplate of spawning, holding handles, and joining.
#[async_trait]
pub trait Plugin: Send + Sync + 'static {
    /// Stable plugin name. Conventionally lowercase, single-word: `"http"`,
    /// `"jobs"`, `"metrics"`. Used for log scoping, health/metric labels,
    /// and config-section routing in custom builds.
    fn name(&self) -> &'static str;

    /// Called once at server startup. Register RPC methods, health checks,
    /// and metrics via `ctx`, then spawn background tasks. Returning `Err`
    /// is fatal: the server aborts startup.
    async fn boot(&mut self, ctx: PluginContext) -> Result<()>;

    /// Called during graceful shutdown. Returning `Err` is logged but does
    /// not abort shutdown of other plugins.
    async fn shutdown(&self) -> Result<()>;

    /// Optional: the RPC methods this plugin exposes. Used for advertising
    /// (e.g., `folk admin list-methods`). Default is empty.
    fn rpc_methods(&self) -> Vec<RpcMethodDef> {
        Vec::new()
    }

    /// Where this plugin runs in the fork-after-warm model (phase 79).
    ///
    /// The core boots the plugin only in the process(es) named here. The
    /// default is [`Placement::WorkerOnly`] — the common case (HTTP/gRPC/jobs
    /// dispatch PHP and live in workers). Master-only plugins (supervisors, the
    /// metrics scrape server) override this to [`Placement::MasterOnly`].
    fn placement(&self) -> Placement {
        Placement::WorkerOnly
    }

    /// Whether this plugin must be booted in **every** worker pool, not just its
    /// own (phase 85).
    ///
    /// Default `false`: a worker-plugin runs only in its pool (a dedicated
    /// `[<plugin>].workers` pool, or the shared pool). `true` means the plugin
    /// exposes a cross-cutting capability that other pools call into — e.g.
    /// `jobs` enqueue (`jobs.push`), invoked from an HTTP handler running in a
    /// separate `http` pool. Because Folk's RPC is process-local (zero-IPC), the
    /// only way that call resolves is for the `jobs` plugin to also be present in
    /// the `http` pool. Such a plugin branches on
    /// [`PoolContext::primary`](crate::PoolContext::primary) to do its heavy work
    /// (run consumers) only in its owning pool and stay push-only elsewhere.
    fn runs_in_every_pool(&self) -> bool {
        false
    }
}
