<?php
/** @var array  $user */
/** @var array  $tenant */
/** @var string $anchorDate */
/** @var string $from */
/** @var string $to */
/** @var array  $kpi */
/** @var array  $dailyIncidents */
/** @var array  $monthlyIncidents */
/** @var array  $monthCategoryContribution */
/** @var array  $yearCategoryContribution */
/** @var array  $monthTop5 */
/** @var array  $yearTop5 */
/** @var array  $readings */
/** @var array  $genHours */
/** @var array  $reliability */
/** @var string $dashboardMode  'exec' or 'client' */
$mode = $dashboardMode ?? 'exec';

// Bundle initial data so Vue can seed itself without a second HTTP hit on first paint.
$initial = [
    'anchorDate'                => $anchorDate,
    'from'                      => $from,
    'to'                        => $to,
    'kpi'                       => $kpi,
    'dailyIncidents'            => $dailyIncidents,
    'monthlyIncidents'          => $monthlyIncidents,
    'monthCategoryContribution' => $monthCategoryContribution,
    'yearCategoryContribution'  => $yearCategoryContribution,
    'monthTop5'                 => $monthTop5,
    'yearTop5'                  => $yearTop5,
    'readings'                  => $readings,
    'genHours'                  => $genHours,
    'reliability'               => $reliability ?? [
        'window_hours' => 0, 'failures' => 0, 'mtbf_hours' => null,
        'mttr_minutes' => null, 'availability' => null, 'top_codes' => [],
    ],
    'roundsToday'               => $roundsToday ?? ['total' => 0, 'overdue' => 0, 'never_run' => 0, 'on_time' => 0],
    'hseTraining'               => $hseTraining ?? ['total' => 0, 'expired' => 0, 'expiring_soon' => 0, 'valid' => 0],
    'hseSds'                    => $hseSds      ?? ['total' => 0, 'overdue' => 0, 'due_soon' => 0, 'no_review_date' => 0],
];
?>

