//! Session management module.
//!
//! Provides PTY-based session management for multiple Claude Code instances.

pub mod command;
pub mod event;
pub mod manager;
pub mod osc;
pub mod pty;

pub use command::{AutoInputStep, SessionCommand};
pub use event::SessionEvent;
pub use manager::SessionManager;
pub use osc::{OscParser, OscResult};
pub use pty::{NativePty, PtyConfig, PtyHandle};

use std::path::PathBuf;
use std::time::Instant;

/// Session identifier (UUID v4)
pub type SessionId = uuid::Uuid;

/// Session lifecycle status
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SessionStatus {
    /// PTY spawning in progress
    Starting,
    /// Process running
    Running,
    /// Process terminated
    Terminated {
        /// Exit code if available
        exit_code: Option<i32>,
    },
}

/// Session representation
#[derive(Debug, Clone)]
pub struct Session {
    /// Unique session identifier
    pub id: SessionId,
    /// Session name (from OSC title or user-specified)
    pub name: String,
    /// Current status
    pub status: SessionStatus,
    /// Associated git worktree path
    pub worktree_path: Option<PathBuf>,
    /// Creation timestamp
    pub created_at: Instant,
}

impl Session {
    /// Create new session with generated ID
    #[must_use]
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            id: SessionId::new_v4(),
            name: name.into(),
            status: SessionStatus::Starting,
            worktree_path: None,
            created_at: Instant::now(),
        }
    }

    /// Create session with specific ID (for testing)
    #[must_use]
    pub fn with_id(id: SessionId, name: impl Into<String>) -> Self {
        Self {
            id,
            name: name.into(),
            status: SessionStatus::Starting,
            worktree_path: None,
            created_at: Instant::now(),
        }
    }
}

#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
    use super::*;

    #[test]
    fn session_new_generates_unique_id() {
        let s1 = Session::new("test1");
        let s2 = Session::new("test2");
        assert_ne!(s1.id, s2.id);
    }

    #[test]
    fn session_with_id_preserves_id() {
        let id = SessionId::new_v4();
        let session = Session::with_id(id, "test");
        assert_eq!(session.id, id);
        assert_eq!(session.name, "test");
    }

    #[test]
    fn session_default_status_starting() {
        let session = Session::new("test");
        assert_eq!(session.status, SessionStatus::Starting);
    }
}
