<?php
declare(strict_types=1);

function cfg(?string $key = null, mixed $default = null): mixed {
    global $config;
    if ($key === null) return $config;
    $value = $config;
    foreach (explode('.', $key) as $part) {
        if (!is_array($value) || !array_key_exists($part, $value)) return $default;
        $value = $value[$part];
    }
    return $value;
}

function db(): ?PDO {
    static $pdo = false;
    if ($pdo instanceof PDO) return $pdo;
    if ($pdo === null) return null;
    try {
        $db = cfg('db');
        if (!$db || str_contains((string)$db['password'], 'REEMPLAZAR')) { $pdo = null; return null; }
        $dsn = sprintf('mysql:host=%s;dbname=%s;charset=%s', $db['host'], $db['name'], $db['charset'] ?? 'utf8mb4');
        $pdo = new PDO($dsn, $db['user'], $db['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES => false,
        ]);
        return $pdo;
    } catch (Throwable $e) {
        error_log('[Sonocamara DB] ' . $e->getMessage());
        $pdo = null;
        return null;
    }
}

function e(?string $value): string { return htmlspecialchars((string)$value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
function base_url(string $path = ''): string { return rtrim((string)cfg('base_url','/nueva'), '/') . ($path ? '/' . ltrim($path,'/') : ''); }
function admin_url(string $path = ''): string { return rtrim((string)cfg('admin_url','/administrar'), '/') . ($path ? '/' . ltrim($path,'/') : ''); }
function redirect(string $url): never { header('Location: ' . $url); exit; }
function random_id(int $bytes=16): string { return bin2hex(random_bytes($bytes)); }
function csrf_token(): string { if (empty($_SESSION['csrf'])) $_SESSION['csrf'] = bin2hex(random_bytes(32)); return $_SESSION['csrf']; }
function verify_csrf(?string $token): void { if (!$token || !hash_equals($_SESSION['csrf'] ?? '', $token)) throw new RuntimeException('La sesión expiró. Recarga la página e inténtalo nuevamente.'); }
function client_ip(): string { return substr($_SERVER['REMOTE_ADDR'] ?? '0.0.0.0',0,45); }

function slugify(string $text): string {
    $text = trim($text);
    if (function_exists('transliterator_transliterate')) $text = transliterator_transliterate('Any-Latin; Latin-ASCII; Lower()', $text);
    else $text = strtolower((string)iconv('UTF-8','ASCII//TRANSLIT//IGNORE',$text));
    $text = preg_replace('/[^a-z0-9]+/', '-', $text) ?? '';
    return trim($text,'-') ?: 'recuerdo';
}
function public_name(string $name): string {
    $parts = preg_split('/\s+/', trim($name)) ?: [];
    if (!$parts) return 'Anónimo';
    $first = array_shift($parts);
    if (!$parts) return $first;
    $last = end($parts);
    return $first . ' ' . mb_strtoupper(mb_substr((string)$last,0,1)) . '.';
}
function valid_video_url(?string $url): ?string {
    $url = trim((string)$url);
    if ($url === '') return null;
    if (!filter_var($url, FILTER_VALIDATE_URL)) throw new RuntimeException('El enlace de video no es válido.');
    $host = strtolower((string)parse_url($url, PHP_URL_HOST));
    $allowed = ['youtube.com','www.youtube.com','youtu.be','vimeo.com','www.vimeo.com'];
    if (!in_array($host,$allowed,true)) throw new RuntimeException('El enlace debe pertenecer a YouTube o Vimeo.');
    return $url;
}
function relative_date(?string $date): string {
    if (!$date) return '';
    $ts = strtotime($date); if (!$ts) return '';
    $diff = time()-$ts;
    if ($diff < 60) return 'Hace unos segundos';
    if ($diff < 3600) return 'Hace ' . floor($diff/60) . ' min';
    if ($diff < 86400) return 'Hace ' . floor($diff/3600) . ' h';
    $days=floor($diff/86400); if ($days<30) return 'Hace ' . $days . ($days===1?' día':' días');
    return date('d/m/Y',$ts);
}
function approved_memories(int $limit=50): array {
    $pdo=db(); if (!$pdo) return [];
    $st=$pdo->prepare("SELECT * FROM memories WHERE status='approved' ORDER BY approved_at DESC, id DESC LIMIT :lim");
    $st->bindValue(':lim',$limit,PDO::PARAM_INT); $st->execute(); return $st->fetchAll();
}
function memory_by_slug(string $slug): ?array {
    $pdo=db(); if (!$pdo) return null;
    $st=$pdo->prepare("SELECT * FROM memories WHERE slug=:slug AND status='approved' LIMIT 1"); $st->execute(['slug'=>$slug]); return $st->fetch() ?: null;
}
function demo_memories(): array {
    $texts=[
      'Tavo tenía una energía única, siempre dispuesto a ayudar y a compartir su pasión por la música y la radio. Un grande.',
      'Lo recuerdo en Sonocámara, cada domingo era cita obligada. Gracias por tantos momentos inolvidables.',
      'Su curiosidad no tenía límites. Siempre innovando y conectando personas. Un visionario.',
      'Gracias por tu amistad, por tu humor y por enseñarnos a disfrutar la vida. Te extrañaremos Tavo.'
    ];
    $names=['Carlos M.','María Elena','Ricardo R.','Ana Lucía']; $out=[];
    foreach($names as $i=>$name) $out[]=[
      'slug'=>'demo-recuerdo-'.($i+1),'public_name'=>$name,'message'=>$texts[$i],
      'avatar_path'=>base_url('assets/images/demo/avatar_'.sprintf('%02d',$i+1).'.webp'),
      'image_thumb_path'=>base_url('assets/images/demo/memory_'.sprintf('%02d',$i+1).'.webp'),
      'image_path'=>base_url('assets/images/demo/memory_'.sprintf('%02d',$i+1).'.webp'),
      'video_url'=>null,'approved_at'=>date('Y-m-d H:i:s',strtotime('-'.($i+1).' days')),'is_demo'=>true
    ];
    return $out;
}
function memory_cards(): array { $m=approved_memories(40); if (!$m && cfg('show_demo_memories',false)) return demo_memories(); return $m; }

function require_admin(): void { if (empty($_SESSION['admin_user_id'])) redirect(admin_url('?route=login')); }
function admin_exists(): bool { $pdo=db(); if(!$pdo) return false; return (bool)$pdo->query('SELECT COUNT(*) FROM admin_users')->fetchColumn(); }
function is_admin(): bool { return !empty($_SESSION['admin_user_id']); }
function flash(string $type, string $message): void { $_SESSION['flash'][]=['type'=>$type,'message'=>$message]; }
function flashes(): array { $f=$_SESSION['flash'] ?? []; unset($_SESSION['flash']); return $f; }
