# 💳 Como Funciona a Compra com Pontos

## 📋 **Visão Geral**

O sistema permite que clientes usem pontos Maktubia para pagar compras (total ou parcial) em estabelecimentos. A conversão é fixa: **1 MT = 10 Pontos**.

---

## 🔄 **Fluxo de Compra com Pontos**

### **1. Resgate Completo (Criar compra usando pontos)**

O cliente usa pontos para pagar uma compra inteira.

#### **Endpoint:**
```http
POST /api/purchases/redeem
```

#### **Request Body:**
```json
{
    "establishment_id": "EST_123",
    "points_amount": 1000,           // Pontos a usar
    "purchase_amount_mt": 100,        // Valor total da compra em MT
    "description": "Compra de produtos" // Opcional
}
```

#### **Processo:**
1. ✅ **Validações:**
   - Verifica se estabelecimento existe
   - Verifica se usuário tem saldo suficiente
   - Calcula valor em MT: `points_amount / 10` (1 MT = 10 pts)
   - Verifica se pontos cobrem o valor da compra

2. ✅ **Débito de Pontos:**
   - Debita pontos da carteira (`wallets`)
   - Usa `FOR UPDATE NOWAIT` para evitar race conditions

3. ✅ **Registros:**
   - Registra no histórico (`points_history`)
   - Registra no ledger (`points_ledger`) para rastreabilidade
   - Cria registro em `points_redemptions`
   - Cria compra em `purchases` com `payment_method = 'points'`

#### **Response:**
```json
{
    "success": true,
    "data": {
        "redemption_id": "RED_1234567890_abc123",
        "purchase_id": "PUR_1234567890_xyz789",
        "user_id": "user_123",
        "establishment_id": "EST_123",
        "points_used": 1000,
        "amount_mt_covered": 100,
        "purchase_amount_mt": 100,
        "previous_balance": 5000,
        "new_balance": 4000,
        "purchase": { ... },
        "created_at": "2024-01-15T10:30:00Z"
    },
    "message": "1000 pontos resgatados com sucesso! 100 MT cobertos."
}
```

---

### **2. Resgate Parcial (Usar pontos em compra existente)**

O cliente já tem uma compra e quer usar pontos para pagar parte dela.

#### **Endpoint:**
```http
POST /api/purchases/:id/partial-redeem
```

#### **Request Body:**
```json
{
    "points_amount": 500  // Pontos a usar
}
```

#### **Processo:**
1. ✅ **Validações:**
   - Verifica se compra existe
   - Verifica se compra pertence ao usuário
   - Verifica saldo suficiente

2. ✅ **Débito de Pontos:**
   - Debita pontos da carteira
   - Atualiza compra:
     - Adiciona `points_used`
     - Muda `payment_method` para `'points'` ou `'mixed'`

3. ✅ **Registros:**
   - Registra no histórico
   - Cria registro de resgate parcial

#### **Response:**
```json
{
    "success": true,
    "data": {
        "redemption_id": "RED_1234567890_abc123",
        "purchase_id": "PUR_1234567890_xyz789",
        "points_used": 500,
        "amount_mt_covered": 50,
        "previous_balance": 4500,
        "new_balance": 4000
    }
}
```

---

## 📊 **Regras de Conversão**

### **Taxa Fixa:**
- **1 MT = 10 Pontos** (imutável)
- Aplicada em todos os resgates

### **Exemplos:**

| Valor da Compra | Pontos Necessários | Cálculo |
|----------------|-------------------|---------|
| 10 MT | 100 pontos | 10 × 10 = 100 |
| 50 MT | 500 pontos | 50 × 10 = 500 |
| 100 MT | 1000 pontos | 100 × 10 = 1000 |
| 250 MT | 2500 pontos | 250 × 10 = 2500 |

### **Validação:**
```javascript
// Se compra = 100 MT, precisa de 1000 pontos
points_amount = 1000
amount_mt_covered = 1000 / 10 = 100 MT ✅

// Se compra = 100 MT, mas só tem 500 pontos
points_amount = 500
amount_mt_covered = 500 / 10 = 50 MT ❌
// Erro: "Pontos insuficientes. 500 pontos cobrem 50 MT, mas a compra é de 100 MT."
```

---

## 🔐 **Segurança e Integridade**

### **1. Transações Atômicas:**
- Todas as operações são feitas em transações SQL
- Se qualquer passo falhar, tudo é revertido (ROLLBACK)
- Garante consistência dos dados

### **2. Row-Level Locking:**
```sql
SELECT points FROM wallets
WHERE user_id = $1
FOR UPDATE NOWAIT
```
- Bloqueia a carteira durante a operação
- Previne race conditions em acessos concorrentes
- Garante que o saldo não seja alterado durante a operação

### **3. Validações:**
- ✅ Saldo suficiente antes de debitar
- ✅ Estabelecimento existe
- ✅ Compra pertence ao usuário (resgate parcial)
- ✅ Pontos cobrem valor da compra

---

## 📡 **Endpoints Disponíveis**

### **1. Resgatar Pontos para Compra**
```http
POST /api/purchases/redeem
```
**Autenticação:** ✅ Necessária  
**Body:**
- `establishment_id` (obrigatório)
- `points_amount` (obrigatório)
- `purchase_amount_mt` (opcional)
- `description` (opcional)

---

### **2. Resgatar Pontos Parcialmente**
```http
POST /api/purchases/:id/partial-redeem
```
**Autenticação:** ✅ Necessária  
**Body:**
- `points_amount` (obrigatório)

---

