<?php
/**
 * SalonPro X - Global Helper Functions
 */

use core\Auth;
use core\Security;
use core\Session;
use core\Database;

/**
 * Escape HTML output (XSS prevention)
 */
function e(mixed $value): string
{
    return Security::escape($value);
}

/**
 * Get CSRF hidden input field
 */
function csrf_field(): string
{
    return Security::csrfField();
}

/**
 * Get CSRF token
 */
function csrf_token(): string
{
    return Security::getCsrfToken();
}

/**
 * Generate URL for path
 */
function url(string $path = ''): string
{
    return rtrim(APP_URL, '/') . '/' . ltrim($path, '/');
}

/**
 * Redirect to URL
 */
function redirect(string $url): void
{
    header('Location: ' . url($url));
    exit;
}

/**
 * Redirect back
 */
function back(): void
{
    $referer = $_SERVER['HTTP_REFERER'] ?? APP_URL;
    header('Location: ' . $referer);
    exit;
}

/**
 * Get asset URL
 */
function asset(string $path): string
{
    $v = defined('APP_VERSION') ? APP_VERSION : '1.0';
    return url('assets/' . ltrim($path, '/')) . '?v=' . $v;
}

/**
 * Get upload URL
 */
function uploadUrl(string $path): string
{
    return url('uploads/' . ltrim($path, '/'));
}

/**
 * Format currency
 */
function currency(mixed $amount): string
{
    return APP_CURRENCY_SYMBOL . ' ' . number_format((float)$amount, 2);
}

/**
 * Format number
 */
function formatNumber(mixed $number, int $decimals = 2): string
{
    return number_format((float)$number, $decimals);
}

/**
 * Format date
 */
function formatDate(?string $date, string $format = null): string
{
    if (empty($date)) {
        return '-';
    }
    $format = $format ?? DATE_DISPLAY_FORMAT;
    return date($format, strtotime($date));
}

/**
 * Format date time
 */
function formatDateTime(?string $date): string
{
    if (empty($date)) {
        return '-';
    }
    return date(DATE_TIME_DISPLAY_FORMAT, strtotime($date));
}

/**
 * Format time
 */
function formatTime(?string $time): string
{
    if (empty($time)) {
        return '-';
    }
    return date(TIME_FORMAT, strtotime($time));
}

/**
 * Time ago helper
 */
function timeAgo(?string $datetime): string
{
    if (empty($datetime)) {
        return '-';
    }
    $timestamp = strtotime($datetime);
    $diff = time() - $timestamp;

    if ($diff < 60) return 'Just now';
    if ($diff < 3600) return floor($diff / 60) . ' min ago';
    if ($diff < 86400) return floor($diff / 3600) . ' hours ago';
    if ($diff < 604800) return floor($diff / 86400) . ' days ago';
    return date(DATE_DISPLAY_FORMAT, $timestamp);
}

/**
 * Get old input value
 */
function old(string $key, mixed $default = ''): mixed
{
    $old = Session::flash('_old_input');
    return $old[$key] ?? $default;
}

/**
 * Get validation error for field
 */
function _validationErrors(): ?array
{
    static $errors = null;
    if ($errors === null) {
        $errors = Session::flash('_errors');
    }
    return $errors;
}

function error(string $field): ?string
{
    return _validationErrors()[$field][0] ?? null;
}

/**
 * Check if field has validation error
 */
function hasError(string $field): bool
{
    return isset(_validationErrors()[$field]);
}

/**
 * Display form error class
 */
function errorClass(string $field): string
{
    return hasError($field) ? 'is-invalid' : '';
}

/**
 * Display form error message
 */
function errorMsg(string $field): string
{
    $msg = error($field);
    return $msg ? '<div class="invalid-feedback">' . e($msg) . '</div>' : '';
}

/**
 * Check if user has permission
 */
function can(string $permission): bool
{
    return Auth::hasPermission($permission);
}

/**
 * Check if user is logged in
 */
function auth(): bool
{
    return Auth::check();
}

/**
 * Get current user
 */
function user(): ?object
{
    return Auth::user();
}

/**
 * Get setting value
 */
