# Simulador

Simulador BACEN PIX para desenvolvimento, testes e homologacao sem conexao real com o Banco Central.

## Pre-requisitos

- Variavel de ambiente `SIMULATOR_ENABLED=true`
- Variavel `BACEN_ENABLED=false` (simulador substitui chamadas reais)
- Migracao #11 (`20260203100008`) aplicada (tabelas do simulador)
- Seed do simulador executado (`simulator_seed.exs`)
- Acesso ao portal admin com permissao `simulator`

::: danger NAO USE EM PRODUCAO
O simulador **nunca** deve ser habilitado em ambientes de producao. Ele substitui completamente a comunicacao com o BACEN por respostas simuladas.
:::

## Arquitetura

```mermaid
flowchart TB
    subgraph Backend["Backend PIX"]
        SC["SimulatorController<br/>(11 endpoints)"]
        SG["Shared.Bacen.Simulator<br/>(GenServer)"]
    end

    subgraph DB["PostgreSQL"]
        CFG["bacen_simulator.config"]
        CEN["bacen_simulator.scenarios"]
        TR["bacen_simulator.test_runs"]
        EX["bacen_simulator.exchanges"]
    end

    subgraph Servicos["Servicos Internos"]
        DICT["DICT Service"]
        SPI["SPI Service"]
    end

    SC --> SG
    SG --> DB
    SG --> DICT & SPI
    CFG & CEN & TR & EX -.-> DB
```

### GenServer do Simulador

O `Shared.Bacen.Simulator` e um GenServer iniciado condicionalmente pelo `Shared.Application`:

```elixir
# Shared.Application
children =
  if simulator_enabled do
    IO.puts("[Shared.Application] BACEN Simulator enabled")
    base_children ++ [Shared.Bacen.Simulator]
  else
    base_children
  end
```

| Parametro | Valor |
|-----------|-------|
| Supervisao | `Shared.Application` (one_for_one) |
| Condicao | `SIMULATOR_ENABLED=true` |
| max_restarts | 10 em 60s |

## Habilitacao

```bash
# Docker Compose (desenvolvimento)
SIMULATOR_ENABLED=true BACEN_ENABLED=false mix phx.server

# Kubernetes (homologacao)
kubectl set env deployment/pix-backend -n pix \
  SIMULATOR_ENABLED=true \
  BACEN_ENABLED=false
```

## Cenarios Integrados

O simulador inclui 8 cenarios pre-configurados:

| Cenario | Descricao | Resultado Esperado |
|---------|-----------|-------------------|
| `happy_path` | Fluxo completo de pagamento PIX (envio + liquidacao) | STLD em < 1.6s |
| `rejected_payment` | Pagamento rejeitado pelo recebedor | RJCT com codigo de razao |
| `return_flow` | Envio seguido de devolucao (pacs.004) | RTRN com referencia original |
| `incoming_payment` | Recebimento de PIX de outra instituicao | STLD (inbound) |
| `echo_test` | Echo request/response (pibr.001/002) | Resposta identica ao request |
| `balance_check` | Consulta de saldo SPI (camt.060) | Saldo atual da conta |
| `full_cycle` | Ciclo completo: envio + recebimento + liquidacao + contabilizacao | Todos os estados |
| `stress_test` | 100 transacoes simultaneas | Throughput e latencia |

### Dados de Seed do Simulador

| Dado | Quantidade | Descricao |
|------|-----------|-----------|
| Configuracoes | 10 | Parametros do simulador |
| Cenarios | 10 | 8 integrados + 2 customizados |
| Entradas DICT | 20 | Chaves PIX de teste |
| Saldos SPI | 12 | Saldos iniciais por participante |

## API do Simulador

### Endpoints

| Metodo | Path | Descricao |
|--------|------|-----------|
| GET | `/api/v1/simulator/status` | Status atual do simulador |
| GET | `/api/v1/simulator/config` | Configuracao do simulador |
| PUT | `/api/v1/simulator/config` | Atualizar configuracao |
| POST | `/api/v1/simulator/process` | Processar mensagem simulada |
| POST | `/api/v1/simulator/inbound` | Simular mensagem recebida |
| GET | `/api/v1/simulator/scenarios` | Listar cenarios disponiveis |
| GET | `/api/v1/simulator/scenarios/:id` | Detalhe do cenario |
| POST | `/api/v1/simulator/scenarios/:id/run` | Executar cenario |
| GET | `/api/v1/simulator/test-runs` | Listar execucoes de teste |
| GET | `/api/v1/simulator/test-runs/:id` | Detalhe da execucao |
| GET | `/api/v1/simulator/exchanges` | Listar trocas de mensagem |

