<?php
$config = require __DIR__ . '/config.php';
require_once __DIR__ . '/helpers.php';

date_default_timezone_set($config['timezone']);

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

function db() {
    static $pdo;
    if ($pdo instanceof PDO) return $pdo;

    if (!extension_loaded('pdo_sqlite')) {
        http_response_code(500);
        exit('<h1>Extensão SQLite não habilitada</h1><p>Ative <strong>pdo_sqlite</strong> no Seletor de PHP do cPanel e recarregue esta página.</p>');
    }

    $path = config('db_path');
    $dir = dirname($path);
    if (!is_dir($dir)) mkdir($dir, 0755, true);
    $pdo = new PDO('sqlite:' . $path);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    // Evita HTTP 500 transitório logo após login, exclusões e outras ações.
    // O timeout precisa ser configurado ANTES de qualquer PRAGMA que possa disputar lock.
    if (defined('PDO::ATTR_TIMEOUT')) {
        try { $pdo->setAttribute(PDO::ATTR_TIMEOUT, 15); } catch (Throwable $ignored) {}
    }
    $pdo->exec('PRAGMA busy_timeout = 15000');
    $pdo->exec('PRAGMA foreign_keys = ON');

    // Alterar journal_mode enquanto outro request ainda encerra pode lançar
    // "database is locked". Se o banco já estiver em WAL, não há motivo para
    // tentar trocar o modo em toda requisição.
    try {
        $currentJournal = strtolower((string)$pdo->query('PRAGMA journal_mode')->fetchColumn());
        if ($currentJournal !== 'wal') {
            for ($journalAttempt = 0; $journalAttempt < 4; $journalAttempt++) {
                try {
                    $pdo->exec('PRAGMA journal_mode = WAL');
                    break;
                } catch (PDOException $journalError) {
                    $message = strtolower($journalError->getMessage());
                    if ($journalAttempt >= 3 || (strpos($message, 'locked') === false && strpos($message, 'busy') === false)) throw $journalError;
                    usleep(150000 * ($journalAttempt + 1));
                }
            }
        }
    } catch (PDOException $journalError) {
        $message = strtolower($journalError->getMessage());
        // Um lock momentâneo no journal não deve derrubar o site. A conexão
        // continua válida e o próximo request poderá confirmar o WAL.
        if (strpos($message, 'locked') === false && strpos($message, 'busy') === false) throw $journalError;
    }
    try { $pdo->exec('PRAGMA synchronous = NORMAL'); } catch (Throwable $ignored) {}

    require_once __DIR__ . '/schema.php';

    // V2.8.42 — migrações não devem rodar a cada pageview.
    // Isso evita concorrência entre login/dashboard/actions no SQLite e impede
    // que rotinas de seed sejam reexecutadas depois que o admin apaga dados demo.
    $schemaVersion = '2.9.22';
    $pdo->exec('CREATE TABLE IF NOT EXISTS settings (key_name TEXT PRIMARY KEY,value TEXT,updated_at TEXT)');
    $versionStmt = $pdo->prepare('SELECT value FROM settings WHERE key_name=? LIMIT 1');
    $versionStmt->execute(['schema_version']);
    $installedSchemaVersion = (string)($versionStmt->fetchColumn() ?: '');

    if ($installedSchemaVersion !== $schemaVersion) {
        $lockPath = $dir . '/.schema_migration.lock';
        $lockHandle = @fopen($lockPath, 'c+');
        if ($lockHandle) @flock($lockHandle, LOCK_EX);
        try {
            // Outro request pode ter terminado a migração enquanto aguardávamos o lock.
            $versionStmt->execute(['schema_version']);
            $installedSchemaVersion = (string)($versionStmt->fetchColumn() ?: '');
            if ($installedSchemaVersion !== $schemaVersion) {
                for ($migrationAttempt = 0; ; $migrationAttempt++) {
                    try {
                        migrate_database($pdo);
                        break;
                    } catch (PDOException $migrationError) {
                        $message = strtolower($migrationError->getMessage());
                        if ($migrationAttempt >= 4 || (strpos($message, 'locked') === false && strpos($message, 'busy') === false)) throw $migrationError;
                        usleep(200000 * ($migrationAttempt + 1));
                    }
                }
                $markVersion = $pdo->prepare('INSERT INTO settings(key_name,value,updated_at) VALUES(?,?,?) ON CONFLICT(key_name) DO UPDATE SET value=excluded.value,updated_at=excluded.updated_at');
                $markVersion->execute(['schema_version',$schemaVersion,date('Y-m-d H:i:s')]);
            }
        } finally {
            if ($lockHandle) {
                @flock($lockHandle, LOCK_UN);
                @fclose($lockHandle);
            }
        }
    }
    return $pdo;
}

db();
require_once __DIR__ . '/auth.php';
restore_remembered_login();

// V2.8.45 — materializa mensalidades recorrentes vencidas/que vencem hoje.
// Falha momentânea de lock não pode derrubar login ou dashboard.
try { process_recurring_subscription_charges(); } catch (Throwable $recurringError) { @error_log('Recurring billing: '.$recurringError->getMessage()); }
try { process_clinic_reminders(); } catch (Throwable $clinicReminderError) { @error_log('Clinic reminders: '.$clinicReminderError->getMessage()); }
try { process_clinic_medication_reminders(); } catch (Throwable $medReminderError) { @error_log('Medication reminders: '.$medReminderError->getMessage()); }
try { process_petcare_reminders(); } catch (Throwable $petReminderError) { @error_log('Pet reminders: '.$petReminderError->getMessage()); }
try { process_gas_consumption_notifications(); } catch (Throwable $gasReminderError) { @error_log('Gas reminders: '.$gasReminderError->getMessage()); }

$currentScript = basename(isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : '');
$maintenanceAllowed = ['login.php','logout.php','install.php','terms.php','register.php','complete_registration.php'];
if (setting('maintenance_mode','0') === '1' && !in_array($currentScript, $maintenanceAllowed, true)) {
    $maintenanceUser = current_user();
    if (!$maintenanceUser || !in_array(($maintenanceUser['role'] ?? ''), ['super_admin','sub_admin'], true)) {
        http_response_code(503);
        header('Retry-After: 3600');
        exit('<!doctype html><html lang="pt-BR"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>'.e(platform_name()).' em manutenção</title><body style="margin:0;background:#10111d;color:#fff;font-family:system-ui;display:grid;place-items:center;min-height:100vh;text-align:center;padding:24px"><div><div style="font-size:52px">✦</div><h1>Estamos fazendo melhorias</h1><p style="color:#a8adc5">A '.e(platform_name()).' voltará em breve. Obrigado pela compreensão.</p></div></body></html>');
    }
}
