use std::sync::atomic::{AtomicU64, Ordering};

use tracing_serde_structured::AsSerde;

use crate::wit;

/// A [`tracing::Subscriber`] that forwards events to the host server over WIT.
///
/// Installed automatically as the global subscriber when the plugin is loaded.
pub(crate) struct WitSubscriber {
    next_id: AtomicU64,
}

impl WitSubscriber {
    /// Creates a new `WitSubscriber` with the span ID counter starting at `1`.
    pub const fn new() -> Self {
        Self {
            next_id: AtomicU64::new(1),
        }
    }
}

impl tracing::Subscriber for WitSubscriber {
    /// Always returns `true` — all log levels are forwarded to the host.
    fn enabled(&self, _metadata: &tracing::Metadata<'_>) -> bool {
        true
    }

    /// Allocates a new monotonically increasing span ID.
    fn new_span(&self, _attrs: &tracing::span::Attributes<'_>) -> tracing::span::Id {
        let id = self.next_id.fetch_add(1, Ordering::Relaxed);
        tracing::span::Id::from_u64(id)
    }

    /// No-op — span field recording is not forwarded to the host.
    fn record(&self, _span: &tracing::span::Id, _values: &tracing::span::Record<'_>) {}

    /// No-op — causality links are not forwarded to the host.
    fn record_follows_from(&self, _span: &tracing::span::Id, _follows: &tracing::span::Id) {}

    /// Serialises the tracing event with `postcard` and sends it to the host via WIT.
    fn event(&self, event: &tracing::Event<'_>) {
        if let Ok(serialized) = postcard::to_allocvec(&event.as_serde()) {
            wit::pumpkin::plugin::logging::log_tracing(&serialized);
        }
    }

    /// No-op — span entry is not tracked.
    fn enter(&self, _span: &tracing::span::Id) {}

    /// No-op — span exit is not tracked.
    fn exit(&self, _span: &tracing::span::Id) {}
}

/// The log severity level used with [`log`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogLevel {
    /// Very fine-grained diagnostic information.
    Trace,
    /// Diagnostic information useful during development.
    Debug,
    /// General informational messages.
    Info,
    /// Potentially harmful situations that do not stop execution.
    Warn,
    /// Errors that may require attention.
    Error,
}

impl LogLevel {
    /// Converts this level to the WIT-generated `Level` type expected by the host.
    const fn to_wit(self) -> wit::pumpkin::plugin::logging::Level {
        match self {
            Self::Trace => wit::pumpkin::plugin::logging::Level::Trace,
            Self::Debug => wit::pumpkin::plugin::logging::Level::Debug,
            Self::Info => wit::pumpkin::plugin::logging::Level::Info,
            Self::Warn => wit::pumpkin::plugin::logging::Level::Warn,
            Self::Error => wit::pumpkin::plugin::logging::Level::Error,
        }
    }
}

/// Sends a log message to the server at the given severity level.
///
/// Prefer the standard `tracing` macros (`tracing::info!`, `tracing::warn!`, etc.)
/// for structured logging; use this function when you need a direct, low-level log call.
pub fn log(level: LogLevel, message: &str) {
    wit::pumpkin::plugin::logging::log(level.to_wit(), message);
}
