//! Timer component for Bubble Tea applications.
//!
//! Package timer provides a simple timeout component for Bubble Tea applications.
//! It closely matches the Go bubbles timer component API for 1-1 compatibility.
//!
//! # Basic Usage
//!
//! ```rust
//! use bubbletea_widgets::timer::{new, new_with_interval};
//! use std::time::Duration;
//!
//! // Create a timer with default 1 second interval
//! let timer = new(Duration::from_secs(30));
//!
//! // Create a timer with custom interval
//! let timer = new_with_interval(Duration::from_secs(60), Duration::from_millis(100));
//! ```
//!
//! # bubbletea-rs Integration
//!
//! ```rust
//! use bubbletea_rs::{Model as BubbleTeaModel, Msg, Cmd};
//! use bubbletea_widgets::timer::{new, Model, TickMsg, StartStopMsg, TimeoutMsg};
//! use std::time::Duration;
//!
//! struct MyApp {
//!     timer: Model,
//! }
//!
//! impl BubbleTeaModel for MyApp {
//!     fn init() -> (Self, Option<Cmd>) {
//!         let timer = new(Duration::from_secs(10));
//!         let cmd = timer.init();
//!         (Self { timer }, Some(cmd))
//!     }
//!
//!     fn update(&mut self, msg: Msg) -> Option<Cmd> {
//!         // Handle timeout
//!         if let Some(timeout) = msg.downcast_ref::<TimeoutMsg>() {
//!             if timeout.id == self.timer.id() {
//!                 // Timer finished!
//!             }
//!         }
//!         
//!         // Forward timer messages
//!         self.timer.update(msg)
//!     }
//!
//!     fn view(&self) -> String {
//!         format!("Time remaining: {}", self.timer.view())
//!     }
//! }
//! ```
//!
//! # Start/Stop Control
//!
//! ```rust
//! use bubbletea_widgets::timer::new;
//! use std::time::Duration;
//!
//! let timer = new(Duration::from_secs(30));
//!
//! // These return commands that send StartStopMsg
//! let start_cmd = timer.start();   // Resume timer
//! let stop_cmd = timer.stop();     // Pause timer  
//! let toggle_cmd = timer.toggle(); // Toggle running state
//! ```

use bubbletea_rs::{tick as bubbletea_tick, Cmd, Model as BubbleTeaModel, Msg};
use std::sync::atomic::{AtomicI64, Ordering};
use std::time::{Duration, Instant};

// Internal ID management for timer instances
static LAST_ID: AtomicI64 = AtomicI64::new(0);

/// Generates unique identifiers for timer instances.
///
/// This function ensures that each timer created gets a unique ID, allowing
/// multiple timers to coexist in the same application without message conflicts.
/// The IDs are generated atomically and start from 1.
///
/// # Returns
///
/// A unique `i64` identifier for a timer instance
///
/// # Thread Safety
///
/// This function is thread-safe and can be called from multiple threads
/// concurrently without risk of duplicate IDs.
fn next_id() -> i64 {
    LAST_ID.fetch_add(1, Ordering::SeqCst) + 1
}

/// Formats a duration using Go's Duration.String() format for compatibility.
///
/// This function converts a Rust `Duration` into a string representation that
/// matches Go's duration formatting exactly, ensuring consistent display across
/// different language implementations of the bubbles library.
///
/// # Arguments
///
/// * `d` - The duration to format
///
/// # Returns
///
/// A formatted string representation of the duration
///
/// # Format Examples
///
/// - `0s` for zero duration
/// - `500ms` for milliseconds
/// - `1.5s` for seconds with decimals
/// - `2m30s` for minutes and seconds
/// - `1m` for exact minutes
///
/// # Examples
///
/// ```rust,ignore
/// use std::time::Duration;
///
/// assert_eq!(format_duration(Duration::from_secs(0)), "0s");
/// assert_eq!(format_duration(Duration::from_millis(500)), "500ms");
/// assert_eq!(format_duration(Duration::from_secs(90)), "1m30s");
/// ```
fn format_duration(d: Duration) -> String {
    let total_nanos = d.as_nanos();

    if total_nanos == 0 {
        return "0s".to_string();
    }

    // Convert to go-like format
    if total_nanos >= 1_000_000_000 {
        // Seconds or more
        let secs = d.as_secs_f64();
        if secs >= 60.0 {
            let minutes = (secs / 60.0) as u64;
            let remaining_secs = secs % 60.0;
            if remaining_secs == 0.0 {
                format!("{}m", minutes)
            } else {
                format!("{}m{:.0}s", minutes, remaining_secs)
            }
        } else if secs >= 1.0 {
            if secs == secs.floor() {
                format!("{:.0}s", secs)
            } else {
                format!("{:.1}s", secs)
            }
        } else {
            format!("{:.3}s", secs)
        }
    } else if total_nanos >= 1_000_000 {
        // Milliseconds
        format!("{}ms", d.as_millis())
    } else if total_nanos >= 1_000 {
        // Microseconds
        format!("{}µs", d.as_micros())
    } else {
        // Nanoseconds
        format!("{}ns", total_nanos)
    }
}

/// Message used to start and stop timer instances.
///
/// This message is sent by the timer's control methods (`start()`, `stop()`, `toggle()`)
/// to change the running state of a specific timer. The message includes the timer's
/// unique ID to ensure it only affects the intended timer instance.
///
/// # Examples
///
/// ```rust
/// use bubbletea_widgets::timer::new;
/// use std::time::Duration;
///
/// let timer = new(Duration::from_secs(30));
///
/// // Use the public API to control the timer
/// let start_cmd = timer.start();  // Creates StartStopMsg internally
/// let stop_cmd = timer.stop();    // Creates StartStopMsg internally
/// ```
///
/// # Note
///
/// The `running` field is intentionally private to ensure it can only be set
/// through the timer's control methods, maintaining proper state management.
#[derive(Debug, Clone)]
pub struct StartStopMsg {
    /// The unique identifier of the timer this message targets.
    ///
    /// Only timers with matching IDs will respond to this message,
    /// allowing multiple timers to coexist safely.
    pub id: i64,
    /// Whether the timer should be running after processing this message.
    ///
    /// This field is private to ensure proper state management through
    /// the timer's public control methods.
    running: bool,
}

/// Message sent on every timer tick to update the countdown.
///
/// This message is generated automatically by the timer at regular intervals
/// (determined by the timer's `interval` setting). Each tick reduces the remaining
/// timeout duration and triggers the next tick command.
///
/// # Message Filtering
///
/// Timers automatically filter tick messages to ensure they only process their own:
/// - Messages with mismatched IDs are ignored
/// - Messages with incorrect tags are rejected (prevents double-ticking)
/// - Messages sent to stopped timers are ignored
///
/// # Examples
///
/// ```rust
/// use bubbletea_widgets::timer::{TickMsg, new};
/// use std::time::Duration;
///
/// let timer = new(Duration::from_secs(30));
/// let timer_id = timer.id();
///
/// // This message would be generated internally by the timer
/// // Use the timer's tick() method instead of constructing manually:
/// let tick_cmd = timer.init(); // Starts the timer and generates tick messages
/// ```
///
/// # Timeout Detection
///
/// The `timeout` field indicates whether this tick represents the final
/// expiration of the timer. You can either check this field or listen
/// for separate `TimeoutMsg` messages.
#[derive(Debug, Clone)]
pub struct TickMsg {
    /// The unique identifier of the timer that generated this tick.
    ///
    /// This allows multiple timers to run simultaneously without interfering
    /// with each other. Each timer only processes ticks with its own ID.
    pub id: i64,

    /// Whether this tick represents a timeout (timer expiration).
    ///
    /// When `true`, this indicates the timer has reached zero and expired.
    /// You can alternatively listen for `TimeoutMsg` for timeout notifications.
    pub timeout: bool,

    /// Internal synchronization tag to prevent message overflow.
    ///
    /// This field is used internally to ensure timers don't process too many
    /// tick messages simultaneously, which could cause timing inaccuracies.
    /// Application code should not modify this field.
    tag: i64,
}

