use crate::{Service, ServiceCtx};

#[cfg(feature = "compress")]
use crate::http::Payload;
#[cfg(feature = "compress")]
use crate::http::encoding::Decoder;

use crate::http::body::MessageBody;

use super::connector::ConnectorService;
use super::error::ClientError;
use super::{ClientConfig, ClientRawRequest, Connect, ServiceRequest, ServiceResponse};

#[derive(Debug)]
pub struct Sender {
    config: ClientConfig,
    connector: ConnectorService,
}

impl Sender {
    pub(crate) fn new(connector: ConnectorService, config: ClientConfig) -> Self {
        Self { config, connector }
    }
}

#[allow(unused_variables)]
impl Service<ServiceRequest> for Sender {
    type Response = ServiceResponse;
    type Error = ClientError;

    crate::forward_ready!(connector);
    crate::forward_poll!(connector);
    crate::forward_shutdown!(connector);

    async fn call(
        &self,
        req: ServiceRequest,
        ctx: ServiceCtx<'_, Self>,
    ) -> Result<Self::Response, Self::Error> {
        let ServiceRequest {
            head,
            addr,
            body,
            headers,
            mut timeout,
            response_decompress,
        } = req;

        let con = ctx
            .call(
                &self.connector,
                Connect {
                    addr,
                    uri: head.uri.clone(),
                },
            )
            .await?;

        if timeout.is_zero() {
            timeout = self.config.timeout();
        }

        let req = ClientRawRequest {
            head,
            headers,
            size: body.size(),
        };

        let (head, payload) = con.send_request(req, body, timeout).await?;

        #[cfg(feature = "compress")]
        if response_decompress {
            let payload =
                Payload::from_stream(Decoder::from_headers(payload, &head.headers));
            return Ok(ServiceResponse {
                head,
                payload,
                config: self.config.clone(),
            });
        }

        Ok(ServiceResponse {
            head,
            payload,
            config: self.config.clone(),
        })
    }
}
