/*!
 * Provider Lock (skeleton)
 *
 * Phase 15.5 受け口: 型→Provider のロック状態を保持するための最小スケルトン。
 * 既定では挙動を変えず、環境変数により警告/エラー化のみ可能にする。
 */

use crate::boxes::file::provider::{FileCaps, FileIo};
use crate::runtime::get_global_ring0;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, OnceLock};

static LOCKED: AtomicBool = AtomicBool::new(false);
static WARN_ONCE: OnceLock<()> = OnceLock::new();
static FILEBOX_PROVIDER: OnceLock<Arc<dyn FileIo>> = OnceLock::new();

/// Return true when providers are locked
pub fn is_locked() -> bool {
    LOCKED.load(Ordering::Relaxed)
}

/// Lock providers (idempotent)
pub fn lock_providers() {
    LOCKED.store(true, Ordering::Relaxed);
}

/// Guard called before creating a new box instance.
/// Default: no-op. When NYASH_PROVIDER_LOCK_STRICT=1, returns Err if not locked.
/// When NYASH_PROVIDER_LOCK_WARN=1, prints a warning once.
pub fn guard_before_new_box(box_type: &str) -> Result<(), String> {
    if is_locked() {
        return Ok(());
    }
    let strict = std::env::var("NYASH_PROVIDER_LOCK_STRICT").ok().as_deref() == Some("1");
    let warn = std::env::var("NYASH_PROVIDER_LOCK_WARN").ok().as_deref() == Some("1");
    if strict {
        return Err(format!(
            "E_PROVIDER_NOT_LOCKED: attempted to create '{}' before Provider Lock",
            box_type
        ));
    }
    if warn {
        // Print once per process
        let _ = WARN_ONCE.get_or_init(|| {
            get_global_ring0().log.warn(
                "[provider-lock][warn] NewBox emitted before Provider Lock. Set NYASH_PROVIDER_LOCK_STRICT=1 to error.",
            );
        });
    }
    Ok(())
}

/// Set the global FileBox provider (can only be called once)
pub fn set_filebox_provider(provider: Arc<dyn FileIo>) -> Result<(), String> {
    FILEBOX_PROVIDER
        .set(provider)
        .map_err(|_| "FileBox provider already set".to_string())
}

/// Get the global FileBox provider
pub fn get_filebox_provider() -> Option<&'static Arc<dyn FileIo>> {
    FILEBOX_PROVIDER.get()
}

/// Convenience: fetch current FileBox provider capabilities (if initialized).
/// Returns None when no provider is registered yet.
pub fn get_filebox_caps() -> Option<FileCaps> {
    get_filebox_provider().map(|p| p.caps())
}