/// Message sent when a timer reaches zero and expires.
///
/// This is a convenience message that provides a clear notification when a timer
/// completes its countdown. It's sent in addition to the final `TickMsg` (which
/// will have `timeout: true`), giving applications two ways to detect timer expiration.
///
/// # Usage Pattern
///
/// Applications typically handle this message in their update loop to respond
/// to timer completion events, such as showing notifications, triggering actions,
/// or starting new timers.
///
/// # Examples
///
/// ```rust
/// use bubbletea_widgets::timer::{TimeoutMsg, new};
/// use bubbletea_rs::{Model as BubbleTeaModel, Msg};
/// use std::time::Duration;
///
/// struct App {
///     timer: bubbletea_widgets::timer::Model,
///     message: String,
/// }
///
/// impl BubbleTeaModel for App {
///     fn update(&mut self, msg: Msg) -> Option<bubbletea_rs::Cmd> {
///         // Handle timer timeout
///         if let Some(timeout) = msg.downcast_ref::<TimeoutMsg>() {
///             if timeout.id == self.timer.id() {
///                 self.message = "Timer expired!".to_string();
///             }
///         }
///         
///         self.timer.update(msg)
///     }
///
///     // ... other methods
/// #   fn init() -> (Self, Option<bubbletea_rs::Cmd>) { unimplemented!() }
/// #   fn view(&self) -> String { unimplemented!() }
/// }
/// ```
///
/// # Relationship to TickMsg
///
/// While `TickMsg` with `timeout: true` and `TimeoutMsg` both indicate timer
/// expiration, `TimeoutMsg` provides a cleaner, more semantic way to handle
/// completion events in your application logic.
#[derive(Debug, Clone)]
pub struct TimeoutMsg {
    /// The unique identifier of the timer that expired.
    ///
    /// Use this to identify which timer expired when multiple timers
    /// are running in the same application.
    pub id: i64,
}

/// High-precision countdown timer component for Bubble Tea applications.
///
/// This struct represents a timer that counts down from an initial timeout value
/// at regular intervals. It provides fine-grained control over timing behavior
/// and integrates seamlessly with the Bubble Tea message-passing architecture.
///
/// # Core Features
///
/// - **Precise Timing**: Configurable tick intervals for smooth countdown display
/// - **State Management**: Start, stop, and toggle operations with proper state tracking
/// - **Message Filtering**: Automatic ID-based filtering prevents cross-timer interference
/// - **Timeout Detection**: Multiple ways to detect and handle timer expiration
/// - **Go Compatibility**: API matches Go's bubbles timer for easy migration
///
/// # Examples
///
/// Basic timer usage:
/// ```rust
/// use bubbletea_widgets::timer::{new, new_with_interval};
/// use std::time::Duration;
///
/// // Create a 30-second timer with default 1-second ticks
/// let timer = new(Duration::from_secs(30));
/// assert_eq!(timer.timeout, Duration::from_secs(30));
/// assert!(timer.running());
///
/// // Create a timer with custom tick rate
/// let fast_timer = new_with_interval(
///     Duration::from_secs(10),
///     Duration::from_millis(100)
/// );
/// assert_eq!(fast_timer.interval, Duration::from_millis(100));
/// ```
///
/// Integration with Bubble Tea:
/// ```rust
/// use bubbletea_widgets::timer::{new, Model as TimerModel, TimeoutMsg};
/// use bubbletea_rs::{Model as BubbleTeaModel, Cmd, Msg};
/// use std::time::Duration;
///
/// struct App {
///     timer: TimerModel,
///     status: String,
/// }
///
/// impl BubbleTeaModel for App {
///     fn init() -> (Self, Option<Cmd>) {
///         let timer = new(Duration::from_secs(5));
///         let cmd = timer.init();
///         (App {
///             timer,
///             status: "Timer running...".to_string(),
///         }, Some(cmd))
///     }
///
///     fn update(&mut self, msg: Msg) -> Option<Cmd> {
///         // Handle timeout events
///         if let Some(timeout) = msg.downcast_ref::<TimeoutMsg>() {
///             if timeout.id == self.timer.id() {
///                 self.status = "Time's up!".to_string();
///                 return None;
///             }
///         }
///         
///         // Forward other messages to timer
///         self.timer.update(msg)
///     }
///
///     fn view(&self) -> String {
///         format!("{} - Remaining: {}", self.status, self.timer.view())
///     }
/// }
/// ```
///
/// # State Management
///
/// The timer maintains several important states:
/// - **Running**: Whether the timer is actively counting down
/// - **Timeout**: The remaining time until expiration  
/// - **ID**: Unique identifier for message filtering
/// - **Tag**: Internal synchronization for accurate timing
///
/// # Thread Safety
///
/// The Model struct is `Clone` and can be safely passed between threads.
/// Each timer instance maintains its own unique ID to prevent conflicts.
///
/// # Performance Considerations
///
/// - Faster intervals (< 100ms) provide smoother display but use more CPU
/// - Multiple timers can run simultaneously without significant overhead
/// - Message filtering ensures efficient processing in complex applications
#[derive(Debug, Clone)]
pub struct Model {
    /// The remaining time until the timer expires.
    ///
    /// This value decreases by `interval` on each tick. When it reaches zero
    /// or below, the timer is considered expired and will stop automatically.
    pub timeout: Duration,

    /// The time between each timer tick.
    ///
    /// This controls how frequently the timer updates its display and sends
    /// tick messages. Smaller intervals provide smoother countdown display
    /// but consume more resources. Default is 1 second.
    pub interval: Duration,

    /// Unique identifier for this timer instance.
    ///
    /// Used to filter messages and ensure timers only respond to their own
    /// tick and control messages. Generated automatically on creation.
    id: i64,
    /// Internal synchronization tag for accurate timing.
    ///
    /// Used to prevent the timer from processing too many tick messages
    /// simultaneously, which could cause timing drift or inaccuracies.
    tag: i64,
    /// Whether the timer is currently counting down.
    ///
    /// When `false`, the timer ignores tick messages and remains paused.
    /// Can be controlled via `start()`, `stop()`, and `toggle()` methods.
    running: bool,
    /// The time when this timer was started.
    ///
    /// Used for accurate timing calculations. Set when the timer first
    /// starts running and updated when resumed after pausing.
    start_instant: Option<Instant>,
    /// The time when the last tick was processed.
    ///
    /// Used to calculate actual elapsed time between ticks, providing
    /// more accurate countdown timing than interval-based calculations.
    last_tick: Option<Instant>,
}

/// Creates a new timer with custom timeout and tick interval.
///
/// This function provides full control over timer behavior by allowing you to specify
/// both the initial countdown duration and how frequently the timer updates. Use this
/// when you need precise control over timing granularity or want smoother display updates.
///
/// # Arguments
///
/// * `timeout` - The initial countdown duration (how long until the timer expires)
/// * `interval` - How frequently the timer ticks and updates its display
///
/// # Returns
///
/// A new `Model` instance configured with the specified timing parameters
///
/// # Examples
///
/// ```rust
/// use bubbletea_widgets::timer::new_with_interval;
/// use std::time::Duration;
///
/// // Create a 30-second timer that updates every 100ms (smooth display)
/// let smooth_timer = new_with_interval(
///     Duration::from_secs(30),
///     Duration::from_millis(100)
/// );
/// assert_eq!(smooth_timer.timeout, Duration::from_secs(30));
/// assert_eq!(smooth_timer.interval, Duration::from_millis(100));
/// assert!(smooth_timer.running());
/// ```
///
/// Different use cases:
/// ```rust
/// use bubbletea_widgets::timer::new_with_interval;
/// use std::time::Duration;
///
/// // High-precision timer for animations (60 FPS)
/// let animation_timer = new_with_interval(
///     Duration::from_secs(5),
///     Duration::from_millis(16) // ~60 FPS
/// );
///
/// // Battery-friendly timer for long countdowns
/// let efficient_timer = new_with_interval(
///     Duration::from_secs(3600), // 1 hour
///     Duration::from_secs(5)     // Update every 5 seconds
/// );
///
/// // Precise scientific timer
/// let precise_timer = new_with_interval(
///     Duration::from_millis(500),
///     Duration::from_millis(10)
/// );
/// ```
///
/// # Performance Considerations
///
/// - **Smaller intervals** provide smoother display but use more CPU and battery
/// - **Larger intervals** are more efficient but may appear jerky
/// - Consider your application's needs when choosing interval duration
/// - For display-only timers, 100ms-1000ms intervals work well
/// - For animations, 16ms (60 FPS) provides smooth motion
///
/// # Timing Accuracy
///
/// The timer's accuracy depends on the underlying system's timer resolution
/// and the Bubble Tea framework's message processing speed. Very small intervals
/// (< 10ms) may not be achievable on all systems.
///
/// # Note
///
/// This function matches Go's `NewWithInterval` function exactly for compatibility
/// with existing bubbles applications.
pub fn new_with_interval(timeout: Duration, interval: Duration) -> Model {
    Model {
        timeout,
        interval,
        running: true,
        id: next_id(),
        tag: 0,
        start_instant: None,
        last_tick: None,
    }
}

