<?php
declare(strict_types=1);

/**
 * Sessão, login e CSRF do painel. Todo arquivo de /admin começa com
 * `require __DIR__ . '/auth.php';` e depois chama admin_require_login().
 */

require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../partner_api.php';
require_once __DIR__ . '/../lead_store.php';

if (session_status() !== PHP_SESSION_ACTIVE) {
    session_name('zm_admin');
    session_set_cookie_params([
        'lifetime' => 0,
        'path' => '/',
        'secure' => !empty($_SERVER['HTTPS']),
        'httponly' => true,
        'samesite' => 'Lax',
    ]);
    session_start();
}

function admin_is_logged_in(): bool
{
    if (empty($_SESSION['admin_ok'])) {
        return false;
    }
    // Sessão expira por tempo absoluto — evita um painel aberto para sempre
    // numa máquina compartilhada.
    if ((int) ($_SESSION['admin_since'] ?? 0) + ADMIN_SESSION_TTL < time()) {
        admin_logout();
        return false;
    }
    return true;
}

function admin_login(string $password): bool
{
    // Throttle simples por sessão: 5 tentativas, depois 60s de espera.
    $tries = (int) ($_SESSION['admin_tries'] ?? 0);
    $lockedUntil = (int) ($_SESSION['admin_locked_until'] ?? 0);
    if ($lockedUntil > time()) {
        return false;
    }

    if (password_verify($password, ADMIN_PASSWORD_HASH)) {
        session_regenerate_id(true);
        $_SESSION['admin_ok'] = true;
        $_SESSION['admin_since'] = time();
        unset($_SESSION['admin_tries'], $_SESSION['admin_locked_until']);
        return true;
    }

    $tries++;
    $_SESSION['admin_tries'] = $tries;
    if ($tries >= 5) {
        $_SESSION['admin_locked_until'] = time() + 60;
        $_SESSION['admin_tries'] = 0;
    }
    return false;
}

function admin_lock_seconds_left(): int
{
    return max(0, (int) ($_SESSION['admin_locked_until'] ?? 0) - time());
}

function admin_logout(): void
{
    $_SESSION = [];
    if (ini_get('session.use_cookies')) {
        $p = session_get_cookie_params();
        setcookie(session_name(), '', time() - 42000, $p['path'], $p['domain'], (bool) $p['secure'], (bool) $p['httponly']);
    }
    session_destroy();
}

function admin_require_login(): void
{
    if (!admin_is_logged_in()) {
        header('Location: login.php', true, 302);
        exit;
    }
}

function admin_csrf_token(): string
{
    if (empty($_SESSION['admin_csrf'])) {
        $_SESSION['admin_csrf'] = bin2hex(random_bytes(32));
    }
    return (string) $_SESSION['admin_csrf'];
}

function admin_csrf_check(?string $token): bool
{
    return is_string($token) && $token !== '' && hash_equals((string) ($_SESSION['admin_csrf'] ?? ''), $token);
}

function h(?string $s): string
{
    return htmlspecialchars((string) $s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

/**
 * Roda a sincronização com o CRM para o período informado.
 *
 * @return array{ok:bool,message:string,stats:array{matched:int,updated:int,inserted:int,ftd:int}}
 */
function admin_run_sync(string $from, string $to): array
{
    $empty = ['matched' => 0, 'updated' => 0, 'inserted' => 0, 'ftd' => 0];

    $res = partner_external_leads($from, $to);
    if (!$res['ok']) {
        return ['ok' => false, 'message' => 'Falha ao consultar o CRM: ' . ($res['error'] ?? 'erro desconhecido'), 'stats' => $empty];
    }

    $data = $res['body']['data'] ?? [];
    if (!is_array($data)) {
        return ['ok' => false, 'message' => 'O CRM respondeu sem a lista de leads.', 'stats' => $empty];
    }

    $stats = store_sync_remote($data);
    return [
        'ok' => true,
        'message' => sprintf(
            '%d leads recebidos do CRM · %d atualizados · %d novos · %d com FTD.',
            count($data),
            $stats['updated'],
            $stats['inserted'],
            $stats['ftd']
        ),
        'stats' => $stats,
    ];
}
