//! Strongly-typed IDs used throughout the framework.

use serde::{Deserialize, Serialize};
use std::fmt;

/// Unique identifier for a single agent run.
///
/// Backed by ULID — sortable by creation time.
///
/// ```
/// use klieo_core::ids::RunId;
/// let a = RunId::new();
/// let b = RunId::new();
/// assert_ne!(a, b);
/// assert_eq!(a.to_string().len(), 26);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct RunId(pub ulid::Ulid);

impl RunId {
    /// Generate a fresh ID.
    pub fn new() -> Self {
        Self(ulid::Ulid::new())
    }
}

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

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

/// Identifies a conversation thread for short-term memory scoping.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ThreadId(pub String);

impl ThreadId {
    /// Wrap a string as a thread id.
    pub fn new(s: impl Into<String>) -> Self {
        Self(s.into())
    }
}

impl fmt::Display for ThreadId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(&self.0)
    }
}

/// Identifier for an enqueued job in `JobQueue`.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct JobId(pub String);

impl JobId {
    /// Wrap a string as a job id.
    pub fn new(s: impl Into<String>) -> Self {
        Self(s.into())
    }
}

impl fmt::Display for JobId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(&self.0)
    }
}

/// Identifier for a stored fact in `LongTermMemory`.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct FactId(pub String);

impl FactId {
    /// Wrap a string as a fact id.
    pub fn new(s: impl Into<String>) -> Self {
        Self(s.into())
    }
}

impl fmt::Display for FactId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(&self.0)
    }
}

/// Durable consumer name for a JetStream-style subscription.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct DurableName(pub String);

impl DurableName {
    /// Wrap a string as a durable consumer name.
    pub fn new(s: impl Into<String>) -> Self {
        Self(s.into())
    }
}