/// Creates a new timer with the specified timeout and default 1-second interval.
///
/// This is the most common way to create a timer. It uses a sensible default of
/// 1-second intervals, which provides a good balance between display smoothness
/// and resource usage for most applications.
///
/// # Arguments
///
/// * `timeout` - The initial countdown duration (how long until the timer expires)
///
/// # Returns
///
/// A new `Model` instance with 1-second tick intervals
///
/// # Examples
///
/// ```rust
/// use bubbletea_widgets::timer::new;
/// use std::time::Duration;
///
/// // Create a 30-second countdown timer
/// let timer = new(Duration::from_secs(30));
/// assert_eq!(timer.timeout, Duration::from_secs(30));
/// assert_eq!(timer.interval, Duration::from_secs(1)); // Default interval
/// assert!(timer.running());
/// assert!(!timer.timedout());
/// ```
///
/// Common timer durations:
/// ```rust
/// use bubbletea_widgets::timer::new;
/// use std::time::Duration;
///
/// // Short timer for notifications
/// let notification = new(Duration::from_secs(5));
///
/// // Medium timer for breaks
/// let break_timer = new(Duration::from_secs(300)); // 5 minutes
///
/// // Long timer for cooking
/// let cooking_timer = new(Duration::from_secs(1800)); // 30 minutes
///
/// // Sub-second timer for quick actions
/// let quick_timer = new(Duration::from_millis(750));
/// ```
///
/// Integration with Bubble Tea:
/// ```rust
/// use bubbletea_widgets::timer::new;
/// use bubbletea_rs::{Model as BubbleTeaModel, Cmd};
/// use std::time::Duration;
///
/// struct App {
///     timer: bubbletea_widgets::timer::Model,
/// }
///
/// impl BubbleTeaModel for App {
///     fn init() -> (Self, Option<Cmd>) {
///         let timer = new(Duration::from_secs(60));
///         let init_cmd = timer.init(); // Start the timer
///         (App { timer }, Some(init_cmd))
///     }
///     
///     // ... other methods
/// #   fn update(&mut self, _: bubbletea_rs::Msg) -> Option<Cmd> { None }
/// #   fn view(&self) -> String { self.timer.view() }
/// }
/// ```
///
/// # Default Configuration
///
/// - **Interval**: 1 second (good balance of smoothness and efficiency)
/// - **State**: Running (timer starts immediately)
/// - **ID**: Unique identifier generated automatically
/// - **Display**: Shows remaining time in Go's duration format
///
/// # When to Use
///
/// Use this function when:
/// - You want standard 1-second timer updates
/// - Resource efficiency is important
/// - You don't need sub-second display precision
/// - Building typical countdown or timeout functionality
///
/// Use `new_with_interval()` instead when you need:
/// - Smoother display updates (< 1 second intervals)
/// - High-precision timing
/// - Custom update frequencies
///
/// # Note
///
/// This function matches Go's `New` function exactly for compatibility
/// with existing bubbles applications.
pub fn new(timeout: Duration) -> Model {
    new_with_interval(timeout, Duration::from_secs(1))
}

impl Model {
    /// Returns the unique identifier of this timer instance.
    ///
    /// Each timer gets a unique ID when created, allowing multiple timers to coexist
    /// in the same application without interfering with each other. This ID is used
    /// internally for message filtering and can be used by applications to identify
    /// which timer generated specific messages.
    ///
    /// # Returns
    ///
    /// The unique `i64` identifier for this timer
    ///
    /// # Examples
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let timer1 = new(Duration::from_secs(30));
    /// let timer2 = new(Duration::from_secs(60));
    ///
    /// // Each timer has a unique ID
    /// assert_ne!(timer1.id(), timer2.id());
    /// assert!(timer1.id() > 0);
    /// assert!(timer2.id() > 0);
    /// ```
    ///
    /// Using ID to identify timer messages:
    /// ```rust
    /// use bubbletea_widgets::timer::{new, TimeoutMsg};
    /// use bubbletea_rs::{Model as BubbleTeaModel, Msg};
    /// use std::time::Duration;
    ///
    /// struct App {
    ///     work_timer: bubbletea_widgets::timer::Model,
    ///     break_timer: bubbletea_widgets::timer::Model,
    /// }
    ///
    /// impl BubbleTeaModel for App {
    ///     fn update(&mut self, msg: Msg) -> Option<bubbletea_rs::Cmd> {
    ///         if let Some(timeout) = msg.downcast_ref::<TimeoutMsg>() {
    ///             if timeout.id == self.work_timer.id() {
    ///                 // Work period finished
    ///             } else if timeout.id == self.break_timer.id() {
    ///                 // Break period finished
    ///             }
    ///         }
    ///         None
    ///     }
    ///     
    ///     // ... other methods
    /// #   fn init() -> (Self, Option<bubbletea_rs::Cmd>) { unimplemented!() }
    /// #   fn view(&self) -> String { unimplemented!() }
    /// }
    /// ```
    ///
    /// # Thread Safety
    ///
    /// The ID is assigned atomically during timer creation and remains constant
    /// throughout the timer's lifetime, making it safe to use across threads.
    ///
    /// # Note
    ///
    /// This method matches Go's `ID()` method exactly for compatibility.
    pub fn id(&self) -> i64 {
        self.id
    }

    /// Returns whether the timer is currently counting down.
    ///
    /// A timer is considered running when it's actively counting down and has not
    /// expired. This method returns `false` if the timer has been manually stopped
    /// or if it has reached zero and timed out.
    ///
    /// # Returns
    ///
    /// `true` if the timer is actively counting down, `false` otherwise
    ///
    /// # Examples
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let mut timer = new(Duration::from_secs(30));
    ///
    /// // Timer starts in running state
    /// assert!(timer.running());
    ///
    /// // Manually stopping the timer
    /// let _stop_cmd = timer.stop();
    /// // Note: timer.running() would still return true until the stop message is processed
    /// ```
    ///
    /// Checking timer state in different scenarios:
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let mut timer = new(Duration::from_secs(5));
    /// assert!(timer.running()); // Initially running
    ///
    /// // Simulate timer expiration
    /// timer.timeout = Duration::ZERO;
    /// assert!(!timer.running()); // Not running when expired
    ///
    /// // Reset timeout but manually stop the timer
    /// timer.timeout = Duration::from_secs(10);
    /// // Use stop() method instead of accessing private field
    /// let _stop_cmd = timer.stop();
    /// // Note: timer.running() may still return true until stop message is processed
    /// ```
    ///
    /// Integration with control commands:
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let timer = new(Duration::from_secs(60));
    ///
    /// // These commands change the running state
    /// let start_cmd = timer.start();   // Will make running() return true
    /// let stop_cmd = timer.stop();     // Will make running() return false
    /// let toggle_cmd = timer.toggle(); // Will flip the running state
    /// ```
    ///
    /// # State Priority
    ///
    /// The running state is determined by multiple factors in this priority order:
    /// 1. **Timeout**: If the timer has expired (`timedout() == true`), it's not running
    /// 2. **Manual State**: If manually stopped via `stop()`, it's not running
    /// 3. **Default**: Otherwise, it follows the internal running flag
    ///
    /// # Note
    ///
    /// This method matches Go's `Running()` method exactly for compatibility.
    pub fn running(&self) -> bool {
        if self.timedout() || !self.running {
            return false;
        }
        true
    }

