Documentation
use crate::body::VariantBody;
use hyper::body::Incoming;
use hyper::client::conn::{TrySendError, http2};
use hyper::http::uri::InvalidUri;
use hyper::{Method, Request, Response, Uri, Version, http};
use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use crate::utils::RefCount;

#[derive(Debug, Clone)]
pub(crate) struct SendRequest {
    inner: http2::SendRequest<VariantBody>,
    _ref: Arc<()>,
}

impl SendRequest {
    pub(crate) fn new(inner: http2::SendRequest<VariantBody>) -> Self {
        Self {
            inner,
            _ref: Arc::new(()),
        }
    }

    /// 引用数量
    pub(crate) fn ref_count(&self) -> usize {
        Arc::strong_count(&self._ref)
    }

    /// 是否达到最大数
    pub(crate) fn limited(&self, max_streams: Option<usize>) -> bool {
        if let Some(max) = max_streams {
            // 这里要加2, 因为队列里一份, run那里一份
            if self.ref_count() >= max + 2 {
                return true;
            }
        }
        false
    }
}

impl Deref for SendRequest {
    type Target = http2::SendRequest<VariantBody>;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl DerefMut for SendRequest {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl PartialEq for SendRequest {
    fn eq(&self, other: &Self) -> bool {
        self._ref.as_ref() as *const _ == other._ref.as_ref() as *const _
    }
}

impl RefCount for SendRequest {
    fn ref_count(&self) -> usize {
        self.ref_count()
    }
}

#[derive(Debug)]
pub struct Sender {
    sender: SendRequest,
    base_url: String,
}

impl Sender {
    pub(crate) fn new(sender: SendRequest, base_url: String) -> Self {
        Sender { sender, base_url }
    }

    #[allow(dead_code)]
    pub(crate) fn from_http2_sr(sr: http2::SendRequest<VariantBody>, base_url: String) -> Self {
        Self::new(SendRequest::new(sr), base_url)
    }

    pub fn base_url(&self) -> &String {
        &self.base_url
    }

    pub fn new_uri(&self, uri: &Uri) -> Result<Uri, InvalidUri> {
        crate::utils::new_uri(self.base_url.clone(), uri)
    }

    pub fn is_ready(&self) -> bool {
        self.sender.is_ready()
    }

    pub fn is_closed(&self) -> bool {
        self.sender.is_closed()
    }

    pub fn send_request(
        &mut self,
        req: Request<VariantBody>,
    ) -> impl Future<Output = hyper::Result<Response<Incoming>>> {
        self.sender.send_request(req)
    }

    pub fn try_send_request(
        &mut self,
        req: Request<VariantBody>,
    ) -> impl Future<Output = Result<Response<Incoming>, TrySendError<Request<VariantBody>>>> {
        self.sender.try_send_request(req)
    }
}

pub fn request_builder<T>(uri: T, method: Method) -> http::request::Builder
where
    T: TryInto<Uri>,
    <T as TryInto<Uri>>::Error: Into<http::Error>,
{
    Request::builder()
        .version(Version::HTTP_2)
        .method(method)
        .uri(uri)
        .header(hyper::header::USER_AGENT, "proxy/0.1")
}