# Telegram Auth Web Wizard

**Objetivo:** Permitir que o usuário autentique sua sessão MadelineProto diretamente pelo painel web (`admin/setup`), sem precisar de acesso ao terminal do servidor.

---

## Problema atual

Após salvar as credenciais (API ID, API Hash, Telefone), o usuário precisa que um administrador execute manualmente no servidor:

```bash
php artisan telegram:test-login --user=1
```

O terminal faz perguntas interativas (código OTP, senha 2FA) que não têm equivalente na interface web.

---

## Solução proposta: mini-wizard em 3 etapas

```
[Etapa 1] Salvar credenciais
     ↓
[Etapa 2] Solicitar código OTP → Telegram envia SMS/notificação no app
     ↓
[Etapa 3] Inserir código → sessão autenticada
     ↓ (se 2FA ativo)
[Etapa 3b] Inserir senha 2FA → sessão autenticada
```

---

## Métodos MadelineProto envolvidos

```php
// Iniciar autenticação (solicita envio do código)
$MadelineProto->phoneLogin('+5511999999999');

// Confirmar com o código recebido
$MadelineProto->completePhoneLogin('12345');

// Se 2FA estiver ativo (retorna exception específica na etapa anterior)
$MadelineProto->complete2faLogin('minha_senha_2fa');
```

---

## Arquivos a criar / modificar

### 1. `SetupController.php` — novos métodos

```php
/**
 * POST admin/setup/telegram/request-code
 * Inicializa sessão MadelineProto e solicita envio do código OTP ao telefone.
 */
public function requestTelegramCode(Request $request): RedirectResponse
{
    $user   = Auth::user();
    $config = $user->telegramConfig;

    if (!$config?->isConfigured()) {
        return back()->with('error', 'Salve as credenciais antes de solicitar o código.');
    }

    try {
        $MadelineProto = new \danog\MadelineProto\API($config->resolvedSessionPath(), [
            'app_info' => [
                'api_id'   => $config->api_id,
                'api_hash' => $config->api_hash,
            ],
        ]);

        $MadelineProto->phoneLogin($config->phone);

        // Armazena estado na sessão PHP para a etapa seguinte
        session(['telegram_auth_step' => 'awaiting_code', 'telegram_auth_user' => $user->id]);

        return redirect()->route('admin.setup.index')
            ->with('telegram_step', 'code')
            ->with('success', 'Código enviado para ' . $config->phone . '. Verifique o app do Telegram ou SMS.');

    } catch (\Throwable $e) {
        return back()->with('error', 'Erro ao solicitar código: ' . $e->getMessage());
    }
}

/**
 * POST admin/setup/telegram/confirm-code
 * Confirma o código OTP recebido e finaliza a autenticação.
 */
public function confirmTelegramCode(Request $request): RedirectResponse
{
    $request->validate(['code' => 'required|string|min:4|max:10']);

    $user   = Auth::user();
    $config = $user->telegramConfig;

    try {
        $MadelineProto = new \danog\MadelineProto\API($config->resolvedSessionPath(), [
            'app_info' => [
                'api_id'   => $config->api_id,
                'api_hash' => $config->api_hash,
            ],
        ]);

        $result = $MadelineProto->completePhoneLogin($request->code);

        // Sessão autenticada com sucesso
        $config->update(['authenticated_at' => now()]);
        session()->forget(['telegram_auth_step', 'telegram_auth_user']);

        return redirect()->route('admin.setup.index')
            ->with('success', 'Telegram autenticado com sucesso!');

    } catch (\danog\MadelineProto\RPCErrorException $e) {

        // 2FA necessária
        if (str_contains($e->getMessage(), 'SESSION_PASSWORD_NEEDED')) {
            session(['telegram_auth_step' => 'awaiting_2fa']);
            return redirect()->route('admin.setup.index')
                ->with('telegram_step', '2fa')
                ->with('info', 'Sua conta tem verificação em duas etapas. Insira sua senha do Telegram.');
        }

        return back()->with('error', 'Código inválido: ' . $e->getMessage());

    } catch (\Throwable $e) {
        return back()->with('error', 'Erro: ' . $e->getMessage());
    }
}

/**
 * POST admin/setup/telegram/confirm-2fa
 * Confirma a senha de verificação em duas etapas.
 */
public function confirmTelegram2fa(Request $request): RedirectResponse
{
    $request->validate(['password_2fa' => 'required|string']);

    $user   = Auth::user();
    $config = $user->telegramConfig;

    try {
        $MadelineProto = new \danog\MadelineProto\API($config->resolvedSessionPath(), [
            'app_info' => [
                'api_id'   => $config->api_id,
                'api_hash' => $config->api_hash,
            ],
        ]);

        $MadelineProto->complete2faLogin($request->password_2fa);

        $config->update(['authenticated_at' => now()]);
        session()->forget(['telegram_auth_step', 'telegram_auth_user']);

        return redirect()->route('admin.setup.index')
            ->with('success', 'Telegram autenticado com sucesso (2FA)!');

    } catch (\Throwable $e) {
        return back()->with('error', 'Senha 2FA incorreta: ' . $e->getMessage());
    }
}
```

---

