<?php

function base_path(string $path = ''): string
{
    return dirname(__DIR__, 2) . ($path ? DIRECTORY_SEPARATOR . $path : '');
}

function app_path(string $path = ''): string
{
    return base_path('app' . ($path ? DIRECTORY_SEPARATOR . $path : ''));
}

function public_path(string $path = ''): string
{
    return base_path('public' . ($path ? DIRECTORY_SEPARATOR . $path : ''));
}

function storage_path(string $path = ''): string
{
    return base_path('storage' . ($path ? DIRECTORY_SEPARATOR . $path : ''));
}

function url(string $path = ''): string
{
    $base = rtrim(BASE_URL, '/');
    $path = '/' . ltrim($path, '/');
    return $base . ($path === '/' ? '/' : $path);
}

function asset(string $path): string
{
    return url('/assets/' . ltrim($path, '/'));
}

function app_origin(): string
{
    $configured = defined('APP_URL') ? trim((string) APP_URL) : '';
    if ($configured !== '') {
        return rtrim($configured, '/');
    }

    $forwardedProto = strtolower((string) ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? ''));
    $isHttps = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $forwardedProto === 'https';
    $scheme = $isHttps ? 'https' : 'http';
    $host = trim((string) ($_SERVER['HTTP_HOST'] ?? 'localhost')) ?: 'localhost';

    return $scheme . '://' . $host;
}

function site_url(string $path = ''): string
{
    $origin = app_origin();
    $base = rtrim(defined('BASE_URL') ? BASE_URL : '', '/');
    $path = '/' . ltrim($path, '/');

    return $origin . $base . ($path === '/' ? '/' : $path);
}

function page_title(?string $pageTitle = null): string
{
    if ($pageTitle) {
        return $pageTitle . ' | ' . APP_NAME;
    }

    $path = current_path();
    $titles = [
        '/dashboard' => 'Executive Dashboard',
        '/loads/board' => 'Dispatch Board',
        '/loads/calendar' => 'Dispatch Calendar',
        '/loads' => 'Load Management',
        '/tracking' => 'Live Driver Map',
        '/borders' => 'Border Crossings',
        '/carriers' => 'Carrier Companies',
        '/carrier' => 'Carrier Portal',
        '/drivers' => 'Drivers',
        '/trucks' => 'Trucks',
        '/trailers' => 'Trailers',
        '/brokers' => 'Brokers and Customers',
        '/documents' => 'Document Center',
        '/invoices' => 'Invoices and Receivables',
        '/settlements' => 'Driver Settlements',
        '/accounting' => 'Accounting Center',
        '/maintenance' => 'Fleet Maintenance',
        '/reports' => 'Reports',
        '/tasks' => 'Team Tasks',
        '/notifications' => 'Notifications',
        '/users' => 'Users and Portals',
        '/settings' => 'Company Settings',
        '/fuel' => 'Fuel Allocation and Allowance',
        '/ai' => 'FleetLume AI',
        '/driver' => 'Driver Portal',
    ];

    foreach ($titles as $prefix => $title) {
        if (str_starts_with($path, $prefix)) {
            return $title . ' | ' . APP_NAME;
        }
    }

    return APP_NAME;
}

function seo_title(): string
{
    return defined('SEO_TITLE') ? SEO_TITLE : APP_NAME;
}

function seo_description(): string
{
    return defined('SEO_DESCRIPTION') ? SEO_DESCRIPTION : 'FleetLume helps dispatch companies manage carriers, loads, driver logbooks and HOS, live GPS, reefer temperatures, fuel allowances, border crossings, documents, invoicing, and accounting.';
}

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

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

function old(string $key, $default = '')
{
    return $_SESSION['_old'][$key] ?? $default;
}

function set_old(array $data): void
{
    $_SESSION['_old'] = $data;
}

function clear_old(): void
{
    unset($_SESSION['_old']);
}

function current_path(): string
{
    $path = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
    $scriptDir = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? '')), '/');

    if ($scriptDir && $scriptDir !== '/' && strpos($path, $scriptDir) === 0) {
        $path = substr($path, strlen($scriptDir));
    }

    return '/' . trim($path, '/');
}

function is_active_nav(string $path): string
{
    return strpos(current_path(), $path) === 0 ? 'active' : '';
}

function money($amount): string
{
    return (setting('currency_symbol', '$') ?: '$') . number_format((float) $amount, 2);
}

function date_display(?string $value, string $fallback = '-'): string
{
    if (!$value) {
        return $fallback;
    }

    $timestamp = strtotime($value);
    return $timestamp ? date('M d, Y', $timestamp) : $fallback;
}

function datetime_display(?string $value, string $fallback = '-'): string
{
    if (!$value) {
        return $fallback;
    }

    $timestamp = strtotime($value);
    return $timestamp ? date('M d, Y g:i A', $timestamp) : $fallback;
}

