use std::future::Future;

use reqwest::Method;
use turborepo_vercel_api::telemetry::TelemetryEvent;

use crate::{AnonAPIClient, Error, SharedHttpClient, add_ai_agent_header, build_user_agent, retry};

const TELEMETRY_ENDPOINT: &str = "/api/turborepo/v1/events";

pub trait TelemetryClient {
    fn record_telemetry(
        &self,
        events: Vec<TelemetryEvent>,
        telemetry_id: &str,
        session_id: &str,
    ) -> impl Future<Output = Result<(), Error>> + Send;
}

impl TelemetryClient for AnonAPIClient {
    async fn record_telemetry(
        &self,
        events: Vec<TelemetryEvent>,
        telemetry_id: &str,
        session_id: &str,
    ) -> Result<(), Error> {
        let url = self.make_url(TELEMETRY_ENDPOINT);
        let telemetry_request = add_ai_agent_header(
            self.client
                .request(Method::POST, url)
                .header("User-Agent", self.user_agent.clone())
                .header("Content-Type", "application/json")
                .header("x-turbo-telemetry-id", telemetry_id)
                .header("x-turbo-session-id", session_id)
                .json(&events),
        );

        retry::make_retryable_request(telemetry_request, retry::RetryStrategy::Timeout)
            .await?
            .into_response()
            .error_for_status()?;

        Ok(())
    }
}

/// A telemetry client backed by the shared on-demand HTTP client.
#[derive(Clone)]
pub struct DeferredTelemetryClient {
    http_client: SharedHttpClient,
    base_url: String,
    user_agent: String,
}

impl DeferredTelemetryClient {
    pub fn new(http_client: SharedHttpClient, base_url: impl Into<String>, version: &str) -> Self {
        Self {
            http_client,
            base_url: base_url.into(),
            user_agent: build_user_agent(version),
        }
    }
}

impl TelemetryClient for DeferredTelemetryClient {
    async fn record_telemetry(
        &self,
        events: Vec<TelemetryEvent>,
        telemetry_id: &str,
        session_id: &str,
    ) -> Result<(), Error> {
        let client = self.http_client.get_or_init().await?;

        let url = format!("{}{}", self.base_url, TELEMETRY_ENDPOINT);
        let telemetry_request = add_ai_agent_header(
            client
                .request(Method::POST, url)
                .header("User-Agent", self.user_agent.clone())
                .header("Content-Type", "application/json")
                .header("x-turbo-telemetry-id", telemetry_id)
                .header("x-turbo-session-id", session_id)
                .json(&events),
        );

        retry::make_retryable_request(telemetry_request, retry::RetryStrategy::Timeout)
            .await?
            .into_response()
            .error_for_status()?;

        Ok(())
    }
}
