use super::Source;
use crate::{Error, Result};
use std::io::{BufRead, BufReader, IsTerminal, Read};
use tqdm::Tqdm;

pub struct HttpSource;

impl Source for HttpSource {
    fn read(content: &str) -> Result<Box<dyn BufRead + Send>> {
        let response = reqwest::blocking::get(content)
            .map_err(|err| Error::Reader(format!("http error: {err}")))?
            .error_for_status()
            .map_err(|err| Error::Reader(format!("http error: {err}")))?;
        let mut pb = Tqdm::new(std::iter::empty::<()>())
            .desc("downloading")
            .unit("B")
            .unit_scale(true)
            .disable(!std::io::stderr().is_terminal());
        if let Some(total) = response
            .content_length()
            .and_then(|n| usize::try_from(n).ok())
        {
            pb = pb.total(total);
        }
        let reader = ProgressRead {
            inner: response,
            pb,
        };
        Ok(Box::new(BufReader::new(reader)))
    }
}

struct ProgressRead<R> {
    inner: R,
    pb: Tqdm<std::iter::Empty<()>>,
}

impl<R: Read> Read for ProgressRead<R> {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        let n = self.inner.read(buf)?;
        if n > 0 {
            self.pb.update(n, false);
        }
        Ok(n)
    }
}
