/*
==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--

sluggish-write

Copyright (C) 2026  Anonymous



This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
*/


use {
    std::io::Read,
    crate::Result,
};

#[cfg(feature="tokio")]
use {
    core::{
        pin::Pin,
        task::{Context, Poll},
    },
    tokio::io::{AsyncRead, ReadBuf},
};

/// #   A sluggish read
#[derive(Debug)]
pub struct SluggishRead<T> {
    input: T,
    should_pend: bool,
}

impl<T> SluggishRead<T> {

    /// #   Makes new instance
    pub const fn new(input: T) -> Self {
        Self {
            input,
            should_pend: false,
        }
    }

    /// #   Returns inner as-is
    pub fn into_inner(self) -> T {
        self.input
    }

}

impl<T> Read for SluggishRead<T> where T: Read {

    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.should_pend = self.should_pend == false;

        let buf_len = buf.len();
        self.input.read(&mut buf[..{
            if self.should_pend {
                buf_len.checked_sub(199).unwrap_or(buf_len).max(1).min(buf_len)
            } else {
                buf_len
            }
        }])
    }

}

#[cfg(feature="tokio")]
impl<T> AsyncRead for SluggishRead<T> where T: AsyncRead + Unpin {

    fn poll_read(self: Pin<&mut Self>, context: &mut Context<'_>, buf: &mut ReadBuf) -> Poll<Result<()>> {
        let me = self.get_mut();
        me.should_pend = me.should_pend == false;
        if me.should_pend {
            let remaining = buf.remaining();
            let mut sub_buf = ReadBuf::new(buf.initialize_unfilled_to(remaining.checked_sub(199).unwrap_or(remaining).max(1).min(remaining)));
            match Pin::new(&mut me.input).poll_read(context, &mut sub_buf) {
                Poll::Ready(Ok(())) => {
                    let bytes_read = sub_buf.filled().len();
                    buf.advance(bytes_read);
                    Poll::Ready(Ok(()))
                }
                Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
                Poll::Pending => Poll::Pending,
            }
        } else {
            Pin::new(&mut me.input).poll_read(context, buf)
        }
    }

}