    /// Returns whether the timer has reached zero and expired.
    ///
    /// A timer is considered timed out when its remaining timeout duration has
    /// reached zero or below. Once timed out, the timer automatically stops
    /// running and will not process further tick messages.
    ///
    /// # Returns
    ///
    /// `true` if the timer has expired, `false` if time remains
    ///
    /// # Examples
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let mut timer = new(Duration::from_secs(30));
    ///
    /// // Timer starts with time remaining
    /// assert!(!timer.timedout());
    ///
    /// // Simulate timer expiration
    /// timer.timeout = Duration::ZERO;
    /// assert!(timer.timedout());
    /// ```
    ///
    /// Checking expiration in different states:
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let mut timer = new(Duration::from_millis(100));
    ///
    /// // With remaining time
    /// assert!(!timer.timedout());
    ///
    /// // Exactly at zero
    /// timer.timeout = Duration::ZERO;
    /// assert!(timer.timedout());
    ///
    /// // Very small remaining time
    /// timer.timeout = Duration::from_nanos(1);
    /// assert!(!timer.timedout());
    /// ```
    ///
    /// Using in timeout detection:
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let mut timer = new(Duration::from_secs(5));
    ///
    /// // Application loop simulation
    /// while !timer.timedout() {
    ///     // Process timer ticks
    ///     // timer.update(tick_msg) would reduce timeout
    ///     
    ///     // Break for this example to avoid infinite loop
    ///     timer.timeout = Duration::ZERO;
    /// }
    ///
    /// assert!(timer.timedout());
    /// assert!(!timer.running()); // Timed out timers are not running
    /// ```
    ///
    /// # Relationship to Running State
    ///
    /// When a timer times out:
    /// - `timedout()` returns `true`
    /// - `running()` returns `false` (expired timers don't run)
    /// - The timer stops processing tick messages automatically
    /// - A `TimeoutMsg` is typically sent to notify the application
    ///
    /// # Precision Note
    ///
    /// The timeout check uses `Duration::ZERO` as the threshold. Due to the
    /// discrete nature of tick intervals, the actual remaining time when
    /// expiration is detected may be slightly negative (saturated to zero).
    ///
    /// # Note
    ///
    /// This method matches Go's `Timedout()` method exactly for compatibility.
    pub fn timedout(&self) -> bool {
        self.timeout <= Duration::ZERO
    }

    /// Generates a command to start or resume the timer.
    ///
    /// This method returns a command that, when executed by the Bubble Tea runtime,
    /// will send a `StartStopMsg` to resume the timer's countdown. If the timer is
    /// already running, this has no effect. If the timer has timed out, the command
    /// has no effect.
    ///
    /// # Returns
    ///
    /// A `Cmd` that will start the timer when executed
    ///
    /// # Examples
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use bubbletea_rs::{Model as BubbleTeaModel, Cmd};
    /// use std::time::Duration;
    ///
    /// struct App {
    ///     timer: bubbletea_widgets::timer::Model,
    /// }
    ///
    /// impl BubbleTeaModel for App {
    ///     fn init() -> (Self, Option<Cmd>) {
    ///         let timer = new(Duration::from_secs(60));
    ///         // Start the timer immediately
    ///         let start_cmd = timer.start();
    ///         (App { timer }, Some(start_cmd))
    ///     }
    ///
    ///     fn update(&mut self, msg: bubbletea_rs::Msg) -> Option<Cmd> {
    ///         // Handle user input to start timer
    ///         // if space_key_pressed {
    ///         //     return Some(self.timer.start());
    ///         // }
    ///         
    ///         self.timer.update(msg)
    ///     }
    ///     
    ///     // ... other methods
    /// #   fn view(&self) -> String { self.timer.view() }
    /// }
    /// ```
    ///
    /// Manual timer control:
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let timer = new(Duration::from_secs(30));
    ///
    /// // Generate control commands
    /// let start_cmd = timer.start();  // Resume countdown
    /// let stop_cmd = timer.stop();    // Pause countdown
    /// let toggle_cmd = timer.toggle(); // Toggle running state
    ///
    /// // Commands are executed by the Bubble Tea runtime
    /// // The actual state change happens when the StartStopMsg is processed
    /// ```
    ///
    /// # Command Execution
    ///
    /// The returned command is not executed immediately. Instead, it's returned
    /// to the Bubble Tea runtime, which will execute it asynchronously. The actual
    /// state change occurs when the resulting `StartStopMsg` is processed by the
    /// timer's `update()` method.
    ///
    /// # State Change Sequence
    ///
    /// 1. `start()` is called → returns `Cmd`
    /// 2. Bubble Tea executes the command → generates `StartStopMsg`
    /// 3. Message is sent to `update()` → timer state changes to running
    /// 4. Timer begins processing tick messages and counting down
    ///
    /// # No Effect Scenarios
    ///
    /// The start command has no effect when:
    /// - The timer has already timed out (`timedout() == true`)
    /// - The timer is already running (redundant operation)
    ///
    /// # Note
    ///
    /// This method matches Go's `Start()` method exactly for compatibility.
    pub fn start(&self) -> Cmd {
        self.start_stop(true)
    }

    /// Generates a command to stop or pause the timer.
    ///
    /// This method returns a command that, when executed by the Bubble Tea runtime,
    /// will send a `StartStopMsg` to pause the timer's countdown. The timer retains
    /// its current timeout value and can be resumed later with `start()`. If the
    /// timer has already timed out, this command has no effect.
    ///
    /// # Returns
    ///
    /// A `Cmd` that will stop the timer when executed
    ///
    /// # Examples
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use bubbletea_rs::{Model as BubbleTeaModel, Cmd, KeyMsg};
    /// use crossterm::event::{KeyCode, KeyModifiers};
    /// use std::time::Duration;
    ///
    /// struct App {
    ///     timer: bubbletea_widgets::timer::Model,
    ///     paused: bool,
    /// }
    ///
    /// impl BubbleTeaModel for App {
    ///     fn update(&mut self, msg: bubbletea_rs::Msg) -> Option<Cmd> {
    ///         // Handle spacebar to pause/resume
    ///         if let Some(key) = msg.downcast_ref::<KeyMsg>() {
    ///             if key.key == KeyCode::Char(' ') {
    ///                 self.paused = !self.paused;
    ///                 return if self.paused {
    ///                     Some(self.timer.stop())
    ///                 } else {
    ///                     Some(self.timer.start())
    ///                 };
    ///             }
    ///         }
    ///         
    ///         self.timer.update(msg)
    ///     }
    ///     
    ///     // ... other methods
    /// #   fn init() -> (Self, Option<Cmd>) { unimplemented!() }
    /// #   fn view(&self) -> String { format!("Timer: {} {}", self.timer.view(), if self.paused { "(PAUSED)" } else { "" }) }
    /// }
    /// ```
    ///
    /// Timer control pattern:
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let timer = new(Duration::from_secs(300)); // 5 minute timer
    ///
    /// // Control commands for different scenarios
    /// let pause_cmd = timer.stop();    // Pause for a break
    /// let resume_cmd = timer.start();  // Resume after break
    /// let toggle_cmd = timer.toggle(); // Quick pause/resume
    /// ```
    ///
    /// # Pause vs. Reset
    ///
    /// Important distinction:
    /// - **Stop/Pause**: Halts countdown but preserves remaining time
    /// - **Reset**: Would require creating a new timer with original timeout
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let mut timer = new(Duration::from_secs(60));
    ///
    /// // Simulate some time passing
    /// timer.timeout = Duration::from_secs(45); // 15 seconds elapsed
    ///
    /// // Stopping preserves the remaining 45 seconds
    /// let _stop_cmd = timer.stop();
    /// // timer.timeout is still 45 seconds after stop command is processed
    ///
    /// // To reset, create a new timer
    /// let reset_timer = new(Duration::from_secs(60));
    /// ```
    ///
    /// # Command Execution
    ///
    /// Like all timer control methods, the returned command is executed
    /// asynchronously by the Bubble Tea runtime. The actual pause occurs
    /// when the `StartStopMsg` is processed.
    ///
    /// # No Effect Scenarios
    ///
    /// The stop command has no effect when:
    /// - The timer has already timed out (`timedout() == true`)
    /// - The timer is already stopped (redundant operation)
    ///
    /// # Note
    ///
    /// This method matches Go's `Stop()` method exactly for compatibility.
    pub fn stop(&self) -> Cmd {
        self.start_stop(false)
    }

