<?php
/**
 * Tom's Java Jive - Helper Functions
 */

require_once __DIR__ . '/../config/config.php';
require_once __DIR__ . '/db.php';

if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

/**
 * Generate a unique ID with prefix
 */
function generateId($prefix = '') {
    return $prefix . bin2hex(random_bytes(6));
}

/**
 * Generate order number
 */
function generateOrderNumber() {
    return 'JJ' . strtoupper(bin2hex(random_bytes(4)));
}

/**
 * Hash password using bcrypt
 */
function hashPassword($password) {
    return password_hash($password, PASSWORD_BCRYPT, ['cost' => HASH_COST]);
}

/**
 * Verify password
 */
function verifyPassword($password, $hash) {
    return password_verify($password, $hash);
}

/**
 * Sanitize input
 */
function sanitize($input) {
    if (is_array($input)) {
        return array_map('sanitize', $input);
    }
    return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8');
}

/**
 * Format currency
 */
function formatCurrency($amount) {
    return TJJ_CURRENCY_SYMBOL . number_format((float)$amount, 2);
}

/**
 * Format date
 */
function formatDate($date, $format = 'M j, Y') {
    return date($format, strtotime($date));
}

/**
 * Format datetime
 */
function formatDateTime($date, $format = 'M j, Y g:i A') {
    return date($format, strtotime($date));
}

/**
 * JSON response helper
 */
function jsonResponse($data, $statusCode = 200) {
    http_response_code($statusCode);
    header('Content-Type: application/json');
    echo json_encode($data);
    exit;
}

/**
 * Redirect helper
 */
function redirect($url) {
    header("Location: $url");
    exit;
}

/**
 * Get current URL
 */
function currentUrl() {
    $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
    return $protocol . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}

/**
 * Check if request is AJAX
 */
function isAjax() {
    return !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && 
           strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
}

/**
 * Get client IP address
 */
function getClientIp() {
    $ip = $_SERVER['REMOTE_ADDR'];
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
    } elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    }
    return trim($ip);
}

/**
 * Generate CSRF token
 */
function generateCsrfToken() {
    if (empty($_SESSION[CSRF_TOKEN_NAME])) {
        $_SESSION[CSRF_TOKEN_NAME] = bin2hex(random_bytes(32));
    }
    return $_SESSION[CSRF_TOKEN_NAME];
}

/**
 * Verify CSRF token
 */
function verifyCsrfToken($token) {
    return isset($_SESSION[CSRF_TOKEN_NAME]) && hash_equals($_SESSION[CSRF_TOKEN_NAME], $token);
}

/**
 * Get setting value
 */
function getSetting($key, $default = null) {
    $result = db()->fetch(
        "SELECT setting_value FROM settings WHERE setting_key = :key",
        ['key' => $key]
    );
    if ($result) {
        return json_decode($result['setting_value'], true) ?? $result['setting_value'];
    }
    return $default;
}

/**
 * Update setting value
 */
function setSetting($key, $value) {
    $jsonValue = json_encode($value);
    $existing = db()->fetch(
        "SELECT id FROM settings WHERE setting_key = :key",
        ['key' => $key]
    );
    
    if ($existing) {
        db()->update('settings', ['setting_value' => $jsonValue], 'setting_key = :key', ['key' => $key]);
    } else {
        db()->insert('settings', ['setting_key' => $key, 'setting_value' => $jsonValue]);
    }
}

/**
 * Flash message helpers
 */
function setFlash($type, $message) {
    $_SESSION['flash'][$type] = $message;
}

function getFlash($type) {
    if (isset($_SESSION['flash'][$type])) {
        $message = $_SESSION['flash'][$type];
        unset($_SESSION['flash'][$type]);
        return $message;
    }
    return null;
}

function hasFlash($type) {
    return isset($_SESSION['flash'][$type]);
}

/**
 * Pagination helper
 */
function paginate($totalItems, $currentPage, $perPage = ITEMS_PER_PAGE) {
    $totalPages = ceil($totalItems / $perPage);
    $currentPage = max(1, min($currentPage, $totalPages));
    $offset = ($currentPage - 1) * $perPage;
    
    return [
        'total_items' => $totalItems,
        'total_pages' => $totalPages,
        'current_page' => $currentPage,
        'per_page' => $perPage,
        'offset' => $offset,
        'has_prev' => $currentPage > 1,
        'has_next' => $currentPage < $totalPages
    ];
}

/**
 * Render pagination HTML
 */
function renderPagination($pagination, $baseUrl) {
    if ($pagination['total_pages'] <= 1) return '';

    $cur   = $pagination['current_page'];
    $total = $pagination['total_pages'];
    // baseUrl may already contain query params; append page with &
    $sep   = strpos($baseUrl, '?') !== false ? '&' : '?';
    $url   = fn($p) => $baseUrl . $sep . 'page=' . $p;

    $btn = fn($href, $label, $active = false, $disabled = false) =>
        '<a href="' . ($disabled ? '#' : htmlspecialchars($href)) . '" style="'
        . 'display:inline-flex;align-items:center;justify-content:center;'
        . 'min-width:36px;height:36px;padding:0 10px;border-radius:6px;'
        . 'font-size:.875rem;font-weight:500;text-decoration:none;transition:all .15s;'
        . ($active  ? 'background:#FF5E1A;color:#fff;cursor:default;' :
          ($disabled ? 'background:transparent;color:#444;cursor:default;pointer-events:none;' :
                       'background:#1e1e1e;color:#ccc;border:1px solid #333;'))
        . '">' . $label . '</a>';

    $html  = '<div style="display:flex;align-items:center;justify-content:center;gap:4px;padding:1.5rem 0;flex-wrap:wrap">';

    // Prev
    $html .= $btn($url($cur - 1), '&#8592; Prev', false, !$pagination['has_prev']);

    // Page numbers with ellipsis
    $pages = [];
    for ($i = 1; $i <= $total; $i++) {
        if ($i === 1 || $i === $total || abs($i - $cur) <= 2) {
            $pages[] = $i;
        }
    }
    $prev = null;
    foreach ($pages as $p) {
        if ($prev !== null && $p - $prev > 1) {
            $html .= '<span style="color:#555;padding:0 4px">…</span>';
        }
        $html .= $btn($url($p), $p, $p === $cur);
        $prev = $p;
    }

    // Next
    $html .= $btn($url($cur + 1), 'Next &#8594;', false, !$pagination['has_next']);

    $html .= '</div>';
    return $html;
}

