use jack::RawMidi;
use kanal::Receiver;
use std::error::Error;

#[derive(Debug)]
pub enum MidiCommand {
    ControlChange { cc: u8, value: u8 },
    Quit,
}

pub struct MidiSender {
    midi_out: jack::Port<jack::MidiOut>,
    command_receiver: Receiver<MidiCommand>,
}

impl MidiSender {
    pub fn new(
        client: &jack::Client,
        command_receiver: Receiver<MidiCommand>,
    ) -> Result<Self, Box<dyn Error>> {
        let midi_out = client
            .register_port("fcb1010_mapper", jack::MidiOut::default())
            .map_err(|e| format!("Could not create MIDI output port: {}", e))?;

        Ok(Self {
            midi_out,
            command_receiver,
        })
    }
}

impl jack::ProcessHandler for MidiSender {
    fn process(&mut self, _client: &jack::Client, ps: &jack::ProcessScope) -> jack::Control {
        let mut midi_writer = self.midi_out.writer(ps);

        while let Ok(Some(command)) = self.command_receiver.try_recv() {
            match command {
                MidiCommand::ControlChange { cc, value } => {
                    let midi_data = [0xB0, cc, value]; // Control Change on channel 1
                    if let Err(e) = midi_writer.write(&RawMidi {
                        time: 0,
                        bytes: &midi_data,
                    }) {
                        eprintln!("Failed to send MIDI: {}", e);
                    }
                }
                MidiCommand::Quit => return jack::Control::Quit,
            }
        }

        jack::Control::Continue
    }
}
