<?php
define('DB_HOST', 'localhost');
define('DB_NAME', 'platafo1_msvclientes');
define('DB_USER', 'platafo1_msvclientes');
define('DB_PASS', '9vYz5cK302hLXsL&nxUl');
define('JWT_SECRET', 'MSVpanel_2026_K8xmPq2wL9vRt4jHs7nBcYeZu'); // Cambiar en producción
define('ADMIN_USER', 'admin');
define('ADMIN_PASS', 'Admin2026!'); // Cambiar después de instalación
define('ADMIN_SECRET', 'MSVadmin_2026_Xp9qRt3mKw7vLs2nBcYeZu'); // Secret separado para JWT admin
define('BASE_URL', 'https://msvportal.plataformamultimedia.com/panel-negocios/');
define('UPLOAD_PATH', __DIR__ . '/../uploads/');
define('UPLOAD_URL', BASE_URL . 'uploads/');
define('MAX_FOTOS', 21);
define('MAX_IMG_WIDTH', 1200);
define('MAX_FILE_SIZE', 3 * 1024 * 1024); // 3MB

function getDB() {
    static $pdo = null;
    if ($pdo === null) {
        $pdo = new PDO(
            'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=utf8mb4',
            DB_USER,
            DB_PASS,
            [
                PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            ]
        );
    }
    return $pdo;
}

function jsonResponse($data, $statusCode = 200) {
    http_response_code($statusCode);
    header('Content-Type: application/json; charset=utf-8');
    header('Cache-Control: no-store, no-cache, must-revalidate');
    header('Pragma: no-cache');
    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

function getJsonInput() {
    return json_decode(file_get_contents('php://input'), true) ?? [];
}

function getClientIP() {
    foreach (['HTTP_CF_CONNECTING_IP','HTTP_X_FORWARDED_FOR','HTTP_X_REAL_IP','REMOTE_ADDR'] as $k) {
        if (!empty($_SERVER[$k])) {
            return trim(explode(',', $_SERVER[$k])[0]);
        }
    }
    return '0.0.0.0';
}

function verificarRateLimit($db, $endpoint = 'admin') {
    $ip         = getClientIP();
    $bloqueoMin = 15;

    // Todo el cálculo de tiempo se hace en MySQL para evitar problemas de zona horaria
    $stmt = $db->prepare(
        'SELECT intentos, bloqueado,
                TIMESTAMPDIFF(MINUTE, ultimo, NOW()) AS minutos_transcurridos
         FROM login_intentos WHERE ip = ? AND endpoint = ?'
    );
    $stmt->execute([$ip, $endpoint]);
    $row = $stmt->fetch();

    if (!$row) return;

    $minutos = (int)$row['minutos_transcurridos'];

    // Expiró el bloqueo — limpiar
    if ($minutos >= $bloqueoMin) {
        $db->prepare('DELETE FROM login_intentos WHERE ip = ? AND endpoint = ?')
           ->execute([$ip, $endpoint]);
        return;
    }

    // Bloqueado y dentro del período
    if ($row['bloqueado']) {
        $restantes = $bloqueoMin - $minutos;
        jsonResponse(['error' => "Demasiados intentos fallidos. Intenta de nuevo en {$restantes} minuto(s)."], 429);
    }
}

function registrarIntentoFallido($db, $endpoint = 'admin') {
    $ip          = getClientIP();
    $maxIntentos = 5;

    $stmt = $db->prepare(
        'SELECT id, intentos FROM login_intentos WHERE ip = ? AND endpoint = ?'
    );
    $stmt->execute([$ip, $endpoint]);
    $row = $stmt->fetch();

    if ($row) {
        $nuevos    = $row['intentos'] + 1;
        $bloqueado = $nuevos >= $maxIntentos ? 1 : 0;
        $db->prepare(
            'UPDATE login_intentos SET intentos=?, bloqueado=?, ultimo=NOW() WHERE id=?'
        )->execute([$nuevos, $bloqueado, $row['id']]);
    } else {
        $db->prepare(
            'INSERT INTO login_intentos (ip, endpoint, intentos, ultimo) VALUES (?, ?, 1, NOW())'
        )->execute([$ip, $endpoint]);
    }
}

function limpiarIntentos($db, $endpoint = 'admin') {
    $ip = getClientIP();
    $db->prepare('DELETE FROM login_intentos WHERE ip = ? AND endpoint = ?')
       ->execute([$ip, $endpoint]);
}

function base64UrlEncode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

function base64UrlDecode($data) {
    return base64_decode(strtr($data, '-_', '+/'));
}

function generateToken($negocio_id, $tipo_cuenta = 'negocio', $dias = 7) {
    $header  = base64UrlEncode(json_encode(['alg' => 'HS256', 'typ' => 'JWT']));
    $payload = base64UrlEncode(json_encode([
        'negocio_id'  => (int)$negocio_id,
        'tipo_cuenta' => $tipo_cuenta,
        'iat'         => time(),
        'exp'         => time() + ($dias * 24 * 3600),
    ]));
    $sig = base64UrlEncode(hash_hmac('sha256', "$header.$payload", JWT_SECRET, true));
    return "$header.$payload.$sig";
}

function comprimirYGuardarImagen($archivoTmp, $negocio_id, $carpeta) {
    $allowedMimes = ['image/jpeg', 'image/png'];
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mime  = finfo_file($finfo, $archivoTmp);
    finfo_close($finfo);

    if (!in_array($mime, $allowedMimes)) {
        return null;
    }

    $img = ($mime === 'image/jpeg')
        ? imagecreatefromjpeg($archivoTmp)
        : imagecreatefrompng($archivoTmp);

    if (!$img) return null;

    $origW = imagesx($img);
    $origH = imagesy($img);

    if ($origW > MAX_IMG_WIDTH) {
        $newW    = MAX_IMG_WIDTH;
        $newH    = (int)round($origH * MAX_IMG_WIDTH / $origW);
        $resized = imagecreatetruecolor($newW, $newH);
        imagealphablending($resized, false);
        imagesavealpha($resized, true);
        imagecopyresampled($resized, $img, 0, 0, 0, 0, $newW, $newH, $origW, $origH);
        imagedestroy($img);
        $img = $resized;
    }

    $dir = UPLOAD_PATH . $carpeta . '/';
    if (!is_dir($dir)) {
        mkdir($dir, 0755, true);
    }

    $filename = $negocio_id . '_' . time() . '_' . rand(1000, 9999) . '.webp';
    $filepath = $dir . $filename;

    imagewebp($img, $filepath, 80);
    imagedestroy($img);

    return UPLOAD_URL . $carpeta . '/' . $filename;
}

function eliminarArchivoUpload($url) {
    if (!$url) return;
    $path = str_replace(UPLOAD_URL, UPLOAD_PATH, $url);
    if (file_exists($path)) {
        unlink($path);
    }
}