    /// Generates a command to toggle the timer's running state.
    ///
    /// This method provides a convenient way to switch between running and stopped
    /// states. If the timer is currently running, it will be stopped. If it's stopped,
    /// it will be started. This is particularly useful for pause/resume functionality
    /// controlled by a single user action.
    ///
    /// # Returns
    ///
    /// A `Cmd` that will toggle the timer's state when executed
    ///
    /// # Examples
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use bubbletea_rs::{Model as BubbleTeaModel, Cmd, KeyMsg};
    /// use crossterm::event::{KeyCode, KeyModifiers};
    /// use std::time::Duration;
    ///
    /// struct PomodoroApp {
    ///     work_timer: bubbletea_widgets::timer::Model,
    /// }
    ///
    /// impl BubbleTeaModel for PomodoroApp {
    ///     fn init() -> (Self, Option<Cmd>) {
    ///         let timer = new(Duration::from_secs(25 * 60)); // 25 minute work session
    ///         let start_cmd = timer.init();
    ///         (PomodoroApp { work_timer: timer }, Some(start_cmd))
    ///     }
    ///
    ///     fn update(&mut self, msg: bubbletea_rs::Msg) -> Option<Cmd> {
    ///         // Spacebar toggles timer
    ///         if let Some(key) = msg.downcast_ref::<KeyMsg>() {
    ///             if key.key == KeyCode::Char(' ') {
    ///                 return Some(self.work_timer.toggle());
    ///             }
    ///         }
    ///         
    ///         self.work_timer.update(msg)
    ///     }
    ///
    ///     fn view(&self) -> String {
    ///         format!(
    ///             "Work Timer: {}\n\n[SPACE] to {}",
    ///             self.work_timer.view(),
    ///             if self.work_timer.running() { "pause" } else { "resume" }
    ///         )
    ///     }
    /// }
    /// ```
    ///
    /// Simple toggle pattern:
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let timer = new(Duration::from_secs(120));
    ///
    /// // One command handles both pause and resume
    /// let toggle_cmd = timer.toggle();
    ///
    /// // Equivalent to:
    /// // if timer.running() {
    /// //     timer.stop()
    /// // } else {
    /// //     timer.start()
    /// // }
    /// ```
    ///
    /// # State Determination
    ///
    /// The toggle decision is based on the current result of `running()`:
    /// - If `running()` returns `true` → generates stop command
    /// - If `running()` returns `false` → generates start command
    ///
    /// This means the toggle respects both manual stops and timeout states:
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let mut timer = new(Duration::from_secs(30));
    ///
    /// // Normal toggle (running → stopped)
    /// assert!(timer.running());
    /// let _toggle1 = timer.toggle(); // Will stop
    ///
    /// // Toggle on expired timer (not running → no effect)
    /// timer.timeout = Duration::ZERO;
    /// assert!(!timer.running()); // Not running due to timeout
    /// let _toggle2 = timer.toggle(); // Will attempt start, but no effect due to timeout
    /// ```
    ///
    /// # User Interface Benefits
    ///
    /// Toggle is ideal for:
    /// - Single-key pause/resume (spacebar pattern)
    /// - Play/pause buttons in UI
    /// - Touch/click interfaces
    /// - Reducing cognitive load (one action vs. two separate actions)
    ///
    /// # Command Execution
    ///
    /// The toggle command evaluates the current state when called, not when executed.
    /// The actual state change occurs asynchronously when the resulting `StartStopMsg`
    /// is processed by the timer's `update()` method.
    ///
    /// # Note
    ///
    /// This method matches Go's `Toggle()` method exactly for compatibility.
    pub fn toggle(&self) -> Cmd {
        self.start_stop(!self.running())
    }

    /// Internal tick function - matches Go's tick method.
    fn tick(&self) -> Cmd {
        let id = self.id;
        let tag = self.tag;
        let timeout = self.timedout();
        let interval = self.interval;

        bubbletea_tick(interval, move |_| {
            Box::new(TickMsg { id, timeout, tag }) as Msg
        })
    }

    /// Internal timedout command - matches Go's timedout method.
    #[allow(dead_code)]
    fn timedout_cmd(&self) -> std::option::Option<Cmd> {
        if !self.timedout() {
            return std::option::Option::None;
        }
        let id = self.id;
        std::option::Option::Some(bubbletea_tick(Duration::from_nanos(1), move |_| {
            Box::new(TimeoutMsg { id }) as Msg
        }))
    }

    /// Internal start/stop command - matches Go's startStop method.
    fn start_stop(&self, running: bool) -> Cmd {
        let id = self.id;
        bubbletea_tick(Duration::from_nanos(1), move |_| {
            Box::new(StartStopMsg { id, running }) as Msg
        })
    }

    /// Initializes the timer and returns the command to start its first tick.
    ///
    /// This method should be called once when the timer is first created to begin
    /// the countdown process. It generates the initial tick command that starts
    /// the timer's regular interval-based updates.
    ///
    /// # Returns
    ///
    /// A `Cmd` that will start the timer's tick cycle when executed
    ///
    /// # Examples
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use bubbletea_rs::{Model as BubbleTeaModel, Cmd};
    /// use std::time::Duration;
    ///
    /// struct App {
    ///     timer: bubbletea_widgets::timer::Model,
    /// }
    ///
    /// impl BubbleTeaModel for App {
    ///     fn init() -> (Self, Option<Cmd>) {
    ///         let timer = new(Duration::from_secs(60));
    ///         // Initialize the timer to start ticking
    ///         let timer_cmd = timer.init();
    ///         (App { timer }, Some(timer_cmd))
    ///     }
    ///     
    ///     // ... other methods
    /// #   fn update(&mut self, _: bubbletea_rs::Msg) -> Option<Cmd> { None }
    /// #   fn view(&self) -> String { self.timer.view() }
    /// }
    /// ```
    ///
    /// Multiple timer initialization:
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use bubbletea_rs::{Model as BubbleTeaModel, Cmd};
    /// use std::time::Duration;
    ///
    /// struct MultiTimerApp {
    ///     work_timer: bubbletea_widgets::timer::Model,
    ///     break_timer: bubbletea_widgets::timer::Model,
    /// }
    ///
    /// impl BubbleTeaModel for MultiTimerApp {
    ///     fn init() -> (Self, Option<Cmd>) {
    ///         let work_timer = new(Duration::from_secs(25 * 60));
    ///         let break_timer = new(Duration::from_secs(5 * 60));
    ///         
    ///         // Start the work timer initially
    ///         let init_cmd = work_timer.init();
    ///         
    ///         (MultiTimerApp { work_timer, break_timer }, Some(init_cmd))
    ///     }
    ///     
    ///     // ... other methods
    /// #   fn update(&mut self, _: bubbletea_rs::Msg) -> Option<Cmd> { None }
    /// #   fn view(&self) -> String { self.work_timer.view() }
    /// }
    /// ```
    ///
    /// # When to Call
    ///
    /// - **Application startup**: In your app's `init()` method
    /// - **Timer creation**: Immediately after creating a new timer
    /// - **Timer reset**: When restarting a timer with new settings
    ///
    /// # What It Does
    ///
    /// The `init()` method:
    /// 1. Creates the first tick command
    /// 2. Sets up the timer's internal tick cycle
    /// 3. Returns immediately (non-blocking)
    /// 4. The actual ticking starts when Bubble Tea executes the command
    ///
    /// # Timing Behavior
    ///
    /// The first tick occurs after the timer's `interval` duration. For example,
    /// with a 1-second interval, the first countdown update happens 1 second after
    /// the init command is executed.
    ///
    /// # Alternative to Start
    ///
    /// While `start()` is used to resume a paused timer, `init()` is specifically
    /// for initial timer setup and should be called once per timer instance.
    ///
    /// # Note
    ///
    /// This method matches Go's `Init()` method exactly for compatibility.
    pub fn init(&self) -> Cmd {
        self.tick()
    }

