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

use crate::{AthenaInvoiceStatus, AthenaPaymentStatus, AthenaSubscriptionStatus, BillingProvider};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CanonicalMoney {
    pub currency: String,
    pub value: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CanonicalPayment {
    pub provider: BillingProvider,
    pub provider_payment_id: String,
    pub provider_customer_id: Option<String>,
    pub provider_profile_id: Option<String>,
    pub provider_subscription_id: Option<String>,
    pub provider_payment_link_id: Option<String>,
    pub status: AthenaPaymentStatus,
    pub amount: CanonicalMoney,
    pub amount_refunded: Option<CanonicalMoney>,
    pub description: Option<String>,
    pub metadata: Value,
    pub paid_at: Option<DateTime<Utc>>,
    pub created_at: Option<DateTime<Utc>>,
    pub raw: Value,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CanonicalSubscription {
    pub provider: BillingProvider,
    pub provider_subscription_id: String,
    pub provider_customer_id: String,
    pub provider_profile_id: Option<String>,
    pub status: AthenaSubscriptionStatus,
    pub amount: Option<CanonicalMoney>,
    pub currency: Option<String>,
    pub interval: Option<String>,
    pub description: Option<String>,
    pub metadata: Value,
    pub next_payment_date: Option<String>,
    pub created_at: Option<DateTime<Utc>>,
    pub canceled_at: Option<DateTime<Utc>>,
    pub raw: Value,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CanonicalInvoice {
    pub provider: BillingProvider,
    pub provider_invoice_id: String,
    pub provider_profile_id: Option<String>,
    pub provider_customer_id: Option<String>,
    pub status: AthenaInvoiceStatus,
    pub amount: Option<CanonicalMoney>,
    pub amount_paid: Option<CanonicalMoney>,
    pub description: Option<String>,
    pub metadata: Value,
    pub issued_at: Option<DateTime<Utc>>,
    pub paid_at: Option<DateTime<Utc>>,
    pub created_at: Option<DateTime<Utc>>,
    pub raw: Value,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case", tag = "kind", content = "document")]
pub enum CanonicalBillingDocument {
    Payment(CanonicalPayment),
    Subscription(CanonicalSubscription),
    Invoice(CanonicalInvoice),
}