### Verificar Status

```bash
curl -s https://pixapi-dev.fluxiq.com.br/api/v1/simulator/status \
  -H "Cookie: pix_session=<token>" | jq
```

Resposta:

```json
{
  "enabled": true,
  "status": "running",
  "uptime_seconds": 3600,
  "scenarios_available": 10,
  "test_runs_total": 45,
  "last_test_run": "2026-02-13T14:00:00Z"
}
```

### Executar Cenario

```bash
# Executar cenario happy_path
curl -X POST https://pixapi-dev.fluxiq.com.br/api/v1/simulator/scenarios/happy_path/run \
  -H "Cookie: pix_session=<token>" \
  -H "Content-Type: application/json" \
  -d '{
    "parameters": {
      "amount": 15000,
      "debtor_ispb": "12345678",
      "creditor_ispb": "53822116"
    }
  }' | jq
```

Resposta:

```json
{
  "test_run_id": "uuid",
  "scenario": "happy_path",
  "status": "running",
  "started_at": "2026-02-13T14:30:00Z",
  "steps": [
    {"step": 1, "action": "create_pacs008", "status": "completed"},
    {"step": 2, "action": "process_outbound", "status": "completed"},
    {"step": 3, "action": "simulate_bacen_response", "status": "running"},
    {"step": 4, "action": "process_inbound_pacs002", "status": "pending"},
    {"step": 5, "action": "settle_transaction", "status": "pending"}
  ]
}
```

### Simular Mensagem Inbound

```bash
# Simular recebimento de pacs.008 do BACEN
curl -X POST https://pixapi-dev.fluxiq.com.br/api/v1/simulator/inbound \
  -H "Cookie: pix_session=<token>" \
  -H "Content-Type: application/json" \
  -d '{
    "message_type": "pacs.008",
    "sender_ispb": "53822116",
    "receiver_ispb": "12345678",
    "amount": 25000,
    "end_to_end_id": "E5382211620260213150000000000001",
    "creditor": {
      "name": "Joao Silva",
      "cpf_cnpj": "12345678901",
      "account": "123456",
      "branch": "0001"
    },
    "remittance_info": "Pagamento de teste via simulador"
  }' | jq
```

### Listar Trocas de Mensagem

```bash
curl -s "https://pixapi-dev.fluxiq.com.br/api/v1/simulator/exchanges?limit=10" \
  -H "Cookie: pix_session=<token>" | jq '.data[:2]'
```

Resposta:

```json
[
  {
    "id": "uuid",
    "test_run_id": "uuid",
    "direction": "outbound",
    "message_type": "pacs.008",
    "sender_ispb": "12345678",
    "receiver_ispb": "53822116",
    "amount": 15000,
    "status": "accepted",
    "sent_at": "2026-02-13T14:30:00.100Z",
    "response_at": "2026-02-13T14:30:00.800Z",
    "latency_ms": 700
  }
]
```

## Teste de Integracao (200/200)

O teste de integracao completo valida o fluxo bidirecional:

### Execucao

```bash
# Executar teste de integracao completo
curl -X POST https://pixapi-dev.fluxiq.com.br/api/v1/simulator/scenarios/full_cycle/run \
  -H "Cookie: pix_session=<token>" \
  -H "Content-Type: application/json" \
  -d '{
    "parameters": {
      "send_count": 100,
      "receive_count": 100,
      "sender_ispb": "12345678",
      "receiver_ispb": "53822116"
    }
  }' | jq
```

### Resultado Esperado

| Metrica | Valor |
|---------|-------|
| Total de transacoes | 200 |
| Envio (MONETARIE -> MW) | 100 |
| Recebimento (MW -> MONETARIE) | 100 |
| Status SUCCESS | 200/200 (100%) |
| Latencia media | 300-800ms |
| ANS compliance | 100% (< 1.6s) |

### Verificar Resultados

```bash
# Verificar resultado do test run
curl -s "https://pixapi-dev.fluxiq.com.br/api/v1/simulator/test-runs/<test_run_id>" \
  -H "Cookie: pix_session=<token>" | jq
```