    /// Processes messages and updates the timer state.
    ///
    /// This method handles all messages related to timer operation, including tick
    /// messages that advance the countdown and control messages that change the
    /// running state. It should be called from your application's update loop
    /// for proper timer functionality.
    ///
    /// # Arguments
    ///
    /// * `msg` - The message to process (typically `TickMsg` or `StartStopMsg`)
    ///
    /// # Returns
    ///
    /// An optional `Cmd` for the next timer operation, or `None` if no action needed
    ///
    /// # Message Types Handled
    ///
    /// - **`StartStopMsg`**: Changes the timer's running state
    /// - **`TickMsg`**: Advances the countdown and schedules the next tick
    /// - **Other messages**: Ignored (returns `None`)
    ///
    /// # Examples
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::{new, TickMsg, StartStopMsg, TimeoutMsg};
    /// use bubbletea_rs::{Model as BubbleTeaModel, Msg, Cmd};
    /// use std::time::Duration;
    ///
    /// struct App {
    ///     timer: bubbletea_widgets::timer::Model,
    ///     status: String,
    /// }
    ///
    /// impl BubbleTeaModel for App {
    ///     fn update(&mut self, msg: Msg) -> Option<Cmd> {
    ///         // Handle application-specific timer events
    ///         if let Some(timeout) = msg.downcast_ref::<TimeoutMsg>() {
    ///             if timeout.id == self.timer.id() {
    ///                 self.status = "Timer completed!".to_string();
    ///             }
    ///         }
    ///         
    ///         // Forward all messages to timer for processing
    ///         self.timer.update(msg)
    ///     }
    ///     
    ///     // ... other methods
    /// #   fn init() -> (Self, Option<Cmd>) { unimplemented!() }
    /// #   fn view(&self) -> String { format!("{}: {}", self.status, self.timer.view()) }
    /// }
    /// ```
    ///
    /// Manual message handling:
    /// ```rust,ignore
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let mut timer = new(Duration::from_secs(10));
    ///
    /// // Start the timer using the public API
    /// let start_cmd = timer.start();
    /// // In a real app, you'd send this command through bubbletea
    ///
    /// // Check initial timeout
    /// assert_eq!(timer.timeout(), Duration::from_secs(10));
    /// ```
    ///
    /// # Message Filtering
    ///
    /// The timer automatically filters messages to ensure it only processes
    /// messages intended for it:
    ///
    /// - **ID Matching**: Only processes messages with matching timer IDs
    /// - **Tag Validation**: Rejects tick messages with incorrect tags
    /// - **State Checks**: Ignores ticks when not running
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let mut timer1 = new(Duration::from_secs(10));
    /// let _timer2 = new(Duration::from_secs(20));
    ///
    /// // Start timer1
    /// let _cmd = timer1.start();
    ///
    /// // Messages with wrong IDs are ignored
    /// // In a real app, messages are routed by ID
    /// assert_eq!(timer1.timeout, Duration::from_secs(10)); // No change
    /// ```
    ///
    /// # State Changes
    ///
    /// Different message types cause different state changes:
    ///
    /// - **`StartStopMsg`**: Changes `running` state, returns tick command
    /// - **`TickMsg`**: Reduces `timeout` by `interval`, returns next tick command
    /// - **Invalid messages**: No state change, returns `None`
    ///
    /// # Timeout Detection
    ///
    /// When a tick reduces the timeout to zero or below, the timer:
    /// 1. Automatically stops running
    /// 2. May send a `TimeoutMsg` (implementation detail)
    /// 3. Returns a tick command that will be ignored (since not running)
    ///
    /// # Error Handling
    ///
    /// This method never panics and handles invalid messages gracefully by
    /// ignoring them and returning `None`.
    ///
    /// # Performance
    ///
    /// Message processing is very fast, involving only basic comparisons and
    /// arithmetic operations. The method is designed to be called frequently
    /// in the Bubble Tea update loop.
    ///
    /// # Note
    ///
    /// This method matches Go's `Update()` method exactly for compatibility.
    pub fn update(&mut self, msg: Msg) -> std::option::Option<Cmd> {
        if let Some(start_stop_msg) = msg.downcast_ref::<StartStopMsg>() {
            if start_stop_msg.id != 0 && start_stop_msg.id != self.id {
                return std::option::Option::None;
            }

            let was_running = self.running;
            self.running = start_stop_msg.running;

            // Reset timing when starting from stopped state
            if !was_running && self.running {
                self.start_instant = None;
                self.last_tick = None;
            }

            return std::option::Option::Some(self.tick());
        }

        if let Some(tick_msg) = msg.downcast_ref::<TickMsg>() {
            if !self.running() || (tick_msg.id != 0 && tick_msg.id != self.id) {
                return std::option::Option::None;
            }

            // If a tag is set, and it's not the one we expect, reject the message.
            // This prevents the ticker from receiving too many messages and
            // thus ticking too fast.
            if tick_msg.tag > 0 && tick_msg.tag != self.tag {
                return std::option::Option::None;
            }

            // Use high-precision elapsed time tracking for accurate countdown
            let now = Instant::now();

            // Initialize timing on first tick
            if self.last_tick.is_none() {
                self.start_instant = Some(now);
                self.last_tick = Some(now);
                // On first tick, just use the interval as fallback
                self.timeout = self.timeout.saturating_sub(self.interval);
            } else {
                // Calculate actual elapsed time since last tick
                let actual_elapsed = now.duration_since(self.last_tick.unwrap());
                self.timeout = self.timeout.saturating_sub(actual_elapsed);
                self.last_tick = Some(now);
            }

            // In Go this uses tea.Batch to return multiple commands.
            // For simplicity in Rust, we'll return just the tick command.
            // The TimeoutMsg will be sent automatically when timeout is detected.
            return std::option::Option::Some(self.tick());
        }

        std::option::Option::None
    }

    /// Renders the timer as a formatted string showing remaining time.
    ///
    /// This method converts the timer's current timeout duration into a
    /// human-readable string using Go's duration formatting conventions.
    /// The output is suitable for direct display in terminal applications.
    ///
    /// # Returns
    ///
    /// A formatted string representation of the remaining time
    ///
    /// # Format Examples
    ///
    /// The format matches Go's `Duration.String()` output:
    /// - `"5m30s"` for 5 minutes 30 seconds
    /// - `"2m"` for exactly 2 minutes
    /// - `"45.5s"` for 45.5 seconds
    /// - `"750ms"` for milliseconds
    /// - `"0s"` when expired
    ///
    /// # Examples
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// // Various timer displays
    /// let timer1 = new(Duration::from_secs(90));
    /// assert!(timer1.view().contains("1m"));
    ///
    /// let timer2 = new(Duration::from_millis(500));
    /// assert!(timer2.view().contains("500ms"));
    ///
    /// let mut timer3 = new(Duration::from_secs(1));
    /// timer3.timeout = Duration::ZERO;
    /// assert_eq!(timer3.view(), "0s");
    /// ```
    ///
    /// Integration in UI:
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use bubbletea_rs::{Model as BubbleTeaModel};
    /// use std::time::Duration;
    ///
    /// struct App {
    ///     cooking_timer: bubbletea_widgets::timer::Model,
    ///     recipe: String,
    /// }
    ///
    /// impl BubbleTeaModel for App {
    ///     fn view(&self) -> String {
    ///         format!(
    ///             "Cooking: {}\n\nTime remaining: {}\n\n[SPACE] to pause",
    ///             self.recipe,
    ///             self.cooking_timer.view()
    ///         )
    ///     }
    ///     
    ///     // ... other methods
    /// #   fn init() -> (Self, Option<bubbletea_rs::Cmd>) { unimplemented!() }
    /// #   fn update(&mut self, _: bubbletea_rs::Msg) -> Option<bubbletea_rs::Cmd> { None }
    /// }
    /// ```
    ///
    /// Dynamic display updates:
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let mut timer = new(Duration::from_secs(125)); // 2m5s
    ///
    /// // Display updates as timer counts down
    /// println!("Start: {}", timer.view()); // "2m5s"
    ///
    /// // Simulate 30 seconds passing
    /// timer.timeout -= Duration::from_secs(30);
    /// println!("After 30s: {}", timer.view()); // "1m35s"
    ///
    /// // Simulate completion
    /// timer.timeout = Duration::ZERO;
    /// println!("Finished: {}", timer.view()); // "0s"
    /// ```
    ///
    /// # Precision Display
    ///
    /// The display precision depends on the remaining time:
    /// - **Minutes**: Shows minutes and seconds (e.g., "3m45s")
    /// - **Seconds**: Shows seconds with decimals if needed (e.g., "1.5s")
    /// - **Milliseconds**: Shows millisecond precision (e.g., "250ms")
    /// - **Microseconds/Nanoseconds**: For very short durations
    ///
    /// # Use Cases
    ///
    /// Perfect for:
    /// - Countdown displays in TUIs
    /// - Progress indicators with time remaining
    /// - Cooking/work timers
    /// - Game time limits
    /// - Session timeouts
    ///
    /// # Performance
    ///
    /// String formatting is performed on each call, so for high-frequency
    /// updates, consider caching the result if the timeout hasn't changed.
    ///
    /// # Localization
    ///
    /// The format uses English abbreviations ("m", "s", "ms") and follows
    /// Go's conventions. For different locales, you may need to parse the
    /// `timeout` duration and format it according to local preferences.
    ///
    /// # Note
    ///
    /// This method matches Go's `View()` method exactly for compatibility.
    pub fn view(&self) -> String {
        format_duration(self.timeout)
    }
}