<div id="execDashboard" v-cloak>
    <!-- ── Header + date-range filter (Vue owns state) ──────────── -->
    <div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
        <h5 class="fw-bold mb-0">
            <i class="fas fa-tachometer-alt me-2 text-primary"></i>
            <?= $mode === 'client' ? 'Client Portal — Executive Dashboard' : 'Dashboard, Executive' ?>
        </h5>
        <div class="d-flex align-items-end gap-2 flex-wrap">
            <div>
                <label class="form-label small mb-0">From</label>
                <input type="date" v-model="from" class="form-control form-control-sm" style="width: 150px;">
            </div>
            <div>
                <label class="form-label small mb-0">To</label>
                <input type="date" v-model="to" class="form-control form-control-sm" style="width: 150px;">
            </div>
            <button class="btn btn-sm btn-primary" @click="applyRange" :disabled="loading">
                <i class="fas fa-filter me-1"></i>
                <span v-if="!loading">Apply</span>
                <span v-else>Loading…</span>
            </button>
            <button class="btn btn-sm btn-outline-secondary" @click="resetRange" :disabled="loading">
                <i class="fas fa-rotate-left me-1"></i>Reset
            </button>
            <div class="btn-group btn-group-sm ms-1" role="group">
                <button class="btn btn-outline-secondary" @click="quickRange(7)"   :disabled="loading">7d</button>
                <button class="btn btn-outline-secondary" @click="quickRange(30)"  :disabled="loading">30d</button>
                <button class="btn btn-outline-secondary" @click="quickRange(90)"  :disabled="loading">90d</button>
                <button class="btn btn-outline-secondary" @click="quickRange(365)" :disabled="loading">1y</button>
            </div>
            <span class="small ms-2 text-danger" v-if="error">{{ error }}</span>
        </div>
    </div>

    <p class="small text-muted">
        Anchored to latest data: <strong>{{ anchorDate }}</strong>
        · Showing <strong>{{ from }}</strong> → <strong>{{ to }}</strong>
    </p>

    <!-- ── KPI Summary Table (bound to Vue state) ─────────────── -->
    <div class="rs-card p-0 mb-3" style="background:#e8f1fa;">
        <table class="table table-sm mb-0 align-middle text-center kpi-table">
            <thead class="table-primary">
                <tr>
                    <th style="width: 60px;">Sn</th>
                    <th class="text-start">Period</th>
                    <th>No of Incidents</th>
                    <th>No. of Equipment Incidents</th>
                    <th>No. of External Incidents</th>
                    <th>No. of H &amp; S Incidents</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>1</td><td class="text-start fw-bold">Today's Summary</td>
                    <td>{{ kpi.today.total.toFixed(2) }}</td>
                    <td>{{ kpi.today.equipment.toFixed(2) }}</td>
                    <td>{{ kpi.today.external.toFixed(2) }}</td>
                    <td>{{ kpi.today.health_safety.toFixed(2) }}</td>
                </tr>
                <tr>
                    <td>2</td><td class="text-start fw-bold">Current Week's Summary</td>
                    <td>{{ kpi.week.total.toFixed(2) }}</td>
                    <td>{{ kpi.week.equipment.toFixed(2) }}</td>
                    <td>{{ kpi.week.external.toFixed(2) }}</td>
                    <td>{{ kpi.week.health_safety.toFixed(2) }}</td>
                </tr>
                <tr>
                    <td>3</td><td class="text-start fw-bold">Current Month's Summary</td>
                    <td>{{ kpi.month.total.toFixed(2) }}</td>
                    <td>{{ kpi.month.equipment.toFixed(2) }}</td>
                    <td>{{ kpi.month.external.toFixed(2) }}</td>
                    <td>{{ kpi.month.health_safety.toFixed(2) }}</td>
                </tr>
            </tbody>
        </table>
    </div>

    <!-- ── Reliability strip (MTBF/MTTR/Availability + top failure codes) ── -->
    <div class="row g-3 mb-3">
        <div class="col-md-3"><div class="rs-card p-3 h-100 text-center">
            <div class="text-muted small text-uppercase">MTBF</div>
            <div class="fw-bold fs-4">{{ fmtMtbf(reliability.mtbf_hours) }}</div>
            <div class="text-muted small">mean time between equipment failures</div>
        </div></div>
        <div class="col-md-3"><div class="rs-card p-3 h-100 text-center">
            <div class="text-muted small text-uppercase">MTTR</div>
            <div class="fw-bold fs-4">{{ fmtMttr(reliability.mttr_minutes) }}</div>
            <div class="text-muted small">mean time to repair</div>
        </div></div>
        <div class="col-md-3"><div class="rs-card p-3 h-100 text-center">
            <div class="text-muted small text-uppercase">Availability</div>
            <div class="fw-bold fs-4" :class="availClass(reliability.availability)">
                {{ reliability.availability !== null ? reliability.availability + '%' : '—' }}
            </div>
            <div class="text-muted small">window uptime</div>
        </div></div>
        <div class="col-md-3"><div class="rs-card p-3 h-100 text-center">
            <div class="text-muted small text-uppercase">Failures (window)</div>
            <div class="fw-bold fs-4 text-danger">{{ reliability.failures }}</div>
            <div class="text-muted small">equipment incidents</div>
        </div></div>
    </div>

    <!-- ── Rounds compliance today (drills into /Rounds) ────────────── -->
    <a href="<?= url('/Rounds') ?>" class="text-decoration-none">
    <div class="rs-card p-3 mb-3" :style="roundsTodayBarStyle()">
        <div class="d-flex justify-content-between align-items-center">
            <h6 class="fw-bold mb-0 text-dark"><i class="fas fa-route me-1 text-primary"></i>Rounds today</h6>
            <span class="small text-muted">click to open →</span>
        </div>
        <div class="row g-2 mt-1">
            <div class="col text-center">
                <div class="fs-5 fw-bold text-dark">{{ roundsToday.total }}</div>
                <div class="small text-muted">active</div>
            </div>
            <div class="col text-center">
                <div class="fs-5 fw-bold text-danger">{{ roundsToday.overdue }}</div>
                <div class="small text-muted">overdue</div>
            </div>
            <div class="col text-center">
                <div class="fs-5 fw-bold text-warning">{{ roundsToday.never_run }}</div>
                <div class="small text-muted">never run</div>
            </div>
            <div class="col text-center">
                <div class="fs-5 fw-bold text-success">{{ roundsToday.on_time }}</div>
                <div class="small text-muted">on time</div>
            </div>
        </div>
    </div>
    </a>

    <!-- ── HSE compliance (drills into /Hse) ────────────────────────── -->
    <a href="<?= url('/Hse') ?>" class="text-decoration-none">
    <div class="rs-card p-3 mb-3" :style="hseBarStyle()">
        <div class="d-flex justify-content-between align-items-center">
            <h6 class="fw-bold mb-0 text-dark"><i class="fas fa-shield-heart me-1 text-primary"></i>HSE compliance</h6>
            <span class="small text-muted">click to open →</span>
        </div>
        <div class="row g-2 mt-1">
            <div class="col text-center">
                <div class="small text-muted">Training expired</div>
                <div class="fs-5 fw-bold text-danger">{{ hseTraining.expired }}</div>
            </div>
            <div class="col text-center">
                <div class="small text-muted">Training ≤ 60d</div>
                <div class="fs-5 fw-bold text-warning">{{ hseTraining.expiring_soon }}</div>
            </div>
            <div class="col text-center">
                <div class="small text-muted">SDS review overdue</div>
                <div class="fs-5 fw-bold text-danger">{{ hseSds.overdue }}</div>
            </div>
            <div class="col text-center">
                <div class="small text-muted">SDS review ≤ 60d</div>
                <div class="fs-5 fw-bold text-warning">{{ hseSds.due_soon }}</div>
            </div>
        </div>
    </div>
    </a>

    <div class="rs-card p-3 mb-3">
        <h6 class="fw-bold mb-2"><i class="fas fa-triangle-exclamation me-1 text-warning"></i>Top Failure Codes (window)</h6>
        <template v-if="reliability.top_codes.length">
            <table class="table table-sm mb-0 align-middle">
                <thead><tr><th style="width:80px;">Code</th><th>Mode</th><th class="text-end">Count</th><th class="text-end">Avg downtime (min)</th></tr></thead>
                <tbody>
                    <tr v-for="c in reliability.top_codes" :key="c.code">
                        <td><code class="small">{{ c.code }}</code></td>
                        <td class="small">{{ c.mode }}</td>
                        <td class="text-end"><strong>{{ c.n }}</strong></td>
                        <td class="text-end small">{{ c.avg_dt !== null ? c.avg_dt : '—' }}</td>
                    </tr>
                </tbody>
            </table>
        </template>
        <p v-else class="text-muted small mb-0">No incidents classified with a failure code in this window.</p>
    </div>

    <!-- ── Chart mount points (Vue re-renders these on data change) -->
    <div class="rs-card mb-3">
        <div class="p-3 border-bottom"><h6 class="fw-bold mb-0">Daily Incident Trend</h6></div>
        <div class="p-3"><div id="chartDailyIncidents" style="height:340px;"></div></div>
    </div>

    <div class="rs-card mb-3">
        <div class="p-3 border-bottom"><h6 class="fw-bold mb-0">Monthly Incident Trend</h6></div>
        <div class="p-3"><div id="chartMonthlyIncidents" style="height:340px;"></div></div>
    </div>

    <div class="row g-3 mb-3">
        <div class="col-md-6">
            <div class="rs-card">
                <div class="p-3 border-bottom"><h6 class="fw-bold mb-0">Current Month Incident Type Contribution</h6></div>
                <div class="p-3"><div id="chartMonthCategory" style="height:340px;"></div></div>
            </div>
        </div>
        <div class="col-md-6">
            <div class="rs-card">
                <div class="p-3 border-bottom"><h6 class="fw-bold mb-0">Current Year Incident Type Contribution</h6></div>
                <div class="p-3"><div id="chartYearCategory" style="height:340px;"></div></div>
            </div>
        </div>
    </div>

    <div class="row g-3 mb-3">
        <div class="col-md-6">
            <div class="rs-card">
                <div class="p-3 border-bottom"><h6 class="fw-bold mb-0">Current Month Top 5 Failed Equipments</h6></div>
                <div class="p-3"><div id="chartMonthTop5" style="height:320px;"></div></div>
            </div>
        </div>
        <div class="col-md-6">
            <div class="rs-card">
                <div class="p-3 border-bottom"><h6 class="fw-bold mb-0">Current Year Top 5 Failed Equipments</h6></div>
                <div class="p-3"><div id="chartYearTop5" style="height:320px;"></div></div>
            </div>
        </div>
    </div>

    <div class="rs-card mb-3">
        <div class="p-3 border-bottom"><h6 class="fw-bold mb-0">Monthly Avg. Voltages</h6></div>
        <div class="p-3"><div id="chartVoltages" style="height:360px;"></div></div>
    </div>

    <div class="rs-card mb-3">
        <div class="p-3 border-bottom"><h6 class="fw-bold mb-0">Monthly Avg. kW, VArs, VAs</h6></div>
        <div class="p-3"><div id="chartPower" style="height:380px;"></div></div>
    </div>

    <div class="rs-card mb-3">
        <div class="p-3 border-bottom"><h6 class="fw-bold mb-0">Monthly Avg. Currents (A)</h6></div>
        <div class="p-3"><div id="chartCurrents" style="height:340px;"></div></div>
    </div>

    <div class="rs-card mb-3">
        <div class="p-3 border-bottom"><h6 class="fw-bold mb-0">Monthly Generator Hrs</h6></div>
        <div class="p-3"><div id="chartGenHours" style="height:320px;"></div></div>
    </div>
