# Ads Billing Service Architecture / Kiến Trúc Dịch Vụ Thanh Toán Quảng Cáo

## Tổng Quan / Overview

```mermaid
graph TB
    subgraph "ads-billing-service"
        API[API Layer]
        APP[Application Layer]
        DOM[Domain Layer]
        INF[Infrastructure Layer]
    end
    
    subgraph "External Services"
        SERVE[ads-serving-service]
        WALLET[Wallet Service]
        MQ[RabbitMQ]
    end
    
    SERVE -->|Charge Events| MQ
    MQ --> INF
    INF --> DOM
    DOM -->|Debit Request| MQ
    MQ --> WALLET
```

## Domain Aggregates

### BillingAccountAggregate
- **BillingAccount** (Root): Links to Wallet, payment settings
- **PaymentMethod**: Credit Card, Bank, Wallet
- **BillingThreshold**: $25, $50, $250, $500

### CreditLineAggregate
- **CreditLine** (Root): Postpaid limit
- **CreditEvaluation**: Trust score calculation
- **PaymentHistory**: Track payment reliability

### InvoiceAggregate
- **Invoice** (Root): Monthly/threshold invoice
- **InvoiceLineItem**: Per-campaign charges
- **TaxCalculation**: VAT by region

### ChargeAggregate
- **AdCharge**: Individual impression/click cost
- **DailySpendSummary**: Aggregated daily charges

## Billing Flow

```
┌─────────────────────────────────────────────────────────────────┐
│                     BILLING FLOW                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  PREPAID                          POSTPAID                       │
│  ────────                         ────────                       │
│                                                                  │
│  1. Add Funds ──► Wallet          1. Run Ads ──► Accumulate     │
│  2. Run Ads ──► Deduct            2. Reach Threshold             │
│  3. Balance = 0 ──► Pause         3. Auto-charge ──► Invoice    │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

## Database Schema

```sql
-- Billing Accounts
CREATE TABLE billing_accounts (
    id UUID PRIMARY KEY,
    advertiser_id UUID NOT NULL,
    wallet_id UUID,
    billing_type VARCHAR(20), -- 'PREPAID' | 'POSTPAID'
    threshold_level INT DEFAULT 25,
    current_balance DECIMAL(18, 2),
    credit_limit DECIMAL(18, 2),
    created_at TIMESTAMP DEFAULT NOW()
);

-- Charges (high volume)
CREATE TABLE ad_charges (
    id UUID PRIMARY KEY,
    billing_account_id UUID REFERENCES billing_accounts(id),
    campaign_id UUID NOT NULL,
    ad_id UUID NOT NULL,
    charge_type VARCHAR(20), -- 'IMPRESSION' | 'CLICK'
    amount DECIMAL(18, 6),
    charged_at TIMESTAMP DEFAULT NOW()
);

-- Invoices
CREATE TABLE invoices (
    id UUID PRIMARY KEY,
    billing_account_id UUID REFERENCES billing_accounts(id),
    invoice_number VARCHAR(50) UNIQUE,
    period_start DATE,
    period_end DATE,
    subtotal DECIMAL(18, 2),
    tax_amount DECIMAL(18, 2),
    total DECIMAL(18, 2),
    status VARCHAR(20), -- 'DRAFT' | 'ISSUED' | 'PAID'
    issued_at TIMESTAMP
);
```

## Threshold Billing Logic

```csharp
/// <summary>
/// EN: Check and trigger threshold billing.
/// VI: Kiểm tra và kích hoạt billing theo ngưỡng.
/// </summary>
public async Task ProcessChargeAsync(AdCharge charge)
{
    var account = await _accountRepository.GetAsync(charge.BillingAccountId);
    
    // EN: Accumulate spend
    account.AddCharge(charge.Amount);
    
    // EN: Check threshold
    if (account.BillingType == BillingType.Postpaid 
        && account.PendingBalance >= account.ThresholdLevel)
    {
        // EN: Trigger auto-charge
        await _publisher.Publish(new WalletDebitRequestedEvent
        {
            WalletId = account.WalletId,
            Amount = account.PendingBalance,
            Description = $"Ads spend threshold reached",
            ReferenceId = account.Id,
            ReferenceType = "ADS_BILLING"
        });
        
        // EN: Generate invoice
        var invoice = account.GenerateInvoice();
        await _invoiceRepository.AddAsync(invoice);
        
        account.ResetPendingBalance();
    }
    
    await _accountRepository.UnitOfWork.SaveChangesAsync();
}
```

## Integration Events

```csharp
// Consume from ads-serving
public record AdImpressionChargedEvent(
    Guid AdId, Guid CampaignId, Guid AdvertiserId,
    decimal Cost, DateTime ChargedAt);

// Publish to wallet-service
public record WalletDebitRequestedEvent(
    Guid WalletId, decimal Amount, string Description,
    Guid ReferenceId, string ReferenceType);
```

## API Endpoints

| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/api/v1/ads-billing/accounts/{id}` | Account info |
| `POST` | `/api/v1/ads-billing/accounts/{id}/add-funds` | Add funds |
| `GET` | `/api/v1/ads-billing/invoices` | List invoices |
