use std::sync::mpsc::Receiver;
use std::sync::mpsc::Sender;
use std::sync::mpsc::SyncSender;

use oxydsp_flowgraph::BlockIO;
use oxydsp_flowgraph::block::Block;
use oxydsp_flowgraph::block::BlockResult;
use oxydsp_flowgraph::io::In;
use oxydsp_flowgraph::io::Out;
use oxydsp_flowgraph::io::stream;

#[derive(BlockIO)]
pub struct RxSource<Rx, I: 'static>
{
    input: Rx,

    #[output]
    output: Out<I>,
}

#[derive(BlockIO)]
pub struct TxSink<Tx, I: 'static>
{
    #[input]
    input: In<I>,

    output: Tx,
}

impl<Rx, I: 'static> RxSource<Rx, I>
{
    pub fn new(input: Rx) -> (Self, In<I>)
    {
        let (output, source) = stream();
        (Self { input, output }, source)
    }
}

impl<Tx, I: 'static> TxSink<Tx, I>
{
    pub fn new(input: In<I>, output: Tx) -> Self
    {
        Self { input, output }
    }
}

impl<I: 'static> Block for RxSource<Receiver<I>, I>
{
    fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
    {
        self
            .output
            .push_iter(self.input.try_iter().map(|x| (x, None).into()));
        BlockResult::Ok
    }
}

impl<I: 'static> Block for TxSink<Sender<I>, I>
{
    fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
    {
        if self
            .input
            .iter()
            .map(|x| self.output.send(x.0))
            .any(|res| res.is_err())
        {
            BlockResult::Terminated
        }
        else
        {
            BlockResult::Ok
        }
    }
}

impl<I: 'static> Block for TxSink<SyncSender<I>, I>
{
    fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
    {
        if self
            .input
            .iter()
            .map(|x| self.output.send(x.0))
            .any(|res| res.is_err())
        {
            BlockResult::Terminated
        }
        else
        {
            BlockResult::Ok
        }
    }
}