```json
{
  "id": "uuid",
  "scenario": "full_cycle",
  "status": "completed",
  "started_at": "2026-02-13T14:30:00Z",
  "completed_at": "2026-02-13T14:32:45Z",
  "duration_seconds": 165,
  "results": {
    "total": 200,
    "success": 200,
    "failed": 0,
    "success_rate": 100.0,
    "avg_latency_ms": 550,
    "p95_latency_ms": 1200,
    "p99_latency_ms": 1450,
    "ans_compliant": 200,
    "ans_exceeded": 0
  }
}
```

## Criacao de Cenarios Customizados

### Via API

```bash
curl -X POST https://pixapi-dev.fluxiq.com.br/api/v1/simulator/scenarios \
  -H "Cookie: pix_session=<token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "high_value_transfer",
    "description": "Teste de transferencia de alto valor (> R$ 100.000)",
    "steps": [
      {
        "action": "create_pacs008",
        "parameters": {
          "amount": 10000000,
          "require_alcada": true
        }
      },
      {
        "action": "simulate_alcada_approval",
        "parameters": {
          "approval_level": 2,
          "delay_ms": 5000
        }
      },
      {
        "action": "process_outbound",
        "parameters": {}
      },
      {
        "action": "simulate_bacen_response",
        "parameters": {
          "response_type": "accepted",
          "delay_ms": 800
        }
      },
      {
        "action": "settle_transaction",
        "parameters": {}
      }
    ]
  }' | jq
```

### Parametros de Simulacao

| Parametro | Tipo | Descricao |
|-----------|------|-----------|
| `delay_ms` | Integer | Atraso simulado (latencia BACEN) |
| `response_type` | String | `accepted`, `rejected`, `timeout` |
| `error_code` | String | Codigo de erro BACEN (ex: `AB03`) |
| `require_alcada` | Boolean | Exigir aprovacao de alcada |
| `approval_level` | Integer | Nivel de aprovacao (1-3) |

## Seguranca do Simulador

::: warning PROTECAO CONTRA ATOM TABLE DoS
O `SimulatorController` utiliza `String.to_existing_atom/1` com whitelist para evitar o ataque de atom table exhaustion. Valores desconhecidos sao rejeitados com erro 400.
:::

::: warning SERIALIZACAO JSON
O `SimulatorController` possui `sanitize_for_json/1` que converte tipos Elixir nativos para JSON:
- `Decimal` -> `String`
- `DateTime` / `NaiveDateTime` -> ISO 8601 string
- Structs -> Map (remove `__struct__`)
:::

## Schema do Banco

```sql
-- bacen_simulator schema
CREATE TABLE bacen_simulator.config (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  key VARCHAR(100) NOT NULL UNIQUE,
  value JSONB NOT NULL,
  description TEXT,
  updated_at TIMESTAMP DEFAULT NOW()
);

CREATE TABLE bacen_simulator.scenarios (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name VARCHAR(100) NOT NULL UNIQUE,
  description TEXT,
  steps JSONB NOT NULL,
  is_active BOOLEAN DEFAULT true,
  created_at TIMESTAMP DEFAULT NOW()
);

CREATE TABLE bacen_simulator.test_runs (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  scenario_id UUID REFERENCES bacen_simulator.scenarios(id),
  status VARCHAR(20) NOT NULL DEFAULT 'pending',
  parameters JSONB,
  results JSONB,
  started_at TIMESTAMP,
  completed_at TIMESTAMP
);

CREATE TABLE bacen_simulator.exchanges (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  test_run_id UUID REFERENCES bacen_simulator.test_runs(id),
  direction VARCHAR(10) NOT NULL,
  message_type VARCHAR(20) NOT NULL,
  payload JSONB,
  response JSONB,
  latency_ms INTEGER,
  created_at TIMESTAMP DEFAULT NOW()
);
```

## Resultado Esperado

Apos habilitar o simulador:

- O GenServer `Shared.Bacen.Simulator` inicia no supervisor (log: `"BACEN Simulator enabled"`)
- Os 11 endpoints do simulador estao acessiveis em `/api/v1/simulator/*`
- Os 8 cenarios integrados estao disponiveis para execucao
- O teste de integracao 200/200 completa com 100% de sucesso
- Cenarios customizados podem ser criados e executados via API
- Chamadas ao BACEN sao substituidas por respostas simuladas
- Nenhuma conexao real com a RSFN e estabelecida
- O `GET /api/v1/simulator/status` retorna `"enabled": true, "status": "running"`