</div>

<?php if ($mode !== 'client'): ?>
<!-- Exec-only tables (client portal keeps its own lists elsewhere). -->
<div class="row g-3">
    <div class="col-lg-6"><div class="rs-card p-3">
        <h6 class="fw-bold mb-3"><i class="fas fa-triangle-exclamation me-1 text-danger"></i>Open Incidents</h6>
        <?php if (empty($openIncidents ?? [])): ?><p class="text-muted small mb-0">Nothing open.</p><?php else: ?>
            <table class="table table-sm table-hover mb-0">
                <thead><tr><th>Title</th><th>Severity</th><th>Asset</th></tr></thead>
                <tbody>
                    <?php foreach (array_slice($openIncidents, 0, 8) as $i): ?>
                        <tr>
                            <td><a href="<?= url('/Incidents/show/' . (int) $i['incident_id']) ?>" class="text-decoration-none"><?= e($i['title']) ?></a></td>
                            <td><span class="badge bg-secondary text-uppercase"><?= e($i['severity']) ?></span></td>
                            <td class="small text-muted"><?= e($i['asset_name'] ?? '—') ?></td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
        <?php endif; ?>
    </div></div>
    <div class="col-lg-6"><div class="rs-card p-3">
        <h6 class="fw-bold mb-3"><i class="fas fa-clipboard-check me-1 text-primary"></i>Work Orders In Progress</h6>
        <?php if (empty($openWos ?? [])): ?><p class="text-muted small mb-0">Nothing in progress.</p><?php else: ?>
            <table class="table table-sm table-hover mb-0">
                <thead><tr><th>Title</th><th>Priority</th><th>Assigned</th><th>Due</th></tr></thead>
                <tbody>
                    <?php foreach (array_slice($openWos, 0, 8) as $w): ?>
                        <tr>
                            <td><a href="<?= url('/WorkOrders/show/' . (int) $w['work_order_id']) ?>" class="text-decoration-none"><?= e($w['title']) ?></a></td>
                            <td><span class="badge bg-secondary text-uppercase"><?= e($w['priority']) ?></span></td>
                            <td class="small text-muted"><?= e($w['assigned_username'] ?? '—') ?></td>
                            <td class="small text-muted"><?= e($w['due_at'] ?? '—') ?></td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
        <?php endif; ?>
    </div></div>
