<x-filament-widgets::widget
    x-data="{
        poller: null,
        isRefreshing: false,
        lastUpdatedLabel: null,
        init() {
            this.requestRefresh();
            this.poller = setInterval(() => {
                this.requestRefresh();
            }, 10000);
        },
        async requestRefresh() {
            if (this.isRefreshing) {
                return;
            }
            if (document.visibilityState === 'hidden') {
                return;
            }
            this.isRefreshing = true;
            try {
                await $wire.refreshData();
                this.lastUpdatedLabel = new Date().toLocaleTimeString();
            } finally {
                this.isRefreshing = false;
            }
        },
        stop() {
            if (this.poller) {
                clearInterval(this.poller);
                this.poller = null;
            }
        }
    }"
    x-on:livewire:navigating.window="stop()"
    x-on:beforeunload.window="stop()"
>
    @php
        $data = $this->getData();
        $cpu = $data['cpu'] ?? [];
        $memory = $data['memory'] ?? [];
        $disk = $data['disk'] ?? [];
        $partitions = $disk['partitions'] ?? [];
        $load = $data['load'] ?? [];
        $uptime = $data['uptime'] ?? 'N/A';
        $range = $this->range;
        $historyPoints = match ($range) {
            '5m' => 30,
            '30m' => 180,
            'day' => 24,
            'week' => 28,
            'month' => 30,
            default => 30,
        };
        $historyIntervalSeconds = match ($range) {
            '5m' => 10,
            '30m' => 10,
            'day' => 3600,
            'week' => 21600,
            'month' => 86400,
            default => 60,
        };
        $historyLabelFormat = match ($range) {
            '5m' => 'H:i:s',
            '30m' => 'H:i:s',
            'day' => 'H:00',
            'week' => 'M d H:00',
            'month' => 'M d',
            default => 'H:i',
        };

        $cpuCores = max(1, (int)($cpu['cores'] ?? 1));
        $load1 = (float)($load['1min'] ?? 0);
        $load5 = (float)($load['5min'] ?? 0);
        $load15 = (float)($load['15min'] ?? 0);
        $ioWait = (float)($cpu['iowait'] ?? 0);
        $memUsage = $memory['usage'] ?? 0;
        $history = $this->getHistory(
            $load1,
            $ioWait,
            (float) $memUsage,
            (float) ($memory['swap_usage'] ?? 0),
            $partitions,
        );
        $historyLabels = $history['labels'] ?? [];
        $historyLoad = $history['load'] ?? [];
        $historyIoWait = $history['iowait'] ?? [];
        $historyMemory = $history['memory'] ?? [];
        $historySwap = $history['swap'] ?? [];
        // Memory values are in MB from agent
        $memUsedGB = ($memory['used'] ?? 0) / 1024;
        $memTotalGB = ($memory['total'] ?? 0) / 1024;
        $swapUsedGB = ($memory['swap_used'] ?? 0) / 1024;
        $swapTotalGB = ($memory['swap_total'] ?? 0) / 1024;
        $hasSwap = $swapTotalGB > 0;

        $diskMounts = collect($partitions)
            ->map(fn (array $partition) => $partition['mount'] ?? $partition['filesystem'] ?? null)
            ->filter()
            ->unique()
            ->values()
            ->all();
        $diskTotals = [];
        $diskUsedTotal = 0;
        $diskTotal = 0;
        foreach ($partitions as $partition) {
            $mount = $partition['mount'] ?? $partition['filesystem'] ?? null;
            if ($mount === null) {
                continue;
            }
            $used = (float) ($partition['used'] ?? 0);
            $total = (float) ($partition['total'] ?? 0);
            $diskTotals[$mount] = $total > 0 ? round($total / 1024 / 1024 / 1024, 2) : 0;
            $diskUsedTotal += $used;
            $diskTotal += $total;
        }
        $diskUsedTotalGB = $diskUsedTotal > 0 ? $diskUsedTotal / 1024 / 1024 / 1024 : 0;
        $diskTotalGB = $diskTotal > 0 ? $diskTotal / 1024 / 1024 / 1024 : 0;
        $diskUsedSeries = [];
        $diskFreeSeries = [];
        foreach ($diskMounts as $mount) {
            $partition = collect($partitions)->first(fn (array $row) => ($row['mount'] ?? $row['filesystem'] ?? null) === $mount);
            $used = $partition ? ((float) ($partition['used'] ?? 0)) / 1024 / 1024 / 1024 : 0;
            $total = $partition ? ((float) ($partition['total'] ?? 0)) / 1024 / 1024 / 1024 : 0;
            $diskUsedSeries[] = round($used, 2);
            $diskFreeSeries[] = round(max(0, $total - $used), 2);
        }
    @endphp

    <style>
        .server-charts-grid {
            display: grid;
            grid-template-columns: 1fr;
            gap: 0;
        }
        .server-charts-grid .chart-card {
            padding: 0.5rem;
        }
        @media (min-width: 768px) {
            .server-charts-grid {
                grid-template-columns: 40% 40% 20%;
            }
        }
        .chart-container {
            height: 160px;
            width: 100%;
            position: relative;
        }
        .chart-container canvas {
            width: 100%;
            height: 100%;
            display: block;
        }
        @media (min-width: 640px) {
            .chart-container {
                height: 180px;
            }
        }
        @media (min-width: 1024px) {
            .chart-container {
                height: 200px;
            }
        }
        .chart-label {
            display: flex;
            align-items: center;
            justify-content: flex-start;
            gap: 0.5rem;
            margin-top: 0.5rem;
        }
        .chart-title {
            font-weight: 600;
            font-size: 0.875rem;
            color: rgb(17 24 39);
        }
        .dark .chart-title {
            color: white;
        }
        .chart-subtitle {
            font-size: 0.75rem;
            color: rgb(107 114 128);
            text-align: left;
            margin-top: 0.25rem;
        }
        .dark .chart-subtitle {
            color: rgb(156 163 175);
        }
    </style>

    <div class="mb-4 flex flex-wrap items-center gap-2">
        <x-filament::button
            size="sm"
            :color="$range === '5m' ? 'primary' : 'gray'"
            wire:click="setRange('5m')"
        >
            {{ __('Last 5 minutes') }}
        </x-filament::button>
        <x-filament::button
            size="sm"
            :color="$range === '30m' ? 'primary' : 'gray'"
            wire:click="setRange('30m')"
        >
            {{ __('Last 30 minutes') }}
        </x-filament::button>
        <x-filament::button
            size="sm"
            :color="$range === 'day' ? 'primary' : 'gray'"
            wire:click="setRange('day')"
        >
            {{ __('Last day') }}
        </x-filament::button>
        <x-filament::button
            size="sm"
            :color="$range === 'week' ? 'primary' : 'gray'"
            wire:click="setRange('week')"
        >
            {{ __('Last week') }}
        </x-filament::button>
        <x-filament::button
            size="sm"
            :color="$range === 'month' ? 'primary' : 'gray'"
            wire:click="setRange('month')"
        >
            {{ __('Last month') }}
        </x-filament::button>
        <div class="ml-auto text-xs text-gray-500 dark:text-gray-400">
            {{ __('Last updated') }}:
            <span x-text="lastUpdatedLabel ?? '—'"></span>
        </div>
    </div>
    @if(!empty($data['warning']))
        <div class="mb-3 text-xs text-warning-600 dark:text-warning-400">
            {{ __('Agent unavailable, showing local metrics.') }}
        </div>
    @endif

    {{-- Main Charts Grid (3 columns) --}}
    <div class="server-charts-grid">
        {{-- CPU Usage Chart --}}
        <div class="chart-card chart-card--load">
            <div
                x-data="{
                    labels: @js($historyLabels),
                    series: @js($historyLoad),
                    ioWaitSeries: @js($historyIoWait),
                    value: {{ $load1 }},
                    ioWaitValue: {{ $ioWait }},
                    maxValue: {{ $cpuCores }},
                    maxPoints: {{ $historyPoints }},
                    intervalSeconds: {{ $historyIntervalSeconds }},
                    labelFormat: @js($historyLabelFormat),
                    init() {
                        if (!this.labels.length || !this.series.length) {
                            this.seedSeries();
                        }
                        this.initChart();
                        const handleRange = (payload) => {
                            const normalized = Array.isArray(payload) ? (payload[0] ?? {}) : (payload ?? {});
                            if (normalized?.label_format) {
                                this.labelFormat = normalized.label_format;
                            }
                            if (normalized?.interval_seconds) {
                                this.intervalSeconds = normalized.interval_seconds;
                            }
                            this.applyHistory(normalized?.history, normalized?.history_points);
                        };
                        const handleUpdate = (payload) => {
                            const normalized = Array.isArray(payload) ? (payload[0] ?? {}) : (payload ?? {});
                            if (normalized?.history) {
                                this.applyHistory(normalized.history, normalized.history_points);
                                return;
                            }
                            const newValue = normalized?.load;
                            const ioWaitValue = normalized?.iowait;
                            const label = normalized?.label ?? null;
                            if (newValue !== undefined) {
                                this.pushPoint(newValue, ioWaitValue, label);
                            }
                        };
                        if (window.Livewire?.on) {
                            window.Livewire.on('server-charts-range-changed', handleRange);
                            window.Livewire.on('server-charts-updated', handleUpdate);
                        }
                        document.addEventListener('server-charts-range-changed', (event) => {
                            handleRange(event?.detail ?? {});
                        });
                        document.addEventListener('server-charts-updated', (event) => {
                            handleUpdate(event?.detail ?? {});
                        });
                    },
                    applyHistory(history, points) {
                        if (!history) {
                            return;
                        }
                        this.labels = history.labels ?? [];
                        this.series = history.load ?? [];
                        this.ioWaitSeries = history.iowait ?? [];
                        if (this.ioWaitSeries.length !== this.labels.length) {
                            this.ioWaitSeries = this.labels.map(() => this.ioWaitValue);
                        }
                        this.maxPoints = points ?? (this.labels.length || this.maxPoints);
                        if (history.label_format) {
                            this.labelFormat = history.label_format;
                        }
                        if (history.interval_seconds) {
                            this.intervalSeconds = history.interval_seconds;
                        }
                        this.updateChart();
                    },
                    seedSeries() {
                        const now = new Date();
                        for (let i = this.maxPoints - 1; i >= 0; i--) {
                            const stamp = new Date(now.getTime() - (i * this.intervalSeconds * 1000));
                            this.labels.push(this.formatTime(stamp));
                            this.series.push(this.value);
                            this.ioWaitSeries.push(this.ioWaitValue);
                        }
                    },
                    formatTime(date) {
                        const pad = (value) => String(value).padStart(2, '0');
                        const hours = pad(date.getHours());
                        const minutes = pad(date.getMinutes());
                        const seconds = pad(date.getSeconds());
                        const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
                        const month = months[date.getMonth()];
                        const day = pad(date.getDate());

                        switch (this.labelFormat) {
                            case 'H:i:s':
                                return `${hours}:${minutes}:${seconds}`;
                            case 'H:00':
                                return `${hours}:00`;
                            case 'M d H:00':
                                return `${month} ${day} ${hours}:00`;
                            case 'M d':
                                return `${month} ${day}`;
                            default:
                                return `${hours}:${minutes}:${seconds}`;
                        }
                    },
                    pushPoint(value, ioWaitValue, label) {
                        const nextLabel = label ?? this.formatTime(new Date());
                        const nextIoWait = ioWaitValue ?? this.ioWaitValue;
                        if (this.labels.length && this.labels[this.labels.length - 1] === nextLabel) {
                            this.series[this.series.length - 1] = value;
                            this.ioWaitSeries[this.ioWaitSeries.length - 1] = nextIoWait;
                            this.updateChart();
                            return;
                        }
                        this.series.push(value);
                        this.ioWaitSeries.push(nextIoWait);
                        this.labels.push(nextLabel);
                        if (this.series.length > this.maxPoints) {
                            this.series.shift();
                            this.ioWaitSeries.shift();
                            this.labels.shift();
                        }
                        this.updateChart();
                    },
                    axisInterval() {
                        return this.labels.length > 0 ? Math.max(0, Math.floor(this.labels.length / 6)) : 0;
                    },
                    tickStep() {
                        if (!this.labels.length) {
                            return 1;
                        }
                        return Math.max(1, Math.round(this.labels.length / 6));
                    },
                    tickLabel(index, maxTicks = 5) {
                        if (!this.labels.length) {
                            return '';
                        }
                        const step = Math.max(1, Math.ceil(this.labels.length / maxTicks));
                        return index % step === 0 ? (this.labels[index] ?? '') : '';
                    },
                    scaleBounds(series, minDefault = 0, maxDefault = null, paddingRatio = 0.15) {
                        if (!Array.isArray(series) || series.length === 0) {
                            return { min: minDefault, max: maxDefault };
                        }
                        const values = series.map((value) => Number(value)).filter((value) => Number.isFinite(value));
                        if (!values.length) {
                            return { min: minDefault, max: maxDefault };
                        }
                        const minValue = Math.min(...values);
                        const maxValue = Math.max(...values);
                        const range = Math.max(1, maxValue - minValue);
                        const padding = range * paddingRatio;
                        const min = Math.max(minDefault ?? minValue, minValue - padding);
                        const max = maxDefault !== null ? Math.min(maxDefault, maxValue + padding) : maxValue + padding;
                        return { min, max };
                    },
                    cloneArray(items) {
                        return Array.isArray(items) ? items.slice() : [];
                    },
                    getChart() {
                        return this.$refs.chart?.__chart ?? null;
                    },
                    setChart(instance) {
                        if (this.$refs.chart) {
                            this.$refs.chart.__chart = instance;
                        }
                    },
                    updateChart() {
                        const chart = this.getChart();
                        if (!chart) {
                            return;
                        }
                        const ratio = this.maxValue > 0 ? (this.series[this.series.length - 1] / this.maxValue) * 100 : this.series[this.series.length - 1];
                        const color = ratio >= 90 ? '#ef4444' : (ratio >= 70 ? '#f59e0b' : '#22c55e');
                        const areaColor = ratio >= 90 ? 'rgba(239,68,68,0.15)' : (ratio >= 70 ? 'rgba(245,158,11,0.15)' : 'rgba(34,197,94,0.15)');
                        const loadPeak = this.series.length ? Math.max(...this.series) : 0;
                        const loadMax = Math.max(this.maxValue, loadPeak);
                        const loadBounds = this.scaleBounds(this.series, 0, null, 0.2);
                        const ioWaitBounds = this.scaleBounds(this.ioWaitSeries, 0, 100, 0.2);
                        chart.data.labels = this.cloneArray(this.labels);
                        chart.data.datasets[0].data = this.cloneArray(this.series);
                        chart.data.datasets[0].borderColor = color;
                        chart.data.datasets[0].backgroundColor = areaColor;
                        chart.data.datasets[1].data = this.cloneArray(this.ioWaitSeries);
                        if (chart.options?.scales?.y) {
                            chart.options.scales.y.suggestedMin = loadBounds.min;
                            chart.options.scales.y.suggestedMax = Math.max(loadMax, loadBounds.max ?? loadMax);
                        }
                        if (chart.options?.scales?.y1) {
                            chart.options.scales.y1.suggestedMin = ioWaitBounds.min;
                            chart.options.scales.y1.suggestedMax = ioWaitBounds.max ?? 100;
                        }
                        chart.update('none');
                    },
                    initChart() {
                        if (typeof window.Chart === 'undefined') {
                            setTimeout(() => this.initChart(), 100);
                            return;
                        }
                        const isDark = document.documentElement.classList.contains('dark');
                        const ratio = this.maxValue > 0 ? (this.value / this.maxValue) * 100 : this.value;
                        const color = ratio >= 90 ? '#ef4444' : (ratio >= 70 ? '#f59e0b' : '#22c55e');
                        const areaColor = ratio >= 90 ? 'rgba(239,68,68,0.15)' : (ratio >= 70 ? 'rgba(245,158,11,0.15)' : 'rgba(34,197,94,0.15)');
                        const ioWaitColor = '#38bdf8';
                        const loadPeak = this.series.length ? Math.max(...this.series) : 0;
                        const loadMax = Math.max(this.maxValue, loadPeak);
                        const loadBounds = this.scaleBounds(this.series, 0, null, 0.2);
                        const ioWaitBounds = this.scaleBounds(this.ioWaitSeries, 0, 100, 0.2);
                        const ctx = this.$refs.chart.getContext('2d');
                        this.setChart(new Chart(ctx, {
                            type: 'line',
                            data: {
                                labels: this.cloneArray(this.labels),
                                datasets: [
                                    {
                                        label: 'Load',
                                        data: this.cloneArray(this.series),
                                        tension: 0.35,
                                        borderColor: color,
                                        backgroundColor: areaColor,
                                        fill: false,
                                        pointRadius: 2,
                                        pointHoverRadius: 3,
                                    },
                                    {
                                        label: 'IO wait',
                                        data: this.cloneArray(this.ioWaitSeries),
                                        tension: 0.35,
                                        borderColor: ioWaitColor,
                                        backgroundColor: 'transparent',
                                        borderDash: [6, 4],
                                        yAxisID: 'y1',
                                        pointRadius: 2,
                                        pointHoverRadius: 3,
                                    }
                                ]
                            },
                            options: {
                                responsive: true,
                                maintainAspectRatio: false,
                                interaction: { mode: 'index', intersect: false },
                                plugins: {
                                    legend: { display: false },
                                    tooltip: {
                                        enabled: true,
                                        callbacks: {
                                            label: (context) => {
                                                if (context.dataset.label === 'IO wait') {
                                                    return `IO wait: ${Number(context.parsed.y).toFixed(1)}%`;
                                                }
                                                return `Load: ${Number(context.parsed.y).toFixed(2)}`;
                                            }
                                        }
                                    }
                                },
                                scales: {
                                    x: {
                                        ticks: {
                                            color: isDark ? '#9ca3af' : '#6b7280',
                                            autoSkip: true,
                                            maxTicksLimit: 5,
                                            maxRotation: 0,
                                            minRotation: 0,
                                            callback: (value, index) => this.tickLabel(index, 5),
                                        },
                                        grid: { display: false }
                                    },
                                    y: {
                                        beginAtZero: false,
                                        suggestedMin: loadBounds.min,
                                        suggestedMax: Math.max(loadMax, loadBounds.max ?? loadMax),
                                        ticks: { color: isDark ? '#9ca3af' : '#6b7280' },
                                        grid: { color: isDark ? '#374151' : '#f3f4f6' }
                                    },
                                    y1: {
                                        beginAtZero: false,
                                        suggestedMin: ioWaitBounds.min,
                                        suggestedMax: ioWaitBounds.max ?? 100,
                                        position: 'right',
                                        grid: { drawOnChartArea: false },
                                        ticks: {
                                            color: isDark ? '#9ca3af' : '#6b7280',
                                            callback: (value) => `${value}%`,
                                        }
                                    }
                                }
                            }
                        }));
                    },
                    destroy() {
                        const chart = this.getChart();
                        if (chart) {
                            chart.destroy();
                        }
                        if (this.$refs.chart) {
                            this.$refs.chart.__chart = null;
                        }
                    }
                }"
                wire:ignore
            >
                <div class="chart-container">
                    <canvas x-ref="chart"></canvas>
                </div>
            </div>
            <div class="chart-label">
                <x-filament::icon icon="heroicon-o-chart-bar" class="h-5 w-5 text-primary-500" />
                <span class="chart-title">{{ __('Load') }}</span>
            </div>
            <div class="chart-subtitle">{{ $cpuCores }} {{ __('cores') }} · {{ __('Load') }}: {{ $load1 }} / {{ $load5 }} / {{ $load15 }}</div>
        </div>

        {{-- Memory Usage Chart --}}
        <div class="chart-card chart-card--memory">
            <div
                x-data="{
                    labels: @js($historyLabels),
                    series: @js($historyMemory),
                    swapSeries: @js($historySwap),
                    value: {{ $memUsage }},
                    swapValue: {{ $memory['swap_usage'] ?? 0 }},
                    hasSwap: {{ $hasSwap ? 'true' : 'false' }},
                    maxValue: 100,
                    maxPoints: {{ $historyPoints }},
                    intervalSeconds: {{ $historyIntervalSeconds }},
                    labelFormat: @js($historyLabelFormat),
                    init() {
                        if (!this.labels.length || !this.series.length) {
                            this.seedSeries();
                        }
                        this.initChart();
                        const handleRange = (payload) => {
                            const normalized = Array.isArray(payload) ? (payload[0] ?? {}) : (payload ?? {});
                            if (normalized?.label_format) {
                                this.labelFormat = normalized.label_format;
                            }
                            if (normalized?.interval_seconds) {
                                this.intervalSeconds = normalized.interval_seconds;
                            }
                            this.applyHistory(normalized?.history, normalized?.history_points);
                        };
                        const handleUpdate = (payload) => {
                            const normalized = Array.isArray(payload) ? (payload[0] ?? {}) : (payload ?? {});
                            if (normalized?.history) {
                                this.applyHistory(normalized.history, normalized.history_points);
                                return;
                            }
                            const newValue = normalized?.memory;
                            const swapValue = normalized?.swap;
                            const label = normalized?.label ?? null;
                            if (newValue !== undefined) {
                                this.pushPoint(newValue, swapValue, label);
                            }
                        };
                        if (window.Livewire?.on) {
                            window.Livewire.on('server-charts-range-changed', handleRange);
                            window.Livewire.on('server-charts-updated', handleUpdate);
                        }
                        document.addEventListener('server-charts-range-changed', (event) => {
                            handleRange(event?.detail ?? {});
                        });
                        document.addEventListener('server-charts-updated', (event) => {
                            handleUpdate(event?.detail ?? {});
                        });
                    },
                    applyHistory(history, points) {
                        if (!history) {
                            return;
                        }
                        this.labels = history.labels ?? [];
                        this.series = history.memory ?? [];
                        this.swapSeries = history.swap ?? [];
                        if (this.hasSwap && this.swapSeries.length !== this.labels.length) {
                            this.swapSeries = this.labels.map(() => 0);
                        }
                        this.maxPoints = points ?? (this.labels.length || this.maxPoints);
                        this.updateChart();
                    },
                    seedSeries() {
                        const now = new Date();
                        for (let i = this.maxPoints - 1; i >= 0; i--) {
                            const stamp = new Date(now.getTime() - (i * this.intervalSeconds * 1000));
                            this.labels.push(this.formatTime(stamp));
                            this.series.push(this.value);
                            if (this.hasSwap) {
                                this.swapSeries.push(this.swapValue);
                            }
                        }
                    },
                    formatTime(date) {
                        const pad = (value) => String(value).padStart(2, '0');
                        const hours = pad(date.getHours());
                        const minutes = pad(date.getMinutes());
                        const seconds = pad(date.getSeconds());
                        const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
                        const month = months[date.getMonth()];
                        const day = pad(date.getDate());

                        switch (this.labelFormat) {
                            case 'H:i:s':
                                return `${hours}:${minutes}:${seconds}`;
                            case 'H:00':
                                return `${hours}:00`;
                            case 'M d H:00':
                                return `${month} ${day} ${hours}:00`;
                            case 'M d':
                                return `${month} ${day}`;
                            default:
                                return `${hours}:${minutes}:${seconds}`;
                        }
                    },
                    pushPoint(value, swapValue, label) {
                        const nextLabel = label ?? this.formatTime(new Date());
                        const nextSwap = swapValue ?? this.swapValue ?? 0;
                        if (this.labels.length && this.labels[this.labels.length - 1] === nextLabel) {
                            this.series[this.series.length - 1] = value;
                            if (this.hasSwap) {
                                this.swapSeries[this.swapSeries.length - 1] = nextSwap;
                            }
                            this.updateChart();
                            return;
                        }
                        this.series.push(value);
                        this.labels.push(nextLabel);
                        if (this.hasSwap) {
                            this.swapSeries.push(nextSwap);
                        }
                        if (this.series.length > this.maxPoints) {
                            this.series.shift();
                            this.labels.shift();
                            if (this.hasSwap) {
                                this.swapSeries.shift();
                            }
                        }
                        this.updateChart();
                    },
                    axisInterval() {
                        return this.labels.length > 0 ? Math.max(0, Math.floor(this.labels.length / 6)) : 0;
                    },
                    tickStep() {
                        if (!this.labels.length) {
                            return 1;
                        }
                        return Math.max(1, Math.round(this.labels.length / 6));
                    },
                    tickLabel(index, maxTicks = 5) {
                        if (!this.labels.length) {
                            return '';
                        }
                        const step = Math.max(1, Math.ceil(this.labels.length / maxTicks));
                        return index % step === 0 ? (this.labels[index] ?? '') : '';
                    },
                    scaleBounds(series, minDefault = 0, maxDefault = 100, padding = 5) {
                        if (!Array.isArray(series) || series.length === 0) {
                            return { min: minDefault, max: maxDefault };
                        }
                        const values = series.map((value) => Number(value)).filter((value) => Number.isFinite(value));
                        if (!values.length) {
                            return { min: minDefault, max: maxDefault };
                        }
                        const minValue = Math.min(...values);
                        const maxValue = Math.max(...values);
                        const min = Math.max(minDefault ?? minValue, minValue - padding);
                        const max = maxDefault !== null ? Math.min(maxDefault, maxValue + padding) : maxValue + padding;
                        return { min, max };
                    },
                    cloneArray(items) {
                        return Array.isArray(items) ? items.slice() : [];
                    },
                    getChart() {
                        return this.$refs.chart?.__chart ?? null;
                    },
                    setChart(instance) {
                        if (this.$refs.chart) {
                            this.$refs.chart.__chart = instance;
                        }
                    },
                    updateChart() {
                        const chart = this.getChart();
                        if (!chart) {
                            return;
                        }
                        const value = this.series[this.series.length - 1];
                        const color = value >= 90 ? '#ef4444' : (value >= 70 ? '#f59e0b' : '#22c55e');
                        const areaColor = value >= 90 ? 'rgba(239,68,68,0.15)' : (value >= 70 ? 'rgba(245,158,11,0.15)' : 'rgba(34,197,94,0.15)');
                        const memoryBounds = this.scaleBounds(this.series, 0, 100, 5);
                        const swapBounds = this.scaleBounds(this.swapSeries, 0, 100, 5);
                        chart.data.labels = this.cloneArray(this.labels);
                        chart.data.datasets[0].data = this.cloneArray(this.series);
                        chart.data.datasets[0].borderColor = color;
                        chart.data.datasets[0].backgroundColor = areaColor;
                        if (this.hasSwap && chart.data.datasets[1]) {
                            chart.data.datasets[1].data = this.cloneArray(this.swapSeries);
                        }
                        if (chart.options?.scales?.y) {
                            chart.options.scales.y.suggestedMin = memoryBounds.min;
                            chart.options.scales.y.suggestedMax = memoryBounds.max ?? 100;
                        }
                        if (chart.options?.scales?.y1) {
                            chart.options.scales.y1.suggestedMin = swapBounds.min;
                            chart.options.scales.y1.suggestedMax = swapBounds.max ?? 100;
                        }
                        chart.update('none');
                    },
                    initChart() {
                        if (typeof window.Chart === 'undefined') {
                            setTimeout(() => this.initChart(), 100);
                            return;
                        }
                        const isDark = document.documentElement.classList.contains('dark');
                        const color = this.value >= 90 ? '#ef4444' : (this.value >= 70 ? '#f59e0b' : '#22c55e');
                        const areaColor = this.value >= 90 ? 'rgba(239,68,68,0.15)' : (this.value >= 70 ? 'rgba(245,158,11,0.15)' : 'rgba(34,197,94,0.15)');
                        const ctx = this.$refs.chart.getContext('2d');
                        const memoryBounds = this.scaleBounds(this.series, 0, 100, 5);
                        const swapBounds = this.scaleBounds(this.swapSeries, 0, 100, 5);
                        const datasets = [
                            {
                                label: 'Memory',
                                data: this.series,
                                tension: 0.35,
                                borderColor: color,
                                backgroundColor: areaColor,
                                fill: false,
                                yAxisID: 'y',
                                pointRadius: 2,
                                pointHoverRadius: 3,
                            }
                        ];
                        if (this.hasSwap) {
                            datasets.push({
                                label: 'Swap',
                                data: this.swapSeries,
                                tension: 0.35,
                                borderColor: '#3b82f6',
                                backgroundColor: 'rgba(59,130,246,0.12)',
                                borderDash: [6, 4],
                                fill: false,
                                yAxisID: 'y1',
                                pointRadius: 2,
                                pointHoverRadius: 3,
                            });
                        }
                        this.setChart(new Chart(ctx, {
                            type: 'line',
                            data: {
                                labels: this.cloneArray(this.labels),
                                datasets
                            },
                            options: {
                                responsive: true,
                                maintainAspectRatio: false,
                                interaction: { mode: 'index', intersect: false },
                                plugins: {
                                    legend: { display: false },
                                    tooltip: {
                                        enabled: true,
                                        callbacks: {
                                            label: (context) => {
                                                if (context.dataset.label === 'Swap') {
                                                    return `Swap: ${Number(context.parsed.y).toFixed(1)}%`;
                                                }
                                                return `Memory: ${Number(context.parsed.y).toFixed(1)}%`;
                                            }
                                        }
                                    }
                                },
                                scales: {
                                    x: {
                                        ticks: {
                                            color: isDark ? '#9ca3af' : '#6b7280',
                                            autoSkip: true,
                                            maxTicksLimit: 5,
                                            maxRotation: 0,
                                            minRotation: 0,
                                            callback: (value, index) => this.tickLabel(index, 5),
                                        },
                                        grid: { display: false }
                                    },
                                    y: {
                                        beginAtZero: false,
                                        suggestedMin: memoryBounds.min,
                                        suggestedMax: memoryBounds.max ?? 100,
                                        ticks: { color: isDark ? '#9ca3af' : '#6b7280' },
                                        grid: { color: isDark ? '#374151' : '#f3f4f6' }
                                    },
                                    y1: {
                                        beginAtZero: false,
                                        suggestedMin: swapBounds.min,
                                        suggestedMax: swapBounds.max ?? 100,
                                        position: 'right',
                                        grid: { drawOnChartArea: false },
                                        ticks: {
                                            color: isDark ? '#9ca3af' : '#6b7280',
                                            callback: (value) => `${value}%`,
                                        }
                                    }
                                }
                            }
                        }));
                    },
                    destroy() {
                        const chart = this.getChart();
                        if (chart) {
                            chart.destroy();
                        }
                        if (this.$refs.chart) {
                            this.$refs.chart.__chart = null;
                        }
                    }
                }"
                wire:ignore
            >
                <div class="chart-container">
                    <canvas x-ref="chart"></canvas>
                </div>
            </div>
            <div class="chart-label">
                <x-filament::icon icon="heroicon-o-server" class="h-5 w-5 text-info-500" />
                <span class="chart-title">{{ __('Memory') }}</span>
            </div>
            <div class="chart-subtitle">
                {{ number_format($memUsedGB, 1) }} GB {{ __('used') }} / {{ number_format($memTotalGB, 1) }} GB {{ __('total') }}
                @if($hasSwap)
                    · {{ __('Swap') }} {{ number_format($swapUsedGB, 1) }} GB / {{ number_format($swapTotalGB, 1) }} GB
                @endif
            </div>
        </div>

        {{-- Disk Usage Chart --}}
        @if(!empty($diskMounts))
            <div class="chart-card chart-card--disk">
                <div
                    x-data="{
                        mounts: @js($diskMounts),
                        usedSeries: @js($diskUsedSeries),
                        freeSeries: @js($diskFreeSeries),
                        totals: @js($diskTotals),
                        labels: {
                            used: @js(__('used')),
                            free: @js(__('free')),
                            total: @js(__('total')),
                        },
                        init() {
                            this.initChart();
                        },
                        withOpacity(color, opacity) {
                            const hex = color.replace('#', '');
                            const bigint = parseInt(hex, 16);
                            const r = (bigint >> 16) & 255;
                            const g = (bigint >> 8) & 255;
                            const b = bigint & 255;
                            return `rgba(${r}, ${g}, ${b}, ${opacity})`;
                        },
                        cloneArray(items) {
                            return Array.isArray(items) ? items.slice() : [];
                        },
                        getChart() {
                            return this.$refs.chart?.__chart ?? null;
                        },
                        setChart(instance) {
                            if (this.$refs.chart) {
                                this.$refs.chart.__chart = instance;
                            }
                        },
                        initChart() {
                            if (typeof window.Chart === 'undefined') {
                                setTimeout(() => this.initChart(), 100);
                                return;
                            }
                            const isDark = document.documentElement.classList.contains('dark');
                            const ctx = this.$refs.chart.getContext('2d');
                            this.setChart(new Chart(ctx, {
                                type: 'bar',
                                data: {
                                    labels: this.cloneArray(this.mounts),
                                    datasets: [
                                        {
                                            label: 'Used',
                                            data: this.cloneArray(this.usedSeries),
                                            backgroundColor: '#f59e0b',
                                            stack: 'disk',
                                            borderWidth: 0,
                                        },
                                        {
                                            label: 'Free',
                                            data: this.cloneArray(this.freeSeries),
                                            backgroundColor: this.withOpacity('#22c55e', 0.35),
                                            stack: 'disk',
                                            borderWidth: 0,
                                        }
                                    ]
                                },
                                options: {
                                    responsive: true,
                                    maintainAspectRatio: false,
                                    interaction: { mode: 'index', intersect: false },
                                plugins: {
                                    legend: { display: false },
                                    tooltip: {
                                        enabled: true,
                                        callbacks: {
                                            label: (context) => {
                                                const mount = context.label ?? '';
                                                    const used = Number(this.usedSeries[context.dataIndex] ?? 0);
                                                    const free = Number(this.freeSeries[context.dataIndex] ?? 0);
                                                    const total = Number(this.totals[mount] ?? (used + free));
                                                    if (context.dataset.label === 'Used') {
                                                        return `Used: ${used.toFixed(2)} GB`;
                                                    }
                                                    if (context.dataset.label === 'Free') {
                                                        return `Free: ${free.toFixed(2)} GB`;
                                                    }
                                                    return `Total: ${total.toFixed(2)} GB`;
                                                },
                                                afterBody: (items) => {
                                                    const index = items?.[0]?.dataIndex ?? 0;
                                                    const mount = items?.[0]?.label ?? '';
                                                    const used = Number(this.usedSeries[index] ?? 0);
                                                    const free = Number(this.freeSeries[index] ?? 0);
                                                    const total = Number(this.totals[mount] ?? (used + free));
                                                    return `Total: ${total.toFixed(2)} GB`;
                                                }
                                            }
                                        }
                                    },
                                    scales: {
                                        x: {
                                            stacked: true,
                                            ticks: { color: isDark ? '#9ca3af' : '#6b7280', fontSize: 10 },
                                            grid: { display: false }
                                        },
                                    y: {
                                        stacked: true,
                                        beginAtZero: true,
                                        ticks: {
                                            color: isDark ? '#9ca3af' : '#6b7280',
                                            callback: (value) => `${value} GB`
                                        },
                                        grid: { color: isDark ? '#374151' : '#f3f4f6' }
                                    }
                                }
                            }
                            }));
                        },
                        destroy() {
                            const chart = this.getChart();
                            if (chart) {
                                chart.destroy();
                            }
                            if (this.$refs.chart) {
                                this.$refs.chart.__chart = null;
                            }
                        }
                    }"
                    wire:ignore
                >
                    <div class="chart-container">
                        <canvas x-ref="chart"></canvas>
                    </div>
                </div>
                <div class="chart-label">
                    <x-filament::icon icon="heroicon-o-circle-stack" class="h-5 w-5 text-warning-500" />
                    <span class="chart-title">{{ __('Disk Usage') }}</span>
                </div>
                <div class="chart-subtitle">{{ number_format($diskUsedTotalGB, 1) }} GB {{ __('used') }} / {{ number_format($diskTotalGB, 1) }} GB {{ __('total') }}</div>
            </div>
        @endif
    </div>

</x-filament-widgets::widget>