### 2. `routes/web.php` — novas rotas

```php
Route::post('setup/telegram/request-code',  [SetupController::class, 'requestTelegramCode'])->name('admin.setup.requestTelegramCode');
Route::post('setup/telegram/confirm-code',   [SetupController::class, 'confirmTelegramCode'])->name('admin.setup.confirmTelegramCode');
Route::post('setup/telegram/confirm-2fa',    [SetupController::class, 'confirmTelegram2fa'])->name('admin.setup.confirmTelegram2fa');
```

---

### 3. `admin/setup/index.blade.php` — UI do wizard

Substituir o alerta estático atual da seção Telegram por um bloco dinâmico:

```blade
@php
    $tgStep = session('telegram_step') ?? (session('telegram_auth_step') === 'awaiting_code' ? 'code' : (session('telegram_auth_step') === 'awaiting_2fa' ? '2fa' : null));
@endphp

{{-- Autenticado --}}
@if($telegramConfig->isAuthenticated())
    <div class="alert alert-success py-2">
        <i class="bi bi-check-circle me-2"></i><strong>Autenticado</strong> — sessão ativa
    </div>

{{-- Aguardando código OTP --}}
@elseif($tgStep === 'code')
    <div class="alert alert-info">
        <p class="fw-semibold mb-2"><i class="bi bi-phone me-1"></i>Código enviado para {{ $telegramConfig->phone }}</p>
        <form action="{{ route('admin.setup.confirmTelegramCode') }}" method="POST" class="d-flex gap-2">
            @csrf
            <input type="text" name="code" class="form-control" placeholder="12345" maxlength="10" autofocus required>
            <button type="submit" class="btn btn-primary text-nowrap">Confirmar código</button>
        </form>
    </div>

{{-- Aguardando senha 2FA --}}
@elseif($tgStep === '2fa')
    <div class="alert alert-warning">
        <p class="fw-semibold mb-2"><i class="bi bi-shield-lock me-1"></i>Verificação em duas etapas</p>
        <form action="{{ route('admin.setup.confirmTelegram2fa') }}" method="POST" class="d-flex gap-2">
            @csrf
            <input type="password" name="password_2fa" class="form-control" placeholder="Senha do Telegram" autofocus required>
            <button type="submit" class="btn btn-warning text-nowrap">Confirmar senha</button>
        </form>
    </div>

{{-- Configurado mas não autenticado → botão para iniciar --}}
@elseif($telegramConfig->isConfigured())
    <div class="alert alert-warning py-2 d-flex align-items-center justify-content-between">
        <span><i class="bi bi-clock me-2"></i><strong>Configurado, aguardando login</strong></span>
        <form action="{{ route('admin.setup.requestTelegramCode') }}" method="POST" class="ms-3">
            @csrf
            <button type="submit" class="btn btn-sm btn-primary">
                <i class="bi bi-send me-1"></i>Enviar código para meu Telegram
            </button>
        </form>
    </div>

{{-- Não configurado --}}
@else
    <div class="alert alert-secondary py-2">
        <i class="bi bi-exclamation-circle me-2"></i>
        Não configurado. Obtenha suas credenciais em
        <a href="https://my.telegram.org/auth" target="_blank">my.telegram.org</a>
        → API development tools.
    </div>
@endif
```

---

## Desafios e cuidados

### Estado entre requests
O MadelineProto precisa da mesma instância de sessão entre a etapa "solicitar código" e "confirmar código". Usar `session()` do Laravel para guardar o estado (`awaiting_code`, `awaiting_2fa`) é suficiente — a sessão do arquivo MadelineProto já persiste em disco.

### Timeout do processo
O MadelineProto pode demorar alguns segundos para inicializar. Se o servidor tiver `max_execution_time` baixo, pode dar timeout. Recomendado:
```php
set_time_limit(120);
```
no início dos métodos do controller.

### Sessão PHP x Sessão MadelineProto
- **Sessão Laravel/PHP** — controla em qual etapa do wizard o usuário está
- **Sessão MadelineProto** — o arquivo `.madeline` em disco que guarda as credenciais do Telegram

São dois conceitos distintos.

### Lock de sessão
O `MadelineSessionLock` já existente deve ser chamado antes de instanciar o MadelineProto nos métodos do wizard, para evitar conflito com o scheduler:

```php
$lock = \App\Support\MadelineSessionLock::acquire($user->id);
// ... usar MadelineProto ...
\App\Support\MadelineSessionLock::release($user->id);
```

### 2FA opcional
Nem todo usuário tem 2FA. O fluxo só chega na etapa de senha 2FA se o `completePhoneLogin` lançar `SESSION_PASSWORD_NEEDED`.

---

## Ordem de implementação sugerida

1. Adicionar as 3 rotas em `routes/web.php`
2. Criar os 3 métodos no `SetupController`
3. Atualizar o bloco de status do Telegram na view `admin/setup/index.blade.php`
4. Testar com uma conta real de teste antes de liberar para usuários

---

## Referência

- [MadelineProto — Login flow](https://docs.madelineproto.xyz/docs/LOGIN.html)
- [danog/MadelineProto — phpLogin](https://github.com/danog/MadelineProto)