function setting(string $key, mixed $default = ''): mixed
{
    $db = Database::getInstance();
    $setting = $db->table('settings')->where('key', $key)->first();
    return $setting ? $setting->value : $default;
}

/**
 * Generate pagination links
 */
function paginateLinks(object $pagination, string $url = ''): string
{
    if ($pagination->totalPages <= 1) {
        return '';
    }

    $url = $url ?: parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
    $html = '<nav><ul class="pagination pagination-sm">';

    // Previous
    $prevClass = $pagination->hasPrev ? '' : ' disabled';
    $html .= '<li class="page-item' . $prevClass . '">';
    if ($pagination->hasPrev) {
        $html .= '<a class="page-link" href="' . $url . '?page=' . $pagination->prevPage . '">Previous</a>';
    } else {
        $html .= '<span class="page-link">Previous</span>';
    }
    $html .= '</li>';

    // Pages
    for ($i = 1; $i <= $pagination->totalPages; $i++) {
        $active = $i === $pagination->currentPage ? ' active' : '';
        $html .= '<li class="page-item' . $active . '">';
        $html .= '<a class="page-link" href="' . $url . '?page=' . $i . '">' . $i . '</a>';
        $html .= '</li>';
    }

    // Next
    $nextClass = $pagination->hasNext ? '' : ' disabled';
    $html .= '<li class="page-item' . $nextClass . '">';
    if ($pagination->hasNext) {
        $html .= '<a class="page-link" href="' . $url . '?page=' . $pagination->nextPage . '">Next</a>';
    } else {
        $html .= '<span class="page-link">Next</span>';
    }
    $html .= '</li>';

    $html .= '</ul></nav>';
    return $html;
}

/**
 * Generate unique invoice number
 */
function generateInvoiceNumber(): string
{
    $prefix = 'INV-';
    $year = date('Y');
    $month = date('m');
    $db = Database::getInstance();
    $count = $db->table('invoices')->where('invoice_number', 'LIKE', $prefix . $year . $month . '%')->count();
    return $prefix . $year . $month . str_pad($count + 1, 4, '0', STR_PAD_LEFT);
}

/**
 * Generate unique purchase order number
 */
function generatePoNumber(): string
{
    $prefix = 'PO-';
    $year = date('Y');
    $count = Database::getInstance()->table('purchase_orders')->count();
    return $prefix . $year . '-' . str_pad($count + 1, 5, '0', STR_PAD_LEFT);
}

/**
 * Generate unique GRN number
 */
function generateGrnNumber(): string
{
    $prefix = 'GRN-';
    $year = date('Y');
    $count = Database::getInstance()->table('goods_received_notes')->count();
    return $prefix . $year . '-' . str_pad($count + 1, 5, '0', STR_PAD_LEFT);
}

/**
 * Calculate commission amount
 */
function calculateCommission(float $amount, string $type, float $value): float
{
    return match ($type) {
        'percentage' => ($amount * $value) / 100,
        'fixed' => $value,
        default => 0,
    };
}

/**
 * Log message to file
 */
function logger(string $message, string $type = 'info', string $file = 'app'): void
{
    $logFile = PATH_LOGS . DS . $file . '.log';
    $entry = date('Y-m-d H:i:s') . ' [' . strtoupper($type) . '] ' . $message . PHP_EOL;
    file_put_contents($logFile, $entry, FILE_APPEND | LOCK_EX);
}

/**
 * Get mime type from extension
 */
function mimeFromExtension(string $extension): string
{
    $mimes = [
        'jpg' => 'image/jpeg',
        'jpeg' => 'image/jpeg',
        'png' => 'image/png',
        'gif' => 'image/gif',
        'webp' => 'image/webp',
        'pdf' => 'application/pdf',
        'doc' => 'application/msword',
        'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'xls' => 'application/vnd.ms-excel',
        'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        'csv' => 'text/csv',
        'txt' => 'text/plain',
    ];
    return $mimes[strtolower($extension)] ?? 'application/octet-stream';
}

/**
 * Upload file
 */
