//! billing — Inspect your plan, access status, and usage.

use serde::Deserialize;

use crate::client::Client;
use crate::decimal::Decimal;
use crate::error::Result;
use crate::http::{send, RequestOpts};
use crate::timestamp::Timestamp;

/// Current access state for an account.
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
#[non_exhaustive]
pub enum AccessStatus {
    /// Active subscription, full access.
    Active,
    /// On a trial.
    Trialing,
    /// Past due but within grace period; see [`BillingSummary::grace_until`].
    Grace,
    /// Access suspended.
    Suspended,
    /// No plan / no access.
    None,
    /// Forward-compat: unknown server-reported status.
    #[serde(other)]
    Unknown,
}

/// Usage totals for the current billing period.
#[derive(Debug, Clone, Deserialize)]
pub struct BillingUsage {
    /// Minutes of concurrent stream usage beyond the plan's included
    /// allowance. `0` on plans without overage.
    pub extra_stream_minutes_total: i64,
    /// Total size of successful exports this period, in GiB (1 GiB = 1024
    /// MiB).
    pub export_gb_total: Decimal,
    /// Export GiB beyond the included allowance, rounded up to a whole GiB.
    /// `0` when within the allowance.
    pub export_gb_extra: i64,
}

/// Billing state and usage for the current period.
#[derive(Debug, Clone, Deserialize)]
pub struct BillingSummary {
    /// Current access state.
    pub access_status: AccessStatus,
    /// When the grace period ends (RFC 3339 / ISO 8601). Set only when
    /// [`access_status`](Self::access_status) is [`AccessStatus::Grace`].
    #[serde(default)]
    pub grace_until: Option<Timestamp>,
    /// Plan identifier (e.g. `"trial"`, `"starter"`, `"pro"`). `None` if the
    /// account has no plan.
    #[serde(default)]
    pub plan_code: Option<String>,
    /// End of the current billing period (RFC 3339 / ISO 8601). `None` if
    /// the account has no active subscription.
    #[serde(default)]
    pub current_period_end: Option<Timestamp>,
    /// Usage totals for the current billing period.
    pub usage: BillingUsage,
}

/// Accessor for `/billing` endpoints.
pub struct BillingResource<'a> {
    pub(crate) client: &'a Client,
}

impl<'a> BillingResource<'a> {
    /// Retrieves the billing summary for the current period.
    ///
    /// # Errors
    ///
    /// - [`crate::Error::Authentication`] if the API key is invalid.
    /// - [`crate::Error::Network`] on transport failure.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # async fn example() -> ticksupply::Result<()> {
    /// let client = ticksupply::Client::new()?;
    /// let summary = client.billing().summary().await?;
    /// println!("status: {:?}, plan: {:?}", summary.access_status, summary.plan_code);
    /// # Ok(()) }
    /// ```
    pub async fn summary(&self) -> Result<BillingSummary> {
        send::<_, ()>(
            self.client,
            reqwest::Method::GET,
            "/billing/summary",
            None,
            None,
            RequestOpts::default(),
        )
        .await
    }
}
