pub mod canonical;
pub mod errors;
pub mod provider_types;
pub mod rights_registry;

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use uuid::Uuid;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum BillingProvider {
    Mollie,
    Stripe,
}

impl BillingProvider {
    pub const fn as_str(self) -> &'static str {
        match self {
            Self::Mollie => "mollie",
            Self::Stripe => "stripe",
        }
    }

    pub fn parse(value: &str) -> Option<Self> {
        match value.trim().to_ascii_lowercase().as_str() {
            "mollie" => Some(Self::Mollie),
            "stripe" => Some(Self::Stripe),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum BillingConnectionMode {
    Live,
    Test,
}

impl BillingConnectionMode {
    pub const fn as_str(self) -> &'static str {
        match self {
            Self::Live => "live",
            Self::Test => "test",
        }
    }

    pub fn parse(value: &str) -> Option<Self> {
        match value.trim().to_ascii_lowercase().as_str() {
            "live" => Some(Self::Live),
            "test" => Some(Self::Test),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum BillingConnectionStatus {
    Pending,
    Active,
    Disabled,
    Error,
}

impl BillingConnectionStatus {
    pub const fn is_connected(self) -> bool {
        matches!(self, Self::Active)
    }

    pub fn parse(value: &str) -> Option<Self> {
        match value.trim().to_ascii_lowercase().as_str() {
            "pending" => Some(Self::Pending),
            "active" => Some(Self::Active),
            "disabled" => Some(Self::Disabled),
            "error" => Some(Self::Error),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum BillingOwnerKind {
    User,
    Org,
    Workspace,
    Tenant,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BillingSubjectRef {
    pub owner_kind: BillingOwnerKind,
    pub owner_id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BillingProviderConnection {
    pub id: Uuid,
    pub provider: BillingProvider,
    pub provider_account_id: String,
    pub provider_profile_id: Option<String>,
    pub mode: BillingConnectionMode,
    pub status: BillingConnectionStatus,
    pub scopes: Vec<String>,
    pub config: Value,
    pub metadata: Value,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub deleted_at: Option<DateTime<Utc>>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct BillingFeatureFlags {
    pub payments: bool,
    pub subscriptions: bool,
    pub refunds: bool,
    pub documents: bool,
    pub mandates: bool,
    pub sales_invoices: bool,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BillingCapabilitiesDocument {
    pub provider: BillingProvider,
    pub connected: bool,
    pub mode: BillingConnectionMode,
    pub status: BillingConnectionStatus,
    pub provider_account_id: String,
    pub provider_profile_id: Option<String>,
    pub features: BillingFeatureFlags,
    pub claims: Vec<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AthenaPaymentStatus {
    Pending,
    Authorized,
    Paid,
    Failed,
    Canceled,
    Refunded,
}

impl AthenaPaymentStatus {
    pub const fn as_str(self) -> &'static str {
        match self {
            Self::Pending => "pending",
            Self::Authorized => "authorized",
            Self::Paid => "paid",
            Self::Failed => "failed",
            Self::Canceled => "canceled",
            Self::Refunded => "refunded",
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AthenaSubscriptionStatus {
    Trialing,
    Active,
    PastDue,
    Canceled,
    Paused,
}

impl AthenaSubscriptionStatus {
    pub const fn as_str(self) -> &'static str {
        match self {
            Self::Trialing => "trialing",
            Self::Active => "active",
            Self::PastDue => "past_due",
            Self::Canceled => "canceled",
            Self::Paused => "paused",
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AthenaInvoiceStatus {
    Draft,
    Open,
    Paid,
    Void,
    Uncollectible,
}

impl AthenaInvoiceStatus {
    pub const fn as_str(self) -> &'static str {
        match self {
            Self::Draft => "draft",
            Self::Open => "open",
            Self::Paid => "paid",
            Self::Void => "void",
            Self::Uncollectible => "uncollectible",
        }
    }
}
