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

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::Write,
    crate::Result,
};

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

/// #   A sluggish write
#[derive(Debug)]
pub struct SluggishWrite<T> {
    output: T,
    should_pend: bool,
}

impl<T> SluggishWrite<T> {

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

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

}

impl<T> Write for SluggishWrite<T> where T: Write {

    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.should_pend = self.should_pend == false;
        self.output.write(&buf[..{
            let len = buf.len();
            if self.should_pend {
                len.checked_sub(100).unwrap_or(len).max(1).min(len)
            } else {
                len
            }
        }])
    }

    fn flush(&mut self) -> Result<()> {
        self.output.flush()
    }

}

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

    fn poll_write(self: Pin<&mut Self>, context: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> {
        let me = self.get_mut();
        me.should_pend = me.should_pend == false;
        if me.should_pend {
            let waker = context.waker().clone();
            task::spawn(async move {
                time::sleep(Duration::from_millis(10)).await;
                waker.wake();
            });
            Poll::Pending
        } else {
            Pin::new(&mut me.output).poll_write(context, &buf[..{
                let len = buf.len();
                if me.should_pend {
                    len.checked_sub(100).unwrap_or(len).max(1).min(len)
                } else {
                    len
                }
            }])
        }
    }

    fn poll_flush(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Result<()>> {
        Pin::new(&mut self.get_mut().output).poll_flush(context)
    }

    fn poll_shutdown(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Result<()>> {
        Pin::new(&mut self.get_mut().output).poll_shutdown(context)
    }

}
