use reqwest::Method;

use super::{urlencode, Client};
use crate::error::Error;
use crate::types::{
    DowngradePayload, DowngradeResponse, InvoicesPage, IssuedTrial, PlansResponse, PortalLink,
};

impl Client {
    pub async fn plans(&self) -> Result<PlansResponse, Error> {
        let path = format!("/api/v1/products/{}/plans", self.product_slug);
        self.do_request::<_, PlansResponse>(Method::GET, &path, None::<&()>)
            .await
    }

    pub async fn start_trial(&self, plan_key: Option<&str>) -> Result<IssuedTrial, Error> {
        let path = format!("/api/v1/me/products/{}/trial", self.product_slug);
        let body = plan_key.map(|p| serde_json::json!({ "plan": p }));
        self.do_request::<_, IssuedTrial>(Method::POST, &path, body.as_ref())
            .await
    }

    /// GET /api/billing/portal - Stripe customer portal short-lived URL.
    pub async fn billing_portal(&self, return_url: &str) -> Result<PortalLink, Error> {
        let path = format!("/api/billing/portal?return_url={}", urlencode(return_url));
        self.do_request::<_, PortalLink>(Method::GET, &path, None::<&()>)
            .await
    }

    /// GET /api/me/invoices - paginated customer invoices.
    pub async fn invoices(&self, cursor: Option<&str>) -> Result<InvoicesPage, Error> {
        let path = match cursor {
            Some(cursor) => format!("/api/me/invoices?starting_after={}", urlencode(cursor)),
            None => "/api/me/invoices".to_string(),
        };
        self.do_request::<_, InvoicesPage>(Method::GET, &path, None::<&()>)
            .await
    }

    /// POST /api/me/subscription/downgrade - schedule a downgrade for a product.
    /// A free target cancels at period end; a lower paid tier swaps the plan.
    pub async fn downgrade_subscription(
        &self,
        payload: DowngradePayload<'_>,
    ) -> Result<DowngradeResponse, Error> {
        self.do_request::<_, DowngradeResponse>(
            Method::POST,
            "/api/me/subscription/downgrade",
            Some(&payload),
        )
        .await
    }

    /// POST /api/me/subscription/resume: undo a scheduled cancellation.
    pub async fn resume_subscription(&self, product: &str) -> Result<DowngradeResponse, Error> {
        self.do_request::<_, DowngradeResponse>(
            Method::POST,
            "/api/me/subscription/resume",
            Some(&DowngradePayload {
                product,
                target_plan: None,
            }),
        )
        .await
    }
}
