<?php
// ============================================================
//  includes/functions.php — Shared Utility Functions
//  Include after db.php. Safe to include multiple times.
// ============================================================
if (defined('FUNCTIONS_LOADED')) return;
define('FUNCTIONS_LOADED', true);

// ── String Helpers ────────────────────────────────────────────

function e(string $str): string {
    return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}

function slug(string $str): string {
    return strtolower(trim(preg_replace('/[^a-zA-Z0-9]+/', '-', $str), '-'));
}

function truncate(string $str, int $len = 60, string $suffix = '…'): string {
    return mb_strlen($str) > $len ? mb_substr($str, 0, $len) . $suffix : $str;
}

function time_ago(string $datetime): string {
    $diff = time() - strtotime($datetime);
    if ($diff < 60)     return 'just now';
    if ($diff < 3600)   return floor($diff/60)  . ' min ago';
    if ($diff < 86400)  return floor($diff/3600) . ' hr ago';
    if ($diff < 604800) return floor($diff/86400) . ' day' . ($diff < 172800 ? '' : 's') . ' ago';
    return date('d M Y', strtotime($datetime));
}

function format_date(string $datetime, string $format = 'd M Y'): string {
    return $datetime ? date($format, strtotime($datetime)) : '—';
}

// ── Security Helpers ──────────────────────────────────────────

function csrf_token(): string {
    if (session_status() === PHP_SESSION_NONE) session_start();
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

function csrf_verify(string $token): bool {
    if (session_status() === PHP_SESSION_NONE) session_start();
    return hash_equals($_SESSION['csrf_token'] ?? '', $token);
}

function csrf_field(): string {
    return '<input type="hidden" name="csrf_token" value="' . e(csrf_token()) . '"/>';
}

function sanitize_username(string $val): string {
    return preg_replace('/[^a-zA-Z0-9_]/', '', trim($val));
}

function is_strong_password(string $pw): bool {
    return strlen($pw) >= 8
        && preg_match('/[A-Z]/', $pw)
        && preg_match('/[0-9]/', $pw);
}

// ── File Upload Helper ────────────────────────────────────────

function handle_avatar_upload(array $file, int $entity_id, string $prefix = 'user'): array {
    $allowed  = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
    $dest_dir = dirname(__DIR__) . '/assets/images/avatars/';

    if ($file['error'] !== UPLOAD_ERR_OK) {
        return ['ok' => false, 'error' => 'Upload error code: ' . $file['error']];
    }
    if (!in_array(mime_content_type($file['tmp_name']), $allowed)) {
        return ['ok' => false, 'error' => 'Only JPG, PNG, WebP, GIF allowed.'];
    }
    if ($file['size'] > MAX_UPLOAD) {
        return ['ok' => false, 'error' => 'Image must be under 2MB.'];
    }
    if (!getimagesize($file['tmp_name'])) {
        return ['ok' => false, 'error' => 'Invalid image file.'];
    }
    if (!is_dir($dest_dir)) {
        mkdir($dest_dir, 0775, true);
    }

    $ext      = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
    $filename = $prefix . '_' . $entity_id . '_' . time() . '.' . $ext;
    $dest     = $dest_dir . $filename;

    if (!move_uploaded_file($file['tmp_name'], $dest)) {
        return ['ok' => false, 'error' => 'Failed to save file. Check folder permissions on assets/images/avatars/'];
    }
    return ['ok' => true, 'filename' => $filename];
}

function delete_old_avatar(string $filename, string $default = 'default_avatar.png'): void {
    if ($filename && $filename !== $default) {
        $path = dirname(__DIR__) . '/assets/images/avatars/' . $filename;
        if (file_exists($path)) @unlink($path);
    }
}

// ── Status Badge HTML ─────────────────────────────────────────

function status_badge(string $status): string {
    $map = [
        'active'      => ['ba',    'Active'],
        'inactive'    => ['bi',    'Inactive'],
        'pending'     => ['bp',    'Pending'],
        'banned'      => ['bb',    'Banned'],
        'confirmed'   => ['ba',    'Confirmed'],
        'in_progress' => ['bl',    'In Progress'],
        'completed'   => ['ba',    'Completed'],
        'cancelled'   => ['bb',    'Cancelled'],
        'dropped'     => ['bi',    'Dropped'],
    ];
    [$cls, $label] = $map[$status] ?? ['bi', ucfirst($status)];
    return '<span class="badge ' . $cls . '">' . $label . '</span>';
}

// ── Pagination Helper ─────────────────────────────────────────

function paginate(int $total, int $per_page, int $current_page, string $url_pattern = '?page='): array {
    $total_pages = max(1, (int)ceil($total / $per_page));
    $current     = max(1, min($current_page, $total_pages));
    $offset      = ($current - 1) * $per_page;
    return [
        'total'       => $total,
        'per_page'    => $per_page,
        'current'     => $current,
        'total_pages' => $total_pages,
        'offset'      => $offset,
        'url'         => $url_pattern,
        'has_prev'    => $current > 1,
        'has_next'    => $current < $total_pages,
        'from'        => $total > 0 ? $offset + 1 : 0,
        'to'          => min($offset + $per_page, $total),
    ];
}

// ── Redirect Helper ───────────────────────────────────────────

function redirect(string $url, string $flash_key = '', string $flash_msg = ''): never {
    if ($flash_key && $flash_msg) {
        if (session_status() === PHP_SESSION_NONE) session_start();
        $_SESSION['flash_' . $flash_key] = $flash_msg;
    }
    header('Location: ' . $url);
    exit;
}