function status_class(string $status): string
{
    $map = [
        'available' => 'success',
        'active' => 'success',
        'new' => 'info',
        'assigned' => 'primary',
        'picked_up' => 'warning',
        'in_transit' => 'warning',
        'arrived_pickup' => 'warning',
        'arrived_delivery' => 'warning',
        'delivered' => 'success',
        'invoiced' => 'purple',
        'paid' => 'dark',
        'cancelled' => 'danger',
        'inactive' => 'muted',
        'maintenance' => 'danger',
        'on_load' => 'warning',
        'assigned_equipment' => 'primary',
        'draft' => 'muted',
        'sent' => 'primary',
        'overdue' => 'danger',
        'void' => 'danger',
        'pending' => 'warning',
        'scheduled' => 'info',
        'completed' => 'success',
        'approved' => 'success',
        'partially_paid' => 'warning',
        'submitted' => 'info',
        'under_review' => 'warning',
        'rejected' => 'danger',
        'reimbursed' => 'purple',
        'posted' => 'dark',
        'ready_to_cross' => 'success',
        'driver_en_route' => 'primary',
        'arrived_at_border' => 'warning',
        'waiting_in_queue' => 'warning',
        'customs_inspection' => 'purple',
        'on_hold' => 'danger',
        'cleared' => 'success',
        'crossed' => 'dark',
        'missing' => 'danger',
        'uploaded' => 'info',
        'waived' => 'muted',
        'open' => 'warning',
        'in_progress' => 'primary',
        'blocked' => 'danger',
        'documents_pending' => 'warning',
        'review' => 'info',
        'lead' => 'muted',
        'on_hold' => 'danger',
        'accepted' => 'success',
        'not_sent' => 'muted',
        'issued' => 'primary',
        'partially_used' => 'warning',
        'used' => 'success',
        'closed' => 'dark',
    ];

    return $map[$status] ?? 'muted';
}

function readable_status(string $status): string
{
    return ucwords(str_replace('_', ' ', $status));
}

function relation_label(string $type): string
{
    return [
        'carrier' => 'Carrier Company',
        'driver' => 'Driver',
        'truck' => 'Truck',
        'trailer' => 'Trailer',
        'broker' => 'Broker / Customer',
        'load' => 'Load',
        'invoice' => 'Invoice',
        'stop' => 'Load Stop',
        'border_crossing' => 'Border Crossing',
        'border_issue' => 'Border Issue',
        'expense' => 'Expense',
        'vendor_bill' => 'Vendor Bill',
        'fuel_allocation' => 'Fuel Allocation',
        'fuel_transaction' => 'Fuel Transaction',
    ][$type] ?? readable_status($type);
}

function user_initials(?string $name): string
{
    $name = trim((string) $name);
    if ($name === '') {
        return 'U';
    }

    $parts = preg_split('/\s+/', $name) ?: [];
    $initials = '';
    foreach (array_slice($parts, 0, 2) as $part) {
        $initials .= strtoupper(substr($part, 0, 1));
    }
    return $initials ?: 'U';
}

function log_activity(string $action, string $description = ''): void
{
    try {
        $db = Database::connection();
        $stmt = $db->prepare('INSERT INTO activity_logs (user_id, action, description) VALUES (?, ?, ?)');
        $stmt->execute([$_SESSION['user_id'] ?? null, $action, $description ?: null]);
    } catch (Throwable $exception) {
        // Activity logging should never block the user's action.
    }
}

function is_driver_user(): bool
{
    $user = Auth::user();
    return ($user['role'] ?? '') === 'driver';
}


function json_response(array $data, int $status = 200): void
{
    http_response_code($status);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    exit;
}

function setting(string $key, ?string $default = null): ?string
{
    static $cache = [];
    if (array_key_exists($key, $cache)) {
        return $cache[$key];
    }
    try {
        $stmt = Database::connection()->prepare('SELECT setting_value FROM system_settings WHERE setting_key = ? LIMIT 1');
        $stmt->execute([$key]);
        $value = $stmt->fetchColumn();
        $cache[$key] = $value !== false ? (string) $value : $default;
    } catch (Throwable $exception) {
        $cache[$key] = $default;
    }
    return $cache[$key];
}

function current_role(): string
{
    return (string) (Auth::user()['role'] ?? '');
}

function is_admin_role(): bool
{
    return in_array(current_role(), ['owner', 'admin'], true);
}

function can(string $permission): bool
{
    $user = Auth::user();
    if (!$user) return false;
    if (in_array($user['role'], ['owner', 'admin'], true)) return true;
    $roleDefaults = [
        'dispatcher' => ['dispatch.view','dispatch.manage','loads.view','loads.manage','carriers.manage','drivers.view','equipment.view','documents.manage','border.manage','tracking.view','tasks.manage','fuel.view','fuel.manage','hos.view','hos.manage','ai.use'],
        'accountant' => ['accounting.view','accounting.manage','invoices.manage','settlements.manage','reports.financial','documents.view','fuel.view','fuel.manage','ai.use'],
        'driver' => ['driver.portal','driver.location','driver.upload','driver.expenses','driver.border','driver.fuel','hos.driver'],
        'carrier' => ['carrier.portal','documents.view','hos.view'],
        'maintenance' => ['maintenance.manage','equipment.view','documents.manage','tasks.manage'],
        'team' => ['loads.view','documents.manage','tasks.manage','ai.use'],
    ];
    if (in_array($permission, $roleDefaults[$user['role']] ?? [], true)) return true;
    $custom = json_decode((string) ($user['permissions'] ?? ''), true);
    return is_array($custom) && in_array($permission, $custom, true);
}