</div>
<?php endif; ?>

<?php $this->start('scripts'); ?>
<script src="https://cdn.jsdelivr.net/npm/apexcharts@3.53.0/dist/apexcharts.min.js"></script>
<script>
(function () {
    // Palette (matches legacy).
    const PINK = '#e91e63';
    const CAT_COLORS = { equipment: '#22c55e', external: '#f59e0b', health_safety: '#e91e63' };
    const CAT_LABELS = { equipment: 'EQUIPMENT', external: 'EXTERNAL', health_safety: 'H & S' };
    const PHASE_COLORS = ['#ef4444', '#eab308', '#3b82f6']; // L1 red, L2 yellow, L3 blue

    // AJAX endpoint for Vue-driven re-fetch on filter change. The URL flips
    // between the exec and client-portal endpoints depending on which route
    // is rendering the shared view.
    const dataUrl = '<?= url($mode === 'client' ? '/ClientPortal/data' : '/Home/data') ?>';

    // Initial payload seeded from PHP so first paint doesn't need an extra hit.
    const initial = <?= json_encode($initial, JSON_UNESCAPED_UNICODE) ?>;

    function unionMonths(seriesMap) {
        const set = new Set();
        Object.values(seriesMap || {}).forEach(list => list.forEach(row => set.add(row.m)));
        return [...set].sort();
    }
    function alignSeries(months, seriesMap, keys) {
        return keys.map(k => {
            const rows = (seriesMap && seriesMap[k]) || [];
            const map  = Object.fromEntries(rows.map(r => [r.m, r.v]));
            return months.map(m => map[m] === undefined ? null : Number(map[m]));
        });
    }

    // Build the 10 ApexCharts config objects from a state snapshot.
    function buildConfigs(state) {
        const c = {};

        c.chartDailyIncidents = {
            chart: { type: 'bar', height: 340, toolbar: { show: false }, animations: { enabled: true, speed: 300 } },
            series: [{ name: 'No. of Incidents', data: state.dailyIncidents.map(r => Number(r.n)) }],
            xaxis:  { categories: state.dailyIncidents.map(r => r.d), labels: { rotate: -60, style: { fontSize: '9px' } } },
            title:  { text: 'Daily Incidents Trend', align: 'center' },
            colors: [PINK],
            plotOptions: { bar: { columnWidth: '35%' } },
            dataLabels: { enabled: false },
            grid: { borderColor: '#eee' },
            noData: { text: '(no daily incidents in range)' },
        };

        c.chartMonthlyIncidents = {
            chart: { type: 'bar', height: 340, toolbar: { show: false } },
            series: [{ name: 'No. of Incidents', data: state.monthlyIncidents.map(r => Number(r.n)) }],
            xaxis:  { categories: state.monthlyIncidents.map(r => r.m) },
            title:  { text: 'Monthly Incidents Trend', align: 'center' },
            colors: [PINK],
            plotOptions: { bar: { columnWidth: '50%' } },
            dataLabels: { enabled: false },
            grid: { borderColor: '#eee' },
            noData: { text: '(no monthly incidents in range)' },
        };

        const pieCfg = (rows) => {
            const has = rows && rows.length;
            return {
                chart: { type: 'pie', height: 340 },
                series: has ? rows.map(r => Number(r.n)) : [1],
                labels: has ? rows.map(r => CAT_LABELS[r.category] || String(r.category).toUpperCase()) : ['no data'],
                colors: has ? rows.map(r => CAT_COLORS[r.category] || '#64748b') : ['#e5e7eb'],
                title:  { text: 'Daily Incidents', align: 'center' },
                legend: { position: 'top' },
            };
        };
        c.chartMonthCategory = pieCfg(state.monthCategoryContribution);
        c.chartYearCategory  = pieCfg(state.yearCategoryContribution);

        const top5Cfg = (rows, titleText) => ({
            chart: { type: 'bar', height: 320, toolbar: { show: false } },
            series: [{ name: 'No. of Incidents', data: rows.map(r => Number(r.n)) }],
            xaxis:  { categories: rows.map(r => r.name), labels: { rotate: -25, style: { fontSize: '10px' } } },
            title:  { text: titleText, align: 'center' },
            colors: [PINK],
            plotOptions: { bar: { columnWidth: '55%' } },
            dataLabels: { enabled: false },
            grid: { borderColor: '#eee' },
            noData: { text: '(no equipment failures in range)' },
        });
        c.chartMonthTop5 = top5Cfg(state.monthTop5, 'Current Month Equipment Incidents:');
        c.chartYearTop5  = top5Cfg(state.yearTop5,  'Current Year Equipment Incidents:');

        // Voltages — 6 series, 3 solid + 3 dashed
        {
            const keys = ['v_l_1','v_l_2','v_l_3','v_l_12','v_l_23','v_l_31'];
            const months = unionMonths(state.readings.voltage);
            const series = alignSeries(months, state.readings.voltage, keys);
            const labels = ['Avg. Voltage L1','Avg. Voltage L2','Avg. Voltage L3','Avg. Voltage L1-L2','Avg. Voltage L2-L3','Avg. Voltage L3-L1'];
            c.chartVoltages = months.length ? {
                chart:  { type: 'line', height: 360, toolbar: { show: false } },
                series: series.map((data, i) => ({ name: labels[i], data })),
                xaxis:  { categories: months },
                yaxis:  { title: { text: 'Voltage (V)' } },
                title:  { text: 'Monthly Average Voltage Profile', align: 'center' },
                colors: [PHASE_COLORS[0], PHASE_COLORS[1], PHASE_COLORS[2], PHASE_COLORS[0], PHASE_COLORS[1], PHASE_COLORS[2]],
                stroke: { curve: 'smooth', width: [3,3,3,2,2,2], dashArray: [0,0,0,6,6,6] },
                markers:{ size: 4 },
                legend: { position: 'top' },
                grid:   { borderColor: '#eee' },
            } : null;
        }

        // Power — 9 series (kW solid, kVAr dashed, kVA dotted)
        {
            const kwKeys   = ['kw_l_1','kw_l_2','kw_l_3'];
            const kvarKeys = ['kvar_l_1','kvar_l_2','kvar_l_3'];
            const kvaKeys  = ['kva_l_1','kva_l_2','kva_l_3'];
            const months = unionMonths({
                ...state.readings.power_kw, ...state.readings.power_kvar, ...state.readings.power_kva,
            });
            if (months.length) {
                const kw   = alignSeries(months, state.readings.power_kw,   kwKeys);
                const kvar = alignSeries(months, state.readings.power_kvar, kvarKeys);
                const kva  = alignSeries(months, state.readings.power_kva,  kvaKeys);
                c.chartPower = {
                    chart:  { type: 'line', height: 380, toolbar: { show: false } },
                    series: [
                        { name: 'Avg. kW L1',   data: kw[0]   },
                        { name: 'Avg. kW L2',   data: kw[1]   },
                        { name: 'Avg. kW L3',   data: kw[2]   },
                        { name: 'Avg. kVAr L1', data: kvar[0] },
                        { name: 'Avg. kVAr L2', data: kvar[1] },
                        { name: 'Avg. kVAr L3', data: kvar[2] },
                        { name: 'Avg. kVA L1',  data: kva[0]  },
                        { name: 'Avg. kVA L2',  data: kva[1]  },
                        { name: 'Avg. kVA L3',  data: kva[2]  },
                    ],
                    xaxis:  { categories: months },
                    yaxis:  { title: { text: 'Value (kW / kVAr / kVA)' } },
                    title:  { text: 'Monthly Average Power Parameters', align: 'center' },
                    colors: [PHASE_COLORS[0], PHASE_COLORS[1], PHASE_COLORS[2],
                             PHASE_COLORS[0], PHASE_COLORS[1], PHASE_COLORS[2],
                             PHASE_COLORS[0], PHASE_COLORS[1], PHASE_COLORS[2]],
                    stroke: { curve: 'smooth', width: [3,3,3,2,2,2,2,2,2], dashArray: [0,0,0,6,6,6,3,3,3] },
                    markers:{ size: 3 },
                    legend: { position: 'top' },
                    grid:   { borderColor: '#eee' },
                };
            } else {
                c.chartPower = null;
            }
        }

        // Currents
        {
            const keys = ['a_1','a_2','a_3'];
            const months = unionMonths(state.readings.current);
            const series = alignSeries(months, state.readings.current, keys);
            c.chartCurrents = months.length ? {
                chart:  { type: 'line', height: 340, toolbar: { show: false } },
                series: [
                    { name: 'Avg. Current L1 (A)', data: series[0] },
                    { name: 'Avg. Current L2 (A)', data: series[1] },
                    { name: 'Avg. Current L3 (A)', data: series[2] },
                ],
                xaxis:  { categories: months },
                yaxis:  { title: { text: 'Current (A)' } },
                colors: PHASE_COLORS,
                stroke: { curve: 'smooth', width: 3 },
                markers:{ size: 4 },
                legend: { position: 'top' },
                grid:   { borderColor: '#eee' },
            } : null;
        }

        // Generator hours (area)
        c.chartGenHours = state.genHours.length ? {
            chart:  { type: 'area', height: 320, toolbar: { show: false } },
            series: [{ name: 'Generator Meter Reading (Hrs)', data: state.genHours.map(r => Number(r.hrs)) }],
            xaxis:  { categories: state.genHours.map(r => r.m) },
            yaxis:  { title: { text: 'Accumulated Hours' }, labels: { formatter: (v) => v + ' hrs' } },
            colors: ['#3da5d9'],
            fill:   { type: 'gradient', gradient: { shadeIntensity: 1, opacityFrom: 0.35, opacityTo: 0.05 } },
            stroke: { curve: 'straight', width: 2 },
            markers:{ size: 5 },
            legend: { position: 'top' },
            grid:   { borderColor: '#eee' },
        } : null;

        return c;
    }

    // ── Vue 3 app (Options API) ───────────────────────────────
    const { createApp } = Vue;
    createApp({
        data() {
            return {
                anchorDate:  initial.anchorDate,
                from:        initial.from,
                to:          initial.to,
                kpi:         initial.kpi,
                reliability: initial.reliability,
                roundsToday: initial.roundsToday,
                hseTraining: initial.hseTraining,
                hseSds:      initial.hseSds,
                stats:       initial,
                charts:      {},
                loading:     false,
                error:       null,
            };
        },
        mounted() {
            this.$nextTick(() => this.renderAllCharts());
        },
        beforeUnmount() {
            this.destroyCharts();
        },
        methods: {
            // Left-edge accent bar: red if any round is overdue, amber if
            // any have never run, green otherwise.
            roundsTodayBarStyle() {
                const r = this.roundsToday || {};
                let color = '#22c55e';
                if ((r.overdue   || 0) > 0) color = '#ef4444';
                else if ((r.never_run || 0) > 0) color = '#f59e0b';
                return { borderLeft: '4px solid ' + color };
            },
            // Same accent-bar treatment for the HSE tile — red on any expired
            // cert or overdue SDS review, amber on anything expiring soon.
            hseBarStyle() {
                const t = this.hseTraining || {}, s = this.hseSds || {};
                let color = '#22c55e';
                if ((t.expired || 0) > 0 || (s.overdue || 0) > 0) color = '#ef4444';
                else if ((t.expiring_soon || 0) > 0 || (s.due_soon || 0) > 0) color = '#f59e0b';
                return { borderLeft: '4px solid ' + color };
            },
            fmtMtbf(h) {
                if (h === null || h === undefined) return '—';
                if (h >= 168) return (h / 168).toFixed(1) + ' wk';
                if (h >= 24)  return (h / 24 ).toFixed(1) + ' d';
                return h.toFixed(1) + ' h';
            },
            fmtMttr(m) {
                if (m === null || m === undefined) return '—';
                if (m >= 60) return (m / 60).toFixed(1) + ' h';
                return m.toFixed(0) + ' m';
            },
            availClass(a) {
                if (a === null || a === undefined) return 'text-muted';
                if (a >= 99) return 'text-success';
                if (a >= 95) return 'text-primary';
                if (a >= 90) return 'text-warning';
                return 'text-danger';
            },
            destroyCharts() {
                for (const id in this.charts) {
                    try { this.charts[id].destroy(); } catch (_) {}
                }
                this.charts = {};
            },
            renderAllCharts() {
                this.destroyCharts();
                const configs = buildConfigs(this.stats);
                for (const id in configs) {
                    const el = document.getElementById(id);
                    if (!el) continue;
                    if (!configs[id]) {
                        el.innerHTML = '<p class="text-muted small mb-0">No data in the selected range.</p>';
                        continue;
                    }
                    const chart = new ApexCharts(el, configs[id]);
                    chart.render();
                    this.charts[id] = chart;
                }
            },
            async applyRange() {
                this.error = null;
                if (!this.from || !this.to) { this.error = 'Pick both dates.'; return; }
                if (this.from > this.to)    { this.error = 'From cannot be after To.'; return; }
                this.loading = true;
                try {
                    const url = `${dataUrl}?from=${encodeURIComponent(this.from)}&to=${encodeURIComponent(this.to)}`;
                    const res = await fetch(url, { headers: { Accept: 'application/json' } });
                    const body = await res.json();
                    if (!res.ok) { this.error = body.error || `HTTP ${res.status}`; return; }
                    this.stats       = body;
                    this.kpi         = body.kpi;
                    this.reliability = body.reliability || this.reliability;
                    this.roundsToday = body.roundsToday || this.roundsToday;
                    this.hseTraining = body.hseTraining || this.hseTraining;
                    this.hseSds      = body.hseSds      || this.hseSds;
                    this.anchorDate  = body.anchorDate;
                    this.$nextTick(() => this.renderAllCharts());
                } catch (e) {
                    this.error = e.message || String(e);
                } finally {
                    this.loading = false;
                }
            },
            resetRange() {
                this.from = initial.from;
                this.to   = initial.to;
                this.applyRange();
            },
            quickRange(days) {
                const to = this.to || initial.to;
                const d  = new Date(to);
                d.setDate(d.getDate() - days);
                this.from = d.toISOString().slice(0, 10);
                this.applyRange();
            },
        },
    }).mount('#execDashboard');
})();
</script>
<?php $this->end(); ?>
