//! Domain layer - core business entities and rules.
//!
//! This layer contains the fundamental types and traits for reactive
//! configuration management:
//!
//! - [`ReactiveError`] - Domain error types
//! - [`ChangeHandler`] - Handler for configuration changes
//! - [`ConfigChange`] - Configuration change event
//! - [`Subscription`] - Subscription configuration
//! - [`FileWatcher`] - File watching trait

mod error;
mod handler;
mod query;
mod stream;
mod subscription;
mod watch;

// Re-exports from new types
pub use error::{ReactiveError, Result};
pub use handler::{ChangeHandler, ErrorStrategy};
pub use query::{AndQuery, FieldQuery, KindQuery, NotQuery, OrQuery, PathQuery, QueryMatcher};
pub use stream::{ChangeKind, ChangeSource, ConfigChange, ConfigStream};
pub use subscription::{Subscription, SubscriptionBuilder, SubscriptionId, SubscriptionKind};
pub use watch::{FileEvent, FileEventKind, FileWatcher, WatchConfig};

#[cfg(feature = "async")]
pub use handler::AsyncChangeHandler;

#[cfg(feature = "async")]
pub use stream::AsyncConfigStream;

#[cfg(feature = "async")]
pub use watch::AsyncFileWatcher;

// Legacy compatibility - re-export old types for backward compatibility
// These will be deprecated in a future version

/// Legacy error type alias for backward compatibility.
#[deprecated(since = "2.1.0", note = "Use ReactiveError instead")]
pub type Error = ReactiveError;

/// Unique identifier for a handler.
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct HandlerId(String);

impl HandlerId {
    /// Creates a new handler ID.
    #[must_use]
    pub fn new(id: impl Into<String>) -> Self {
        Self(id.into())
    }

    /// Returns the ID as a string slice.
    #[must_use]
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl Default for HandlerId {
    fn default() -> Self {
        Self::new("default")
    }
}

impl std::fmt::Display for HandlerId {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// Legacy Event type for backward compatibility.
#[derive(Debug, Clone)]
pub struct Event {
    /// Kind of event.
    pub kind: EventKind,
    /// Path that changed.
    pub path: String,
    /// Metadata for the event.
    pub metadata: EventMetadata,
}

/// Kind of configuration event.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EventKind {
    /// Configuration created.
    Create,
    /// Configuration updated.
    Update,
    /// Configuration deleted.
    Delete,
    /// Configuration file changed.
    Change,
    /// Configuration reloaded.
    Reload,
}

/// Metadata associated with an event.
#[derive(Debug, Clone)]
pub struct EventMetadata {
    /// Source path or identifier.
    pub source: String,
    /// Timestamp of the event.
    pub timestamp: u64,
    /// Optional correlation ID.
    pub correlation_id: Option<String>,
}

impl EventMetadata {
    /// Create new event metadata.
    #[must_use]
    pub fn new(source: impl Into<String>) -> Self {
        Self {
            source: source.into(),
            timestamp: current_timestamp(),
            correlation_id: None,
        }
    }
}

impl Event {
    /// Create a new event.
    #[must_use]
    pub fn new(kind: EventKind, path: impl Into<String>, metadata: EventMetadata) -> Self {
        Self {
            kind,
            path: path.into(),
            metadata,
        }
    }

    /// Create a change event.
    #[must_use]
    pub fn change(path: impl Into<String>) -> Self {
        Self::new(EventKind::Change, path, EventMetadata::new("file-watcher"))
    }
}

/// Legacy Handler trait for backward compatibility.
pub trait Handler: Send + Sync {
    /// Returns the handler ID.
    fn id(&self) -> &HandlerId;

    /// Handle an event.
    ///
    /// # Errors
    ///
    /// Returns an error if handling fails.
    fn handle(&self, event: &Event) -> Result<()>;
}

/// Boxed handler type.
pub type BoxedHandler = std::sync::Arc<dyn Handler>;

/// Get current timestamp in milliseconds.
fn current_timestamp() -> u64 {
    std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|d| u64::try_from(d.as_millis()).unwrap_or(0))
        .unwrap_or(0)
}
