use std::marker::PhantomData;

use crate::properties::Properties;
use crate::Error;

use super::device::Mixer;
use super::track::Track;
use super::{bool_result, sys};

/// A group for organizing tracks.
///
/// Groups allow you to receive post-mix callbacks for a subset of tracks,
/// which is useful for applying effects or level metering to specific
/// categories of sound (e.g., music vs. sound effects).
///
/// A group must not outlive its parent mixer (enforced by the lifetime
/// parameter).
pub struct Group<'mixer> {
    raw: *mut sys::MIX_Group,
    _marker: PhantomData<&'mixer Mixer>,
}

impl<'mixer> Group<'mixer> {
    pub(crate) fn from_raw(raw: *mut sys::MIX_Group) -> Self {
        Group {
            raw,
            _marker: PhantomData,
        }
    }

    /// Get a pointer to the underlying `MIX_Group`.
    #[inline]
    pub fn raw(&self) -> *mut sys::MIX_Group {
        self.raw
    }

    /// Assign a track to this group.
    ///
    /// A track can only belong to one group at a time. Assigning to a new group
    /// removes it from its previous group.
    #[doc(alias = "MIX_SetTrackGroup")]
    pub fn assign_track(&self, track: &Track) -> Result<(), Error> {
        bool_result(unsafe { sys::MIX_SetTrackGroup(track.raw(), self.raw) })
    }

    /// Remove a track from any group (return it to the default group).
    #[doc(alias = "MIX_SetTrackGroup")]
    pub fn remove_track(&self, track: &Track) -> Result<(), Error> {
        bool_result(unsafe { sys::MIX_SetTrackGroup(track.raw(), std::ptr::null_mut()) })
    }

    /// Get the properties associated with this group.
    ///
    /// The returned `Properties` is borrowed from SDL and will not be
    /// destroyed when dropped.
    #[doc(alias = "MIX_GetGroupProperties")]
    pub fn properties(&self) -> Properties {
        let id = unsafe { sys::MIX_GetGroupProperties(self.raw) };
        Properties::const_from_ll(id)
    }
}

impl Drop for Group<'_> {
    fn drop(&mut self) {
        unsafe { sys::MIX_DestroyGroup(self.raw) };
    }
}
