import { type ClassValue, clsx } from 'clsx' import { twMerge } from 'tailwind-merge' export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } export function formatBytes(bytes: number, decimals = 2): string { if (bytes === 0) return '0 Bytes' const k = 1024 const dm = decimals < 0 ? 0 : decimals const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'] const i = Math.floor(Math.log(bytes) / Math.log(k)) return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i] } export function formatUptime(seconds: number): string { const days = Math.floor(seconds / 86400) const hours = Math.floor((seconds % 86400) / 3600) const minutes = Math.floor((seconds % 3600) / 60) if (days > 0) return `${days}d ${hours}h` if (hours > 0) return `${hours}h ${minutes}m` return `${minutes}m` } export function formatDurationSeconds(seconds: number): string { const h = Math.floor(seconds / 3600) const m = Math.floor((seconds % 3600) / 60) const s = Math.floor(seconds % 60) const pad = (n: number) => n.toString().padStart(2, '0') return `${pad(h)}:${pad(m)}:${pad(s)}` } export function formatDate(date: Date | string): string { const d = new Date(date) return d.toLocaleDateString('es-MX', { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', }) } export function formatRelativeTime(date: Date | string): string { const d = new Date(date) const now = new Date() const diff = now.getTime() - d.getTime() const seconds = Math.floor(diff / 1000) const minutes = Math.floor(seconds / 60) const hours = Math.floor(minutes / 60) const days = Math.floor(hours / 24) if (days > 0) return `hace ${days}d` if (hours > 0) return `hace ${hours}h` if (minutes > 0) return `hace ${minutes}m` return 'ahora' } export function getStatusColor(status: string): string { switch (status.toUpperCase()) { case 'ONLINE': return 'text-success' case 'OFFLINE': return 'text-gray-500' case 'ALERTA': return 'text-danger' case 'MANTENIMIENTO': return 'text-warning' default: return 'text-gray-400' } } export function getStatusBgColor(status: string): string { switch (status.toUpperCase()) { case 'ONLINE': return 'bg-success/20' case 'OFFLINE': return 'bg-gray-500/20' case 'ALERTA': return 'bg-danger/20' case 'MANTENIMIENTO': return 'bg-warning/20' default: return 'bg-gray-400/20' } } export function getStatusBorderColor(status: string): string { switch (status.toUpperCase()) { case 'ONLINE': return 'border-success/50' case 'OFFLINE': return 'border-gray-500/40' case 'ALERTA': return 'border-danger/50' case 'MANTENIMIENTO': return 'border-warning/50' default: return 'border-dark-100' } } export function getSeverityColor(severity: string): string { switch (severity.toUpperCase()) { case 'CRITICAL': return 'text-danger' case 'WARNING': return 'text-warning' case 'INFO': return 'text-info' default: return 'text-gray-400' } } export function getSeverityBgColor(severity: string): string { switch (severity.toUpperCase()) { case 'CRITICAL': return 'bg-danger/20' case 'WARNING': return 'bg-warning/20' case 'INFO': return 'bg-info/20' default: return 'bg-gray-400/20' } } export function debounce) => ReturnType>( func: T, wait: number ): (...args: Parameters) => void { let timeout: NodeJS.Timeout | null = null return (...args: Parameters) => { if (timeout) clearTimeout(timeout) timeout = setTimeout(() => func(...args), wait) } } export function generateId(): string { return Math.random().toString(36).substring(2, 15) }