function next_reference(string $prefix, string $table, string $column): string
{
    try {
        $stmt = Database::connection()->query("SELECT {$column} FROM {$table} ORDER BY id DESC LIMIT 1");
        $last = (string) ($stmt->fetchColumn() ?: '');
        if (preg_match('/(\\d+)$/', $last, $m)) {
            return $prefix . str_pad((string) ((int) $m[1] + 1), 5, '0', STR_PAD_LEFT);
        }
    } catch (Throwable $exception) {}
    return $prefix . '00001';
}

function notify_roles(array $roles, string $title, string $message = '', ?string $link = null, string $level = 'info'): void
{
    try {
        $db = Database::connection();
        $roles = array_values(array_unique(array_filter($roles)));
        if (!$roles) return;
        $placeholders = implode(',', array_fill(0, count($roles), '?'));
        $users = $db->prepare("SELECT id FROM users WHERE status='active' AND role IN ({$placeholders})");
        $users->execute($roles);
        $stmt = $db->prepare('INSERT INTO notifications (user_id, title, message, link, level) VALUES (?, ?, ?, ?, ?)');
        foreach ($users->fetchAll() as $user) {
            $stmt->execute([(int) $user['id'], $title, $message ?: null, $link, $level]);
        }
    } catch (Throwable $exception) {
        // Notifications must never interrupt an operational action.
    }
}

function notify_user(int $userId, string $title, string $message = '', ?string $link = null, string $level = 'info'): void
{
    try {
        Database::connection()->prepare('INSERT INTO notifications (user_id, title, message, link, level) VALUES (?, ?, ?, ?, ?)')
            ->execute([$userId, $title, $message ?: null, $link, $level]);
    } catch (Throwable $exception) {
    }
}

function notify_carrier_users(int $carrierId, string $title, string $message = '', ?string $link = null, string $level = 'info'): void
{
    if ($carrierId <= 0) return;
    try {
        $db = Database::connection();
        $users = $db->prepare("SELECT id FROM users WHERE status='active' AND role='carrier' AND carrier_id=?");
        $users->execute([$carrierId]);
        $stmt = $db->prepare('INSERT INTO notifications (user_id, title, message, link, level) VALUES (?, ?, ?, ?, ?)');
        foreach ($users->fetchAll() as $user) {
            $stmt->execute([(int) $user['id'], $title, $message ?: null, $link, $level]);
        }
    } catch (Throwable $exception) {
    }
}

function unread_notification_count(): int
{
    $user = Auth::user();
    if (!$user) return 0;
    try {
        $stmt = Database::connection()->prepare('SELECT COUNT(*) FROM notifications WHERE read_at IS NULL AND (user_id = ? OR role_target = ?)');
        $stmt->execute([(int) $user['id'], $user['role']]);
        return (int) $stmt->fetchColumn();
    } catch (Throwable $exception) {
        return 0;
    }
}

function hos_minutes(int|float|string|null $minutes): string
{
    $total = max(0, (int) round((float) $minutes));
    return sprintf('%02d:%02d', intdiv($total, 60), $total % 60);
}

function hos_status_label(string $status, ?string $special = null): string
{
    if ($special === 'personal_conveyance') return 'Personal Conveyance';
    if ($special === 'yard_move') return 'Yard Move';
    return match ($status) {
        'off_duty' => 'Off Duty',
        'sleeper_berth' => 'Sleeper Berth',
        'driving' => 'Driving',
        'on_duty' => 'On Duty (Not Driving)',
        default => readable_status($status),
    };
}

function hos_rule_label(string $rule): string
{
    return match ($rule) {
        'us_property' => 'United States · Property Carrying',
        'canada_south' => 'Canada · South of 60°N',
        'canada_north' => 'Canada · North of 60°N',
        default => readable_status($rule),
    };
}


function ai_pending_action_count(): int
{
    try { return (int) Database::connection()->query("SELECT COUNT(*) FROM ai_action_queue WHERE status='proposed'")->fetchColumn(); }
    catch (Throwable $exception) { return 0; }
}

function ai_recent_change_count(int $hours = 24): int
{
    $hours=max(1,min(168,$hours));
    try { return (int) Database::connection()->query("SELECT COUNT(*) FROM ai_change_log WHERE created_at >= DATE_SUB(NOW(), INTERVAL {$hours} HOUR)")->fetchColumn(); }
    catch (Throwable $exception) { return 0; }
}

function ai_automation_is_ready(): bool
{
    try { return setting('ai_automation_enabled','1')==='1' && (new GeminiService())->isEnabled(); }
    catch (Throwable $exception) { return false; }
}