### **3. Listar Resgates**
```http
GET /api/points/redemptions
```
**Autenticação:** ✅ Necessária  
**Query Params:**
- `user_id` (opcional)
- `establishment_id` (opcional)
- `start_date` (opcional)
- `end_date` (opcional)
- `page` (opcional, padrão: 1)
- `limit` (opcional, padrão: 20)

---

## 🔄 **Fluxo Completo de Uso**

### **Cenário 1: Cliente compra produto usando pontos**

```javascript
// 1. Cliente escaneia QR code ou seleciona produto
// 2. Cliente escolhe pagar com pontos
POST /api/purchases/redeem
{
    "establishment_id": "EST_123",
    "points_amount": 1000,
    "purchase_amount_mt": 100,
    "description": "Compra de produtos"
}

// 3. Sistema valida e debita pontos
// 4. Sistema cria compra
// 5. Sistema registra tudo no histórico

// 6. Resposta:
{
    "success": true,
    "data": {
        "points_used": 1000,
        "amount_mt_covered": 100,
        "new_balance": 4000
    }
}
```

### **Cenário 2: Cliente compra produto e usa pontos parcialmente**

```javascript
// 1. Cliente cria compra normal (sem pontos)
POST /api/purchases/scan
{
    "qr_code": "QR_123",
    "amount": 200,
    "payment_method": "cash"
}

// 2. Cliente decide usar pontos para pagar parte
POST /api/purchases/PUR_123/partial-redeem
{
    "points_amount": 500  // 50 MT
}

// 3. Sistema atualiza compra:
// - payment_method: "mixed"
// - points_used: 500
// - Restante: 150 MT (pode pagar com dinheiro)
```

---

## 📊 **Estrutura de Dados**

### **Tabela `points_redemptions`:**
```sql
CREATE TABLE points_redemptions (
    redemption_id VARCHAR(64) PRIMARY KEY,
    user_id VARCHAR(64) NOT NULL,
    merchant_id INTEGER,  -- Loja onde foi usado
    purchase_id VARCHAR(64),
    points_amount BIGINT NOT NULL,
    amount_mt_covered NUMERIC(14,2) NOT NULL,
    purchase_amount_mt NUMERIC(14,2),
    description TEXT,
    created_at TIMESTAMP DEFAULT NOW()
);
```

### **Tabela `purchases`:**
```sql
-- Quando pagamento é com pontos:
payment_method = 'points'
points_used = 1000
amount = 100  -- Valor em MT

-- Quando pagamento é misto:
payment_method = 'mixed'
points_used = 500
amount = 200  -- Valor total em MT
-- Restante: 150 MT (pode pagar com dinheiro)
```

---

## ✅ **Validações e Erros**

### **Erros Comuns:**

1. **Saldo Insuficiente:**
```json
{
    "success": false,
    "message": "Saldo insuficiente. Você tem 500 pontos. Necessário: 1000 pontos."
}
```

2. **Pontos não cobrem compra:**
```json
{
    "success": false,
    "message": "Pontos insuficientes. 500 pontos cobrem 50 MT, mas a compra é de 100 MT."
}
```

3. **Estabelecimento não encontrado:**
```json
{
    "success": false,
    "message": "Estabelecimento não encontrado"
}
```

4. **Compra não pertence ao usuário:**
```json
{
    "success": false,
    "message": "Esta compra não pertence a você"
}
```

---

## 🔍 **Rastreabilidade**

### **Histórico de Pontos:**
Todas as operações são registradas em `points_history`:
```sql
INSERT INTO points_history (
    user_id, delta, reason, related_id
)
VALUES (
    'user_123',
    -1000,  -- Negativo para débito
    'Resgate de pontos para compra de 100 MT',
    'RED_1234567890_abc123'
);
```

### **Ledger (Rastreabilidade Completa):**
Registrado em `points_ledger` para rastreabilidade completa:
- Origem dos pontos resgatados
- Data e hora do resgate
- Estabelecimento onde foi usado
- Compra relacionada

---

## 📝 **Exemplo Completo de Uso**

### **Frontend/App Flutter:**

```dart
// 1. Usuário seleciona produto de 100 MT
double purchaseAmount = 100.0;

// 2. Calcula pontos necessários
int pointsNeeded = (purchaseAmount * 10).toInt(); // 1000 pontos

// 3. Verifica saldo
if (userPoints >= pointsNeeded) {
    // 4. Faz resgate
    var response = await http.post(
        Uri.parse('$baseUrl/api/purchases/redeem'),
        headers: {'Authorization': 'Bearer $token'},
        body: jsonEncode({
            'establishment_id': establishmentId,
            'points_amount': pointsNeeded,
            'purchase_amount_mt': purchaseAmount,
            'description': 'Compra de produtos'
        })
    );
    
    if (response.statusCode == 201) {
        // Sucesso! Compra realizada com pontos
        var data = jsonDecode(response.body)['data'];
        print('${data['points_used']} pontos usados');
        print('Saldo restante: ${data['new_balance']} pontos');
    }
} else {
    // Saldo insuficiente
    print('Saldo insuficiente. Você tem $userPoints pontos, mas precisa de $pointsNeeded pontos.');
}
```

---

## ✅ **Resumo**

1. ✅ **Resgate Completo**: `POST /api/purchases/redeem` - Criar compra usando pontos
2. ✅ **Resgate Parcial**: `POST /api/purchases/:id/partial-redeem` - Usar pontos em compra existente
3. ✅ **Listar Resgates**: `GET /api/points/redemptions` - Ver histórico de resgates
4. ✅ **Conversão Fixa**: 1 MT = 10 Pontos
5. ✅ **Transações Atômicas**: Garantem integridade dos dados
6. ✅ **Rastreabilidade**: Tudo registrado no histórico e ledger

**Status:** ✅ Implementado e funcional!