function uploadFile(array $file, string $directory = 'temp', array $allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp']): ?string
{
    if ($file['error'] !== UPLOAD_ERR_OK) {
        return null;
    }

    $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
    if (!in_array($ext, $allowedTypes)) {
        return null;
    }

    $uploadDir = PATH_UPLOADS . DS . $directory;
    if (!is_dir($uploadDir)) {
        mkdir($uploadDir, 0755, true);
    }

    $filename = uniqid() . '_' . time() . '.' . $ext;
    $destPath = $uploadDir . DS . $filename;

    if (move_uploaded_file($file['tmp_name'], $destPath)) {
        return $directory . '/' . $filename;
    }

    return null;
}

/**
 * Delete file
 */
function deleteFile(string $path): bool
{
    $fullPath = PATH_UPLOADS . DS . $path;
    if (file_exists($fullPath)) {
        return unlink($fullPath);
    }
    return false;
}

/**
 * Get status badge class
 */
function statusBadge(string $status): string
{
    return match (strtolower($status)) {
        'active', 'completed', 'paid', 'approved', 'confirmed', 'checked_in' => 'success',
        'pending', 'draft', 'partial' => 'warning',
        'inactive', 'cancelled', 'rejected', 'void', 'refunded' => 'danger',
        'in_progress', 'processing' => 'info',
        'on_hold', 'suspended' => 'secondary',
        default => 'secondary',
    };
}

/**
 * Pluralize helper
 */
function pluralize(string $word, int $count): string
{
    if ($count === 1) {
        return $word;
    }
    return $word . 's';
}

/**
 * Truncate text
 */
function truncate(string $text, int $length = 100, string $suffix = '...'): string
{
    if (mb_strlen($text) <= $length) {
        return $text;
    }
    return mb_substr($text, 0, $length) . $suffix;
}

/**
 * Generate random color
 */
function randomColor(): string
{
    $colors = ['#C8A44E', '#E8D48B', '#D4AF37', '#A8893A', '#FFD700', '#F0E68C', '#B8860B', '#DAA520'];
    return $colors[array_rand($colors)];
}

/**
 * Get payment methods list
 */
function paymentMethods(): array
{
    return ['cash' => 'Cash', 'card' => 'Card', 'bank_transfer' => 'Bank Transfer', 'gift_card' => 'Gift Card', 'advance' => 'Advance Payment'];
}

/**
 * Get appointment statuses
 */
function appointmentStatuses(): array
{
    return [
        'pending' => 'Pending',
        'confirmed' => 'Confirmed',
        'checked_in' => 'Checked In',
        'in_progress' => 'In Progress',
        'completed' => 'Completed',
        'cancelled' => 'Cancelled',
        'no_show' => 'No Show',
    ];
}

/**
 * Get payment statuses
 */
function paymentStatuses(): array
{
    return ['pending' => 'Pending', 'partial' => 'Partial', 'paid' => 'Paid', 'refunded' => 'Refunded', 'cancelled' => 'Cancelled'];
}

/**
 * Get days of week
 */
function daysOfWeek(): array
{
    return ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
}

/**
 * Get time slots in minutes interval
 */
function timeSlots(int $interval = 30): array
{
    $slots = [];
    $start = strtotime('00:00');
    $end = strtotime('23:59');
    while ($start <= $end) {
        $slots[] = date('H:i', $start);
        $start = strtotime('+' . $interval . ' minutes', $start);
    }
    return $slots;
}

/**
 * Calculate duration between two times
 */
function calculateDuration(string $start, string $end): int
{
    return (strtotime($end) - strtotime($start)) / 60;
}

/**
 * Add business days to date
 */
function addBusinessDays(string $date, int $days): string
{
    $timestamp = strtotime($date);
    $added = 0;
    while ($added < $days) {
        $timestamp = strtotime('+1 day', $timestamp);
        if (date('N', $timestamp) < 6) {
            $added++;
        }
    }
    return date('Y-m-d', $timestamp);
}

/**
 * Check if string is JSON
 */
function isJson(string $string): bool
{
    json_decode($string);
    return json_last_error() === JSON_ERROR_NONE;
}

/**
 * Safe json encode
 */
function jsonSafe(mixed $data): string
{
    return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP);
}

/**
 * Dump and die (debugging)
 */
function dd(mixed ...$vars): void
{
    echo '<pre>';
    foreach ($vars as $var) {
        var_dump($var);
    }
    echo '</pre>';
    exit;
}