impl BubbleTeaModel for Model {
    /// Creates a new timer model with default settings for standalone use.
    ///
    /// This implementation provides a default timer configuration suitable for
    /// applications that want to use the timer as a standalone component without
    /// custom initialization. It creates a 60-second timer with 1-second intervals.
    ///
    /// # Returns
    ///
    /// A tuple containing the new timer model and its initialization command
    ///
    /// # Examples
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::Model as TimerModel;
    /// use bubbletea_rs::{Model as BubbleTeaModel};
    ///
    /// // Use timer as a standalone Bubble Tea application
    /// let model = TimerModel::default();
    /// let cmd = model.init();
    /// // Would start a 60-second timer app
    /// ```
    ///
    /// # Default Configuration
    ///
    /// - **Timeout**: 60 seconds
    /// - **Interval**: 1 second
    /// - **State**: Running (starts immediately)
    /// - **Display**: Shows countdown in "1m0s" format
    ///
    /// # Note
    ///
    /// Most applications will want to use `new()` or `new_with_interval()` instead
    /// to create timers with specific durations rather than this default.
    fn init() -> (Self, std::option::Option<Cmd>) {
        let model = new(Duration::from_secs(60));
        let cmd = model.init();
        (model, std::option::Option::Some(cmd))
    }

    /// Forwards messages to the timer's update method.
    ///
    /// This implementation delegates all message processing to the timer's
    /// own `update()` method, ensuring consistent behavior whether the timer
    /// is used standalone or as part of a larger application.
    ///
    /// # Arguments
    ///
    /// * `msg` - The message to process
    ///
    /// # Returns
    ///
    /// An optional command for continued timer operation
    ///
    /// # Examples
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::Model as TimerModel;
    /// use bubbletea_rs::{Model as BubbleTeaModel};
    ///
    /// let mut timer = TimerModel::default();
    /// // Start the timer
    /// let _start_cmd = timer.start();
    ///
    /// // In a real app, tick messages are generated automatically
    /// // Timer processes updates and returns commands for next ticks
    /// ```
    fn update(&mut self, msg: Msg) -> std::option::Option<Cmd> {
        self.update(msg)
    }

    /// Renders the timer display using the timer's view method.
    ///
    /// This implementation delegates to the timer's own `view()` method,
    /// providing a consistent display format regardless of how the timer
    /// is integrated into the application.
    ///
    /// # Returns
    ///
    /// A formatted string showing the remaining time
    ///
    /// # Examples
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::Model as TimerModel;
    /// use bubbletea_rs::Model as BubbleTeaModel;
    ///
    /// let timer = TimerModel::default();
    /// let display = timer.view();
    /// assert!(display.contains("1m") || display.contains("60s"));
    /// ```
    fn view(&self) -> String {
        self.view()
    }
}