/**
 * Truncate text
 */
function truncate($text, $length = 100, $suffix = '...') {
    if (strlen($text) <= $length) return $text;
    return substr($text, 0, $length) . $suffix;
}

/**
 * Slugify text
 */
function slugify($text) {
    $text = preg_replace('~[^\pL\d]+~u', '-', $text);
    $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
    $text = preg_replace('~[^-\w]+~', '', $text);
    $text = trim($text, '-');
    $text = preg_replace('~-+~', '-', $text);
    return strtolower($text);
}

/**
 * Get cart from session
 */
function getCart() {
    return $_SESSION['cart'] ?? [];
}

/**
 * Add item to cart
 */
function addToCart($productId, $quantity = 1) {
    if (!isset($_SESSION['cart'])) {
        $_SESSION['cart'] = [];
    }
    
    if (isset($_SESSION['cart'][$productId])) {
        $_SESSION['cart'][$productId] += $quantity;
    } else {
        $_SESSION['cart'][$productId] = $quantity;
    }
}

/**
 * Update cart item quantity
 */
function updateCartItem($productId, $quantity) {
    if ($quantity <= 0) {
        removeFromCart($productId);
    } else {
        $_SESSION['cart'][$productId] = $quantity;
    }
}

/**
 * Remove item from cart
 */
function removeFromCart($productId) {
    unset($_SESSION['cart'][$productId]);
}

/**
 * Clear cart
 */
function clearCart() {
    $_SESSION['cart'] = [];
}

/**
 * Get cart count
 */
function getCartCount() {
    return array_sum($_SESSION['cart'] ?? []);
}

/**
 * Get cart total
 */
function getCartTotal() {
    $total = 0;
    $cart = getCart();
    
    foreach ($cart as $productId => $quantity) {
        $product = db()->fetch(
            "SELECT price, sale_price FROM products WHERE product_id = :id AND is_active = 1",
            ['id' => $productId]
        );
        if ($product) {
            $price = $product['sale_price'] ?? $product['price'];
            $total += $price * $quantity;
        }
    }
    
    return $total;
}

/**
 * Send email via CyberMail API.
 * Thin wrapper around Email::send() (includes/email.php) so there is a
 * single implementation of the CyberMail HTTP call, TLS settings, and
 * error handling instead of two copies that can drift out of sync.
 */
function sendEmail($to, $subject, $htmlContent, $textContent = '') {
    require_once __DIR__ . '/email.php';
    $result = emailService()->send($to, $subject, $htmlContent, $textContent ?: null);
    return $result['success'] ?? false;
}

/**
 * Log activity
 */
function logActivity($action, $details = [], $userId = null) {
    // Implement activity logging if needed
}

/**
 * Validate and save an uploaded image, verifying the ACTUAL file content
 * (not the client-supplied MIME type or filename extension, both of which
 * are attacker-controlled) before writing it to disk. Used by every admin
 * image-upload endpoint so the checks live in exactly one place.
 *
 * @param string $fieldName  Key in $_FILES to read
 * @param string $destDir    Absolute directory to save into (created if missing)
 * @param string $prefix     Filename prefix, e.g. "product_" or "splash_"
 * @return array ['success' => bool, 'url' => string, 'path' => string] or ['error' => string]
 */
function handleImageUpload(string $fieldName, string $destDir, string $prefix = 'img_'): array {
    if (empty($_FILES[$fieldName]) || $_FILES[$fieldName]['error'] !== UPLOAD_ERR_OK) {
        return ['error' => 'No file received'];
    }

    $file = $_FILES[$fieldName];

    if ($file['size'] > MAX_UPLOAD_SIZE) {
        return ['error' => 'File too large. Maximum ' . (MAX_UPLOAD_SIZE / (1024 * 1024)) . 'MB.'];
    }

    // Never trust $file['type'] (client-supplied) or the extension in
    // $file['name'] (attacker-supplied) — inspect the real file bytes.
    $imageInfo = @getimagesize($file['tmp_name']);
    if ($imageInfo === false) {
        return ['error' => 'File is not a valid image.'];
    }

    $extensionByMime = [
        'image/jpeg' => 'jpg',
        'image/png'  => 'png',
        'image/gif'  => 'gif',
        'image/webp' => 'webp',
    ];
    $mime = $imageInfo['mime'];
    if (!in_array($mime, ALLOWED_IMAGE_TYPES, true) || !isset($extensionByMime[$mime])) {
        return ['error' => 'Invalid file type. Use JPG, PNG, WebP, or GIF.'];
    }

    if (!is_dir($destDir)) {
        mkdir($destDir, 0755, true);
    }

    $filename = $prefix . time() . '_' . bin2hex(random_bytes(4)) . '.' . $extensionByMime[$mime];
    $filepath = rtrim($destDir, '/\\') . '/' . $filename;

    if (!move_uploaded_file($file['tmp_name'], $filepath)) {
        return ['error' => 'Failed to save file. Check directory permissions.'];
    }

    return ['success' => true, 'filename' => $filename, 'path' => $filepath];
}
