//! Sync Component trait and supporting types for RFC 0003
//!
//! This module defines the core trait that all synced components implement,
//! along with the types used for strategy selection and merge decisions.

use bevy::prelude::*;

/// Sync strategy enum - determines how conflicts are resolved
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SyncStrategy {
    /// Last-Write-Wins: Newer timestamp wins, node ID tiebreaker for concurrent
    LastWriteWins,
    /// OR-Set: Observed-Remove Set for collections
    Set,
    /// Sequence: RGA (Replicated Growable Array) for ordered lists
    Sequence,
    /// Custom: User-defined conflict resolution
    Custom,
}

/// Result of comparing vector clocks
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ClockComparison {
    /// Remote vector clock is strictly newer
    RemoteNewer,
    /// Local vector clock is strictly newer
    LocalNewer,
    /// Concurrent (neither is newer)
    Concurrent,
}

/// Decision made during component merge operation
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ComponentMergeDecision {
    /// Kept local value
    KeptLocal,
    /// Took remote value
    TookRemote,
    /// Merged both (for CRDTs)
    Merged,
}

/// Core trait for synced components
///
/// This trait is automatically implemented by the `#[derive(Synced)]` macro.
/// All synced components must implement this trait.
///
/// # Example
/// ```
/// use bevy::prelude::*;
/// use libmarathon::networking::{
///     ClockComparison,
///     ComponentMergeDecision,
///     SyncComponent,
///     SyncStrategy,
/// };
///
/// // Example showing what the trait looks like - normally generated by #[derive(Synced)]
/// #[derive(Component, Reflect, Clone, serde::Serialize, serde::Deserialize)]
/// struct Health(f32);
///
/// // The SyncComponent trait defines these methods that the macro generates
/// // You can serialize and deserialize components for sync
/// ```
pub trait SyncComponent: Component + Reflect + Sized {
    /// Schema version for this component
    const VERSION: u32;

    /// Sync strategy for conflict resolution
    const STRATEGY: SyncStrategy;

    /// Serialize this component to bytes
    ///
    /// Uses rkyv for zero-copy binary serialization.
    fn serialize_sync(&self) -> anyhow::Result<bytes::Bytes>;

    /// Deserialize this component from bytes
    ///
    /// Uses rkyv to deserialize from the format created by `serialize_sync`.
    fn deserialize_sync(data: &[u8]) -> anyhow::Result<Self>;

    /// Merge remote state with local state
    ///
    /// The merge logic is strategy-specific:
    /// - **LWW**: Takes newer value based on vector clock, uses tiebreaker for
    ///   concurrent
    /// - **Set**: Merges both sets (OR-Set semantics)
    /// - **Sequence**: Merges sequences preserving order (RGA semantics)
    /// - **Custom**: Calls user-defined ConflictResolver
    ///
    /// # Arguments
    /// * `remote` - The remote state to merge
    /// * `clock_cmp` - Result of comparing local and remote vector clocks
    ///
    /// # Returns
    /// Decision about what happened during the merge
    fn merge(&mut self, remote: Self, clock_cmp: ClockComparison) -> ComponentMergeDecision;
}

/// Marker component for entities that should be synced
///
/// Add this to any entity with synced components to enable automatic
/// change detection and synchronization.
///
/// # Example
/// ```
/// use bevy::prelude::*;
/// use libmarathon::networking::Synced;
/// use sync_macros::Synced as SyncedDerive;
///
/// #[derive(Component, Reflect, Clone, serde::Serialize, serde::Deserialize, SyncedDerive)]
/// #[sync(version = 1, strategy = "LastWriteWins")]
/// struct Health(f32);
///
/// #[derive(Component, Reflect, Clone, serde::Serialize, serde::Deserialize, SyncedDerive)]
/// #[sync(version = 1, strategy = "LastWriteWins")]
/// struct Position {
///     x: f32,
///     y: f32,
/// }
///
/// let mut world = World::new();
/// world.spawn((
///     Health(100.0),
///     Position { x: 0.0, y: 0.0 },
///     Synced, // Marker enables sync
/// ));
/// ```
#[derive(Component, Reflect, Default, Clone, Copy)]
#[reflect(Component)]
pub struct Synced;

/// Diagnostic component for debugging sync issues
///
/// Add this to an entity to get detailed diagnostic output about
/// its sync status.
///
/// # Example
/// ```
/// use bevy::prelude::*;
/// use libmarathon::networking::DiagnoseSync;
///
/// let mut world = World::new();
/// let entity = world.spawn_empty().id();
/// world.entity_mut(entity).insert(DiagnoseSync);
/// // A diagnostic system will check this entity and log sync status
/// ```
#[derive(Component, Reflect, Default)]
#[reflect(Component)]
pub struct DiagnoseSync;

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

    #[test]
    fn strategy_enum_works() {
        assert_eq!(SyncStrategy::LastWriteWins, SyncStrategy::LastWriteWins);
        assert_ne!(SyncStrategy::LastWriteWins, SyncStrategy::Set);
    }

    #[test]
    fn clock_comparison_works() {
        assert_eq!(ClockComparison::RemoteNewer, ClockComparison::RemoteNewer);
        assert_ne!(ClockComparison::RemoteNewer, ClockComparison::LocalNewer);
    }
}