impl Default for Model {
    /// Creates a timer with sensible default settings.
    ///
    /// This implementation provides a standard 60-second timer with 1-second
    /// intervals, suitable for most common timing needs. The timer starts in
    /// a running state and is ready for immediate use.
    ///
    /// # Returns
    ///
    /// A new timer configured with default settings
    ///
    /// # Examples
    ///
    /// ```rust
    /// use bubbletea_widgets::timer::Model;
    /// use std::time::Duration;
    ///
    /// // Create timer with defaults
    /// let timer = Model::default();
    /// assert_eq!(timer.timeout, Duration::from_secs(60));
    /// assert_eq!(timer.interval, Duration::from_secs(1));
    /// assert!(timer.running());
    /// assert!(!timer.timedout());
    /// ```
    ///
    /// Using with struct initialization:
    /// ```rust
    /// use bubbletea_widgets::timer::Model as TimerModel;
    ///
    /// struct App {
    ///     timer: TimerModel,
    ///     // other fields...
    /// }
    ///
    /// impl Default for App {
    ///     fn default() -> Self {
    ///         Self {
    ///             timer: TimerModel::default(),
    ///             // initialize other fields...
    ///         }
    ///     }
    /// }
    /// ```
    ///
    /// # Default Values
    ///
    /// - **Timeout**: 60 seconds (1 minute)
    /// - **Interval**: 1 second (standard clock tick)
    /// - **Running**: `true` (starts immediately)
    /// - **ID**: Unique identifier (generated automatically)
    ///
    /// # When to Use
    ///
    /// Use `Default` when:
    /// - You need a quick timer for testing or prototyping
    /// - 60 seconds is an appropriate duration for your use case
    /// - You want to rely on struct field defaults in larger structures
    /// - Building utilities or examples that need reasonable timer behavior
    ///
    /// Use `new()` or `new_with_interval()` when:
    /// - You need specific timeout durations
    /// - Custom tick intervals are required
    /// - Explicit configuration is preferred for clarity
    ///
    /// # Equivalent Creation
    ///
    /// This default implementation is equivalent to:
    /// ```rust
    /// use bubbletea_widgets::timer::new;
    /// use std::time::Duration;
    ///
    /// let timer = new(Duration::from_secs(60));
    /// ```
    fn default() -> Self {
        new(Duration::from_secs(60))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time::Duration;

    #[test]
    fn test_new_with_timeout() {
        // Test Go's: New(timeout)
        let timeout = Duration::from_secs(30);
        let timer = new(timeout);

        assert_eq!(timer.timeout, timeout);
        assert_eq!(timer.interval, Duration::from_secs(1)); // Default interval
        assert!(timer.id() > 0); // Should have unique ID
        assert!(timer.running()); // Should start running
        assert!(!timer.timedout()); // Should not be timed out initially
    }

    #[test]
    fn test_new_with_interval() {
        // Test Go's: NewWithInterval(timeout, interval)
        let timeout = Duration::from_secs(60);
        let interval = Duration::from_millis(500);
        let timer = new_with_interval(timeout, interval);

        assert_eq!(timer.timeout, timeout);
        assert_eq!(timer.interval, interval);
        assert!(timer.id() > 0);
        assert!(timer.running());
        assert!(!timer.timedout());
    }

    #[test]
    fn test_unique_ids() {
        // Test that multiple timers get unique IDs
        let timer1 = new(Duration::from_secs(10));
        let timer2 = new(Duration::from_secs(20));

        assert_ne!(timer1.id(), timer2.id());
    }

    #[test]
    fn test_running_logic() {
        // Test Go's: Running() bool
        let mut timer = new(Duration::from_secs(5));

        // Initially running
        assert!(timer.running());

        // After manual stop
        timer.running = false;
        assert!(!timer.running());

        // After timeout
        timer.running = true;
        timer.timeout = Duration::ZERO;
        assert!(!timer.running()); // Should be false when timed out
    }

    #[test]
    fn test_timedout_logic() {
        // Test Go's: Timedout() bool
        let mut timer = new(Duration::from_secs(5));

        assert!(!timer.timedout());

        // Set to zero
        timer.timeout = Duration::ZERO;
        assert!(timer.timedout());

        // Set to negative (should be handled as zero)
        timer.timeout = Duration::from_nanos(0);
        assert!(timer.timedout());
    }

    #[test]
    fn test_id_method() {
        // Test Go's: ID() int
        let timer = new(Duration::from_secs(10));
        let id = timer.id();

        assert!(id > 0);
        assert_eq!(timer.id(), id); // Should return same ID consistently
    }

    #[test]
    fn test_start_stop_toggle_commands() {
        // Test Go's: Start(), Stop(), Toggle() return commands
        let timer = new(Duration::from_secs(10));

        // These should return commands (not panic)
        let _start_cmd = timer.start();
        let _stop_cmd = timer.stop();
        let _toggle_cmd = timer.toggle();

        // Commands should be callable (we can't easily test their content without executing)
        // In a real app, these would send StartStopMsg messages
    }

    #[test]
    fn test_init_command() {
        // Test Go's: Init() tea.Cmd
        let timer = new(Duration::from_secs(10));
        let _cmd = timer.init();

        // Should return a command (tick command)
    }

    #[test]
    fn test_update_with_start_stop_msg() {
        // Test Go's: Update with StartStopMsg
        let mut timer = new(Duration::from_secs(10));
        timer.running = false; // Stop it first

        let start_msg = StartStopMsg {
            id: timer.id(),
            running: true,
        };

        let result = timer.update(Box::new(start_msg));
        assert!(result.is_some()); // Should return tick command
        assert!(timer.running); // Should now be running
    }

    #[test]
    fn test_update_with_wrong_id() {
        // Test that timer rejects StartStopMsg with wrong ID
        let mut timer = new(Duration::from_secs(10));

        let wrong_msg = StartStopMsg {
            id: timer.id() + 999, // Wrong ID
            running: false,
        };

        let original_running = timer.running;
        let result = timer.update(Box::new(wrong_msg));

        assert!(result.is_none()); // Should reject
        assert_eq!(timer.running, original_running); // State unchanged
    }

    #[test]
    fn test_update_with_tick_msg() {
        // Test Go's: Update with TickMsg
        let mut timer = new(Duration::from_secs(5));
        let original_timeout = timer.timeout;

        let tick_msg = TickMsg {
            id: timer.id(),
            timeout: false,
            tag: 0,
        };

        let result = timer.update(Box::new(tick_msg));
        assert!(result.is_some()); // Should return next tick command
        assert!(timer.timeout < original_timeout); // Should have decreased
    }

    #[test]
    fn test_update_tick_reduces_timeout() {
        // Test that TickMsg reduces timeout by interval
        let mut timer = new_with_interval(Duration::from_secs(10), Duration::from_secs(2));
        let original_timeout = timer.timeout;

        let tick_msg = TickMsg {
            id: timer.id(),
            timeout: false,
            tag: 0,
        };

        timer.update(Box::new(tick_msg));

        assert_eq!(
            timer.timeout,
            original_timeout.saturating_sub(Duration::from_secs(2))
        );
    }

    #[test]
    fn test_view_format() {
        // Test Go's: View() string (using timeout.String() format)
        let timer = new(Duration::from_secs(65)); // 1m5s
        let view = timer.view();

        // Should be formatted like Go's Duration.String()
        assert!(view.contains("m") || view.contains("s"));

        // Test zero duration
        let mut timer_zero = new(Duration::from_secs(1));
        timer_zero.timeout = Duration::ZERO;
        assert_eq!(timer_zero.view(), "0s");
    }

    #[test]
    fn test_view_various_durations() {
        // Test various duration formats
        let test_cases = vec![
            (Duration::from_millis(500), "500ms"),
            (Duration::from_secs(1), "1s"),
            (Duration::from_secs(61), "1m1s"),
            (Duration::from_secs(120), "2m"),
        ];

        for (duration, expected_contains) in test_cases {
            let mut timer = new(duration);
            timer.timeout = duration;
            let view = timer.view();

            // At least check that it contains expected parts
            // (exact format matching with Go is complex due to precision)
            if expected_contains.contains("m") {
                assert!(
                    view.contains("m"),
                    "Duration {:?} should contain 'm' in view: {}",
                    duration,
                    view
                );
            }
            if expected_contains.contains("s") && !expected_contains.contains("ms") {
                assert!(
                    view.contains("s"),
                    "Duration {:?} should contain 's' in view: {}",
                    duration,
                    view
                );
            }
        }
    }

    #[test]
    fn test_tag_filtering() {
        // Test that timer rejects TickMsg with wrong tag
        let mut timer = new(Duration::from_secs(10));
        timer.tag = 5; // Set specific tag

        let wrong_tick = TickMsg {
            id: timer.id(),
            timeout: false,
            tag: 999, // Wrong tag
        };

        let result = timer.update(Box::new(wrong_tick));
        assert!(result.is_none()); // Should reject
    }

    #[test]
    fn test_not_running_rejects_ticks() {
        // Test that stopped timer rejects TickMsg
        let mut timer = new(Duration::from_secs(10));
        timer.running = false;

        let tick_msg = TickMsg {
            id: timer.id(),
            timeout: false,
            tag: 0,
        };

        let result = timer.update(Box::new(tick_msg));
        assert!(result.is_none()); // Should reject when not running
    }

    #[test]
    fn test_default_timer() {
        // Test Default implementation
        let timer = Model::default();
        assert_eq!(timer.timeout, Duration::from_secs(60));
        assert_eq!(timer.interval, Duration::from_secs(1));
        assert!(timer.running());
    }

    #[test]
    fn test_timeout_msg_semantics() {
        // Test TimeoutMsg structure
        let timeout_msg = TimeoutMsg { id: 123 };
        assert_eq!(timeout_msg.id, 123);
    }

    #[test]
    fn test_timing_fields_initialization() {
        // Test that timing fields are properly initialized
        let timer = new(Duration::from_secs(10));
        assert!(timer.start_instant.is_none());
        assert!(timer.last_tick.is_none());

        let timer_with_interval =
            new_with_interval(Duration::from_secs(30), Duration::from_millis(100));
        assert!(timer_with_interval.start_instant.is_none());
        assert!(timer_with_interval.last_tick.is_none());
    }

    #[test]
    fn test_timing_initialization_on_first_tick() {
        // Test that timing is initialized on first tick message
        let mut timer = new(Duration::from_secs(5));
        assert!(timer.start_instant.is_none());
        assert!(timer.last_tick.is_none());

        let tick_msg = TickMsg {
            id: timer.id(),
            timeout: false,
            tag: 0,
        };

        // First tick should initialize timing
        let start_time = std::time::Instant::now();
        let result = timer.update(Box::new(tick_msg));
        let end_time = std::time::Instant::now();

        assert!(result.is_some());
        assert!(timer.start_instant.is_some());
        assert!(timer.last_tick.is_some());

        // Check that the timing was set to approximately the current time
        let tick_time = timer.last_tick.unwrap();
        assert!(tick_time >= start_time);
        assert!(tick_time <= end_time);
    }

    #[test]
    fn test_timing_reset_on_restart() {
        // Test that timing is reset when starting from stopped state
        let mut timer = new(Duration::from_secs(10));

        // Stop the timer
        timer.running = false;
        timer.start_instant = Some(std::time::Instant::now());
        timer.last_tick = Some(std::time::Instant::now());

        // Start the timer (should reset timing)
        let start_msg = StartStopMsg {
            id: timer.id(),
            running: true,
        };

        let result = timer.update(Box::new(start_msg));
        assert!(result.is_some());
        assert!(timer.running);
        assert!(timer.start_instant.is_none()); // Should be reset
        assert!(timer.last_tick.is_none()); // Should be reset
    }

    #[test]
    fn test_timing_preserved_on_stop() {
        // Test that timing is preserved when stopping (not reset)
        let mut timer = new(Duration::from_secs(10));

        // Initialize timing with a tick
        let tick_msg = TickMsg {
            id: timer.id(),
            timeout: false,
            tag: 0,
        };
        timer.update(Box::new(tick_msg));

        let preserved_start = timer.start_instant;
        let preserved_tick = timer.last_tick;

        // Stop the timer (should preserve timing)
        let stop_msg = StartStopMsg {
            id: timer.id(),
            running: false,
        };

        let result = timer.update(Box::new(stop_msg));
        assert!(result.is_some());
        assert!(!timer.running);
        assert_eq!(timer.start_instant, preserved_start); // Should be preserved
        assert_eq!(timer.last_tick, preserved_tick); // Should be preserved
    }
}
