use crate::*;

#[derive(Debug)]
pub struct OscController {
    sender: kanal::Sender<osc::Message>,
}

impl OscController {
    pub(crate) fn new(sender: kanal::Sender<osc::Message>) -> Self {
        Self { sender }
    }

    pub fn track_state_changed(&self, column: usize, row: usize, state: TrackState) -> Result<()> {
        let message = osc::Message::TrackStateChanged {
            column,
            row,
            state: state.into(),
        };
        match self.sender.try_send(message) {
            Ok(true) => Ok(()),
            Ok(false) => Err(LooperError::Osc(std::panic::Location::caller())), // Channel full
            Err(_) => Err(LooperError::Osc(std::panic::Location::caller())),    // Channel closed
        }
    }

    pub fn track_volume_changed(&self, column: usize, row: usize, volume: f32) -> Result<()> {
        let message = osc::Message::TrackVolumeChanged {
            column,
            row,
            volume,
        };
        match self.sender.try_send(message) {
            Ok(true) => Ok(()),
            Ok(false) => Err(LooperError::Osc(std::panic::Location::caller())), // Channel full
            Err(_) => Err(LooperError::Osc(std::panic::Location::caller())),    // Channel closed
        }
    }

    pub fn selected_column_changed(&self, column: usize) -> Result<()> {
        let message = osc::Message::SelectedColumnChanged { column };
        match self.sender.try_send(message) {
            Ok(true) => Ok(()),
            Ok(false) => Err(LooperError::Osc(std::panic::Location::caller())), // Channel full
            Err(_) => Err(LooperError::Osc(std::panic::Location::caller())),    // Channel closed
        }
    }

    pub fn selected_row_changed(&self, row: usize) -> Result<()> {
        let message = osc::Message::SelectedRowChanged { row };
        match self.sender.try_send(message) {
            Ok(true) => Ok(()),
            Ok(false) => Err(LooperError::Osc(std::panic::Location::caller())), // Channel full
            Err(_) => Err(LooperError::Osc(std::panic::Location::caller())),    // Channel closed
        }
    }

    pub fn metronome_position_changed(&self, position: f32) -> Result<()> {
        let message = osc::Message::MetronomePosition { position };
        match self.sender.try_send(message) {
            Ok(true) => Ok(()),
            Ok(false) => Err(LooperError::Osc(std::panic::Location::caller())), // Channel full
            Err(_) => Err(LooperError::Osc(std::panic::Location::caller())),    // Channel closed
        }
    }

    pub fn column_beats_changed(&self, column: usize, beats: usize) -> Result<()> {
        let message = osc::Message::ColumnBeatsChanged { column, beats };
        match self.sender.try_send(message) {
            Ok(true) => Ok(()),
            Ok(false) => Err(LooperError::Osc(std::panic::Location::caller())), // Channel full
            Err(_) => Err(LooperError::Osc(std::panic::Location::caller())),    // Channel closed
        }
    }

    pub fn column_beat_changed(&self, column: usize, beat: usize) -> Result<()> {
        let message = osc::Message::ColumnBeatChanged { column, beat };
        match self.sender.try_send(message) {
            Ok(true) => Ok(()),
            Ok(false) => Err(LooperError::Osc(std::panic::Location::caller())), // Channel full
            Err(_) => Err(LooperError::Osc(std::panic::Location::caller())),    // Channel closed
        }
    }
}
