# Task 011 — `App.php` (Observatorio + GalaxiaAutoLoad + bootstrap)

**Depende de:** 004, 010
**Bloqueia:** 013

## Objetivo

Entry-point do sinal que:
1. Faz **bootstrap de canais default** (`LogCanal`) e configurações default.
2. Implementa `Observatorio()` e `GalaxiaAutoLoad()` no padrão Galaxia.
3. Expõe dispatcher textual para uso direto via roteador (AJAX/forms).

## Deliverable

`App.php`:

```php
namespace GalaxiaMissoes\Mensageria\sinais\Otp;

use GalaxiaMissoes\Mensageria\sinais\Otp\Canais\OtpCanalRegistry;
use GalaxiaMissoes\Mensageria\sinais\Otp\Canais\LogCanal;
use GalaxiaMissoes\Mensageria\sinais\Otp\Satelites\OtpSatelite;

class App {
    public $galaxiaRoute;
    public $response = [];
    private $bootstrapDone = false;

    public function __construct(object $galaxia, ?array $data = []) {
        $this->galaxiaRoute = $galaxia;
        $this->bootstrap();
    }

    private function bootstrap(): void {
        if ($this->bootstrapDone) return;
        if (!OtpCanalRegistry::temRegistro('log')) {
            OtpCanalRegistry::registrar('log', LogCanal::class);
        }
        // Hooks p/ providers reais: registrar via env / config externa
        // Ex.: if (getenv('TWILIO_ENABLED')) OtpCanalRegistry::registrar('sms', SmsTwilioCanal::class);
        $this->bootstrapDone = true;
    }

    // -------- Hooks Galaxia --------

    public function GalaxiaAutoload(?array $available = []) {
        return $this->Observatorio($available);
    }

    public function Observatorio(?array $available = []) {
        $rota = $available['rota'] ?? '';
        if ($rota === 'before') return [];

        $exe      = $available['exe'] ?? '';
        $satelite = $available['satelite'] ?? '';
        $data     = $available['response'] ?? [];

        // Pós-processamento mínimo: quando OtpSatelite retorna sucesso de validar/cancelar,
        // emitimos atualizarPagina() (consumidor pode sobrescrever no seu próprio Observatorio)
        if ($satelite === 'OtpSatelite' && in_array($exe, ['validar', 'cancelar'], true)
            && ($data['notification_class'] ?? '') === 'success'
        ) {
            $this->response = ['replaceDataTo' =>
                $this->galaxiaRoute->galaxiaResposta($data)->atualizarPagina()->feito()
            ];
            return $this;
        }
        return [];
    }

    // -------- Dispatcher textual (uso direto via roteador) --------

    public function start(?array $data = []) {
        $opcao = $data['opcao_otp'] ?? '';
        if (!$opcao) {
            $this->galaxiaRoute->setSemHeader(1);
            return $this;
        }
        $resp = (new OtpSatelite($this->galaxiaRoute, $opcao, $data))->response;
        $this->response = ['replaceDataTo' =>
            $this->galaxiaRoute->galaxiaResposta($resp)->feito()
        ];
        return $this;
    }
}
```

## Critério de aceite

- Bootstrap idempotente (chamável várias vezes sem efeitos colaterais).
- `Observatorio()` retorna `[]` quando não reconhece a chamada — não interfere em outros sinais.
- Lint OK.
