<?php
/**
 * Workspace dashboard — Operations View (v2).
 * Single-page scroll, dense layout, all panels visible without tab clicks.
 * Same data scope as workspace.php (Trend view) but adds per-client scorecard
 * table, carrier mix donut, top-line alerts.  Total: 4 SQL queries (vs. v1's 3).
 */
require_once __DIR__ . '/../includes/config.php';
$user = require_login('internal');
require_permission('report.view');

$pdo   = db();
$first = explode(' ', trim((string)$user['name']))[0] ?: 'there';
$noAccess = (accessible_report_ids((int)$user['id']) === []);

$scopeRaw = report_scope_sql('report_id');
$scopeCr  = report_scope_sql('cr.report_id');
$scopeRep = report_scope_sql('id');

$months   = [];      // 13 calendar months — for trend chart + MoM delta
$byClient = [];      // per-client scorecard rows
$carriers = [];      // top 8 carriers for the donut
$aging    = ['0-30'=>0,'31-60'=>0,'61-90'=>0,'91-120'=>0,'121+'=>0];
$tot      = ['charge'=>0,'paid'=>0,'expected'=>0,'ins_bal'=>0,'pat_bal'=>0,'claims'=>0,
             'paid_n'=>0,'unpaid_n'=>0,'at_risk'=>0,'recent_claims'=>0,'recent_owed'=>0];
$clientCount = 0; $reportCount = 0; $hasData = false;

try {
    $reportCount = (int) $pdo->query("SELECT COUNT(*) FROM reports WHERE deleted_at IS NULL AND status='active'" . $scopeRep)->fetchColumn();

    /* ===== Q1: monthly aggregation (drives KPI totals AND trend chart) =====
       One pass over the indexed (report_id, dos_year, dos_month, …) tuple. */
    foreach ($pdo->query("
        SELECT dos_year, dos_month,
               SUM(charge_amount) charge,
               SUM(primary_ins_paid + secondary_ins_paid + tertiary_ins_paid + patient_payment_amount) paid,
               SUM(expected_payment) expected,
               SUM(CASE WHEN insurance_balance > 0 THEN insurance_balance ELSE 0 END) ins_bal,
               SUM(CASE WHEN patient_balance   > 0 THEN patient_balance   ELSE 0 END) pat_bal,
               COUNT(DISTINCT visit_id) claims,
               COUNT(DISTINCT CASE WHEN primary_ins_paid > 0 THEN visit_id END) paid_n
          FROM collection_raw
         WHERE dos_year IS NOT NULL AND dos_month IS NOT NULL" . $scopeRaw . "
         GROUP BY dos_year, dos_month ORDER BY dos_year, dos_month")->fetchAll() as $r) {
        $mn = ['', 'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'][(int)$r['dos_month']];
        $months[] = ['label'=>$mn.' '.substr((string)$r['dos_year'], -2),
                     'charge'=>(float)$r['charge'], 'paid'=>(float)$r['paid'],
                     'expected'=>(float)$r['expected'], 'ins_bal'=>(float)$r['ins_bal'],
                     'pat_bal'=>(float)$r['pat_bal'], 'claims'=>(int)$r['claims'],
                     'paid_n'=>(int)$r['paid_n']];
        $tot['charge']   += (float)$r['charge'];
        $tot['paid']     += (float)$r['paid'];
        $tot['expected'] += (float)$r['expected'];
        $tot['ins_bal']  += (float)$r['ins_bal'];
        $tot['pat_bal']  += (float)$r['pat_bal'];
        $tot['claims']   += (int)$r['claims'];
        $tot['paid_n']   += (int)$r['paid_n'];
    }
    $tot['unpaid_n'] = max(0, $tot['claims'] - $tot['paid_n']);

    /* ===== Q2: at-risk dollars + recently-billed (today-relative numbers) =====
       Two scalar aggregates rolled into one query — saves a round-trip. */
    $sn = $pdo->query("
        SELECT SUM(CASE WHEN primary_ins_paid = 0 AND dos IS NOT NULL
                          AND DATEDIFF(CURDATE(), dos) > 60
                          AND (insurance_balance > 0 OR patient_balance > 0)
                         THEN insurance_balance + patient_balance ELSE 0 END) at_risk,
               COUNT(DISTINCT CASE WHEN entry_date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) THEN visit_id END) recent_claims,
               SUM(CASE WHEN entry_date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
                          AND (insurance_balance > 0 OR patient_balance > 0)
                         THEN insurance_balance + patient_balance ELSE 0 END) recent_owed
          FROM collection_raw
         WHERE 1=1" . $scopeRaw)->fetch();
    $tot['at_risk']       = (float)($sn['at_risk'] ?? 0);
    $tot['recent_claims'] = (int)  ($sn['recent_claims'] ?? 0);
    $tot['recent_owed']   = (float)($sn['recent_owed']   ?? 0);

    /* ===== Q3: per-PROCESS scorecard with aging segments =====
       Single GROUP BY process + 5 conditional sums for aging breakdown. Each row is one process,
       labelled "Client » Process". Reads collection_raw once and joins 3 tiny dim tables. */
    foreach ($pdo->query("
        SELECT p.id client_id, CONCAT(c.name,' » ',p.name) client,
               COUNT(DISTINCT cr.visit_id) claims,
               COUNT(DISTINCT CASE WHEN cr.primary_ins_paid > 0 THEN cr.visit_id END) paid_n,
               COUNT(DISTINCT cr.report_id) reports,
               SUM(cr.charge_amount) charge,
               SUM(cr.primary_ins_paid + cr.secondary_ins_paid + cr.tertiary_ins_paid + cr.patient_payment_amount) paid,
               SUM(cr.expected_payment) expected,
               SUM(CASE WHEN cr.insurance_balance > 0 THEN cr.insurance_balance ELSE 0 END) ins_bal,
               SUM(CASE WHEN cr.patient_balance   > 0 THEN cr.patient_balance   ELSE 0 END) pat_bal,
               SUM(CASE WHEN cr.dos IS NOT NULL AND DATEDIFF(CURDATE(),cr.dos)<=30 AND (cr.insurance_balance>0 OR cr.patient_balance>0)
                         THEN cr.insurance_balance + cr.patient_balance ELSE 0 END) ag0,
               SUM(CASE WHEN cr.dos IS NOT NULL AND DATEDIFF(CURDATE(),cr.dos) BETWEEN 31 AND 60 AND (cr.insurance_balance>0 OR cr.patient_balance>0)
                         THEN cr.insurance_balance + cr.patient_balance ELSE 0 END) ag1,
               SUM(CASE WHEN cr.dos IS NOT NULL AND DATEDIFF(CURDATE(),cr.dos) BETWEEN 61 AND 90 AND (cr.insurance_balance>0 OR cr.patient_balance>0)
                         THEN cr.insurance_balance + cr.patient_balance ELSE 0 END) ag2,
               SUM(CASE WHEN cr.dos IS NOT NULL AND DATEDIFF(CURDATE(),cr.dos) BETWEEN 91 AND 120 AND (cr.insurance_balance>0 OR cr.patient_balance>0)
                         THEN cr.insurance_balance + cr.patient_balance ELSE 0 END) ag3,
               SUM(CASE WHEN cr.dos IS NOT NULL AND DATEDIFF(CURDATE(),cr.dos) > 120 AND (cr.insurance_balance>0 OR cr.patient_balance>0)
                         THEN cr.insurance_balance + cr.patient_balance ELSE 0 END) ag4
          FROM collection_raw cr
          JOIN reports  rep ON rep.id  = cr.report_id AND rep.deleted_at IS NULL
          JOIN processes p  ON p.id    = rep.process_id
          JOIN clients   c  ON c.id    = p.client_id
         WHERE 1=1" . $scopeCr . "
         GROUP BY p.id
         ORDER BY (SUM(cr.insurance_balance) + SUM(cr.patient_balance)) DESC")->fetchAll() as $row) {
        $bal = (float)$row['ins_bal'] + (float)$row['pat_bal'];
        // Collection % = paid claims ÷ total claims
        $cp  = (int)$row['claims'] > 0 ? ((int)$row['paid_n']/(int)$row['claims'])*100 : 0;
        $aging['0-30']    += (float)$row['ag0'];
        $aging['31-60']   += (float)$row['ag1'];
        $aging['61-90']   += (float)$row['ag2'];
        $aging['91-120']  += (float)$row['ag3'];
        $aging['121+']    += (float)$row['ag4'];
        $byClient[] = [
            'client'=>$row['client'], 'reports'=>(int)$row['reports'], 'claims'=>(int)$row['claims'],
            'paid_n'=>(int)$row['paid_n'],
            'charge'=>(float)$row['charge'], 'paid'=>(float)$row['paid'],
            'expected'=>(float)$row['expected'], 'ins_bal'=>(float)$row['ins_bal'],
            'pat_bal'=>(float)$row['pat_bal'], 'total_bal'=>$bal, 'col_pct'=>$cp,
            'aging'=>['0-30'=>(float)$row['ag0'],'31-60'=>(float)$row['ag1'],
                      '61-90'=>(float)$row['ag2'],'91-120'=>(float)$row['ag3'],'121+'=>(float)$row['ag4']],
        ];
    }
    $clientCount = count($byClient);

    /* ===== Q4: top 8 carriers by open balance — for the donut ===== */
    foreach ($pdo->query("
        SELECT COALESCE(NULLIF(carrier1_name,''),'(no carrier)') carrier,
               SUM(CASE WHEN insurance_balance > 0 THEN insurance_balance ELSE 0 END) +
               SUM(CASE WHEN patient_balance   > 0 THEN patient_balance   ELSE 0 END) bal,
               COUNT(DISTINCT visit_id) claims
          FROM collection_raw
         WHERE 1=1" . $scopeRaw . "
         GROUP BY carrier1_name
         ORDER BY bal DESC LIMIT 8")->fetchAll() as $row) {
        $carriers[] = ['carrier'=>$row['carrier'],'bal'=>(float)$row['bal'],'claims'=>(int)$row['claims']];
    }

    $hasData = $tot['charge'] > 0 || $tot['claims'] > 0;
} catch (Throwable $e) { /* schema not present */ }

/* ----------------- Derived values for the view ----------------- */
$totalBal = $tot['ins_bal'] + $tot['pat_bal'];
// Collection % = paid claims ÷ total claims
$collPct  = $tot['claims']   > 0 ? ($tot['paid_n']/$tot['claims'])*100 : 0;
$over90   = $aging['91-120'] + $aging['121+'];
$over90Pct = $totalBal > 0 ? ($over90/$totalBal)*100 : 0;

/* MoM delta — only compute when BOTH months have data; otherwise show "—" so we
   never display a misleading "-100%" against an empty previous month. */
$mom = ['ar'=>null, 'col_pct'=>null, 'paid'=>null, 'claims'=>null];
if (count($months) >= 2) {
    $cur  = end($months);
    $prev = $months[count($months) - 2];
    $pctDelta = function($curV, $prevV) { return $prevV > 0 ? (($curV - $prevV) / $prevV) * 100 : null; };
    $mom['ar']      = $pctDelta($cur['ins_bal']+$cur['pat_bal'], $prev['ins_bal']+$prev['pat_bal']);
    // Collection % = paid claims ÷ total claims
    $curCol  = $cur['claims']  > 0 ? ($cur['paid_n']/$cur['claims'])*100   : 0;
    $prevCol = $prev['claims'] > 0 ? ($prev['paid_n']/$prev['claims'])*100 : 0;
    $mom['col_pct'] = ($prev['claims'] > 0) ? ($curCol - $prevCol) : null;   // percentage-point change
    $mom['paid']    = $pctDelta($cur['paid'], $prev['paid']);
    $mom['claims']  = $pctDelta($cur['claims'], $prev['claims']);
}
$weightedDso = null;
/* (DSO not in cached aggregates — kept as separate panel target if needed later.) */

$money    = function($v){ return '$' . number_format((float)$v, 2); };
$moneyK   = function($v){ $v=(float)$v; $a=abs($v);
    if ($a>=1e6) return '$'.number_format($v/1e6,2).'M';
    if ($a>=1e3) return '$'.number_format($v/1e3,1).'K';
    return '$'.number_format($v,0);
};
$renderDelta = function($v, $unit = '%') {
    if ($v === null) return '<span class="ms-delta neutral" title="No prior month data to compare"><i class="ti ti-minus"></i>—</span>';
    $cls = $v > 0.5 ? 'up' : ($v < -0.5 ? 'down' : 'neutral');
    $ico = $v > 0.5 ? 'arrow-up' : ($v < -0.5 ? 'arrow-down' : 'minus');
    return '<span class="ms-delta '.$cls.'"><i class="ti ti-'.$ico.'"></i>'
         . ($v>=0?'+':'') . number_format($v, 1) . $unit . '</span>';
};

$pageTitle = 'Dashboard';
require __DIR__ . '/../includes/header.php';
?>
<style>
.page-body{padding-top:6px!important;padding-bottom:8px!important}
.ov-head{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:4px 0 10px}
.ov-head h2{margin:0;font-size:1.05rem;font-weight:700}
.ov-pill{display:inline-flex;align-items:center;gap:4px;background:var(--m-surface-2);border:1px solid var(--m-border);border-radius:999px;padding:1px 8px;font-size:.66rem;color:var(--m-text-soft)}

/* KPI strip */
.ms-strip{display:grid;grid-template-columns:repeat(7,1fr);gap:8px;margin-bottom:10px}
@media(max-width:1200px){.ms-strip{grid-template-columns:repeat(4,1fr)}}
@media(max-width:768px){.ms-strip{grid-template-columns:repeat(2,1fr)}}
.ms-tile{background:var(--m-surface);border:1px solid var(--m-border);border-left-width:3px;border-radius:8px;padding:8px 12px;position:relative}
.ms-tile .l{font-size:.62rem;text-transform:uppercase;letter-spacing:.04em;color:var(--m-text-soft);font-weight:700;display:flex;align-items:center;gap:4px}
.ms-tile .v{font-size:1.05rem;font-weight:700;line-height:1.1;margin-top:2px;font-variant-numeric:tabular-nums}
.ms-tile .s{font-size:.7rem;color:var(--m-text-soft);margin-top:2px}
.ms-delta{display:inline-flex;align-items:center;gap:2px;font-size:.68rem;font-weight:700;padding:1px 6px;border-radius:99px;margin-top:3px}
.ms-delta.up{background:rgba(220,38,38,.12);color:#dc2626}    /* A/R rising = bad */
.ms-delta.down{background:rgba(34,197,94,.12);color:#16a34a}
.ms-delta.neutral{background:var(--m-surface-2);color:var(--m-text-soft)}
.ms-delta i{font-size:.7rem}
.ms-delta.col-up{background:rgba(34,197,94,.12);color:#16a34a}   /* collection % up = good */
.ms-delta.col-down{background:rgba(220,38,38,.12);color:#dc2626}

/* Section card */
.s-card{background:var(--m-surface);border:1px solid var(--m-border);border-radius:9px;padding:0;margin-bottom:10px;overflow:hidden}
.s-head{padding:10px 14px;border-bottom:1px solid var(--m-border);display:flex;align-items:center;gap:8px;background:var(--m-surface-2)}
.s-head h3{margin:0;font-size:.82rem;font-weight:700}
.s-head .sub{font-size:.7rem;color:var(--m-text-soft);font-weight:normal;margin-left:auto}
.s-body{padding:10px 14px}

/* Per-client scorecard */
.client-tbl{width:100%;font-size:.78rem}
.client-tbl thead th{font-size:.62rem;text-transform:uppercase;letter-spacing:.04em;color:var(--m-text-soft);font-weight:700;padding:6px 10px;border-bottom:1px solid var(--m-border);background:var(--m-surface-2);position:sticky;top:0;z-index:3}
.client-tbl tbody td{padding:7px 10px;border-bottom:1px solid var(--m-border);vertical-align:middle}
.client-tbl tbody tr:hover{background:rgba(32,107,196,.04)}
.client-tbl .nm{font-weight:700}
.client-tbl .nm small{display:block;font-size:.62rem;color:var(--m-text-soft);font-weight:400}
.cp-pill{display:inline-block;padding:1px 8px;border-radius:99px;font-size:.7rem;font-weight:700;font-variant-numeric:tabular-nums}
.cp-pill.good{background:rgba(34,197,94,.14);color:#15803d}
.cp-pill.warn{background:rgba(245,158,11,.14);color:#a16207}
.cp-pill.bad{background:rgba(220,38,38,.14);color:#b91c1c}
.aging-mini{display:flex;width:120px;height:8px;border-radius:4px;overflow:hidden;background:var(--m-surface-2)}
.aging-mini > span{display:block;height:100%}
.aging-mini .b0{background:#16a34a}.aging-mini .b1{background:#84cc16}.aging-mini .b2{background:#f59e0b}.aging-mini .b3{background:#f97316}.aging-mini .b4{background:#dc2626}
.aging-legend{display:flex;gap:8px;font-size:.62rem;color:var(--m-text-soft);margin-top:6px}
.aging-legend span i{display:inline-block;width:8px;height:8px;border-radius:2px;margin-right:3px;vertical-align:middle}

/* Alerts row */
.alert-row{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:10px}
@media(max-width:992px){.alert-row{grid-template-columns:1fr}}
.al-card{background:var(--m-surface);border:1px solid var(--m-border);border-left-width:4px;border-radius:9px;padding:12px 14px}
.al-card .lbl{font-size:.65rem;text-transform:uppercase;letter-spacing:.04em;color:var(--m-text-soft);font-weight:700}
.al-card .big{font-size:1.2rem;font-weight:700;margin-top:2px;line-height:1.1}
.al-card .sub{font-size:.72rem;color:var(--m-text-soft);margin-top:3px}
.al-card.danger{border-left-color:#dc2626}
.al-card.warning{border-left-color:#f59e0b}
.al-card.info{border-left-color:#206bc4}
</style>

<div class="container-xl">
    <div class="ov-head">
        <h2><i class="ti ti-target me-2 text-primary"></i>Hi <?= e($first) ?> — Operations View</h2>
        <span class="ov-pill"><i class="ti ti-shield-check"></i> <?= e($myRoleLabel) ?></span>
        <span class="ov-pill"><i class="ti ti-users"></i> <?= (int)$clientCount ?> clients</span>
        <span class="ov-pill"><i class="ti ti-report-analytics"></i> <?= (int)$reportCount ?> reports</span>
        <div class="btn-group btn-group-sm ms-auto me-2" role="group">
            <a href="<?= e(url('/admin/workspace.php')) ?>" class="btn btn-outline-primary"><i class="ti ti-chart-area-line me-1"></i>Trend view</a>
            <button type="button" class="btn btn-primary" disabled><i class="ti ti-target me-1"></i>Operations view</button>
        </div>
        <a href="<?= e(url('/admin/reports.php')) ?>" class="btn btn-sm btn-outline-primary"><i class="ti ti-search me-1"></i>Browse reports</a>
    </div>
</div>

<div class="page-body"><div class="container-xl">
<?php if (!$hasData): ?>
    <div class="card"><div class="card-body text-center text-secondary py-5">
        <?php if ($noAccess): ?>
            <div style="font-size:2.6rem">🔒</div>
            <h3 class="mt-2">No reports assigned yet</h3>
            <p class="mb-0">You haven't been granted access to any reports. Ask your administrator to assign reports to you under <strong>Report Access</strong>.</p>
        <?php else: ?>
            <div style="font-size:2.6rem">📊</div>
            <h3 class="mt-2">Your dashboard will appear here</h3>
            <p class="mb-0">Once collection data is loaded, you'll see trend, per-process scorecard, aging mix and carrier breakdown.</p>
        <?php endif; ?>
    </div></div>
<?php else: ?>

    <!-- ============ KPI STRIP (7 tiles) ============ -->
    <div class="ms-strip">
        <div class="ms-tile" style="border-left-color:#f76707">
            <div class="l" title="Insurance balance + patient balance"><i class="ti ti-wallet"></i>Total Open A/R</div>
            <div class="v text-warning"><?= $money($totalBal) ?></div>
            <?= $renderDelta($mom['ar']) ?>
        </div>
        <div class="ms-tile" style="border-left-color:#16a34a">
            <div class="l" title="Paid claims ÷ Total claims"><i class="ti ti-target"></i>Collection %</div>
            <div class="v text-<?= $collPct>=70?'success':($collPct>=40?'warning':'danger') ?>"><?= number_format($collPct, 1) ?>%</div>
            <?php if ($mom['col_pct'] === null): ?>
                <span class="ms-delta neutral"><i class="ti ti-minus"></i>—</span>
            <?php else: $clsExt = $mom['col_pct']>0.5?'col-up':($mom['col_pct']<-0.5?'col-down':'neutral'); ?>
                <span class="ms-delta <?= $clsExt ?>"><i class="ti ti-arrow-<?= $mom['col_pct']>0?'up':($mom['col_pct']<0?'down':'right') ?>"></i><?= ($mom['col_pct']>=0?'+':'').number_format($mom['col_pct'],1) ?> pp</span>
            <?php endif; ?>
        </div>
        <div class="ms-tile" style="border-left-color:#2fb344">
            <div class="l"><i class="ti ti-cash"></i>Total Paid</div>
            <div class="v text-success"><?= $money($tot['paid']) ?></div>
            <?php $clsExt = $mom['paid']===null?'neutral':($mom['paid']>0.5?'col-up':($mom['paid']<-0.5?'col-down':'neutral')); ?>
            <?php if ($mom['paid'] === null): ?>
                <span class="ms-delta neutral"><i class="ti ti-minus"></i>—</span>
            <?php else: ?>
                <span class="ms-delta <?= $clsExt ?>"><i class="ti ti-arrow-<?= $mom['paid']>0?'up':($mom['paid']<0?'down':'right') ?>"></i><?= ($mom['paid']>=0?'+':'').number_format($mom['paid'],1) ?>%</span>
            <?php endif; ?>
        </div>
        <div class="ms-tile" style="border-left-color:#206bc4">
            <div class="l"><i class="ti ti-file-invoice"></i>Active Claims</div>
            <div class="v"><?= number_format($tot['claims']) ?></div>
            <?php $clsExt = $mom['claims']===null?'neutral':($mom['claims']>0.5?'col-up':($mom['claims']<-0.5?'col-down':'neutral')); ?>
            <?php if ($mom['claims'] === null): ?>
                <span class="ms-delta neutral"><i class="ti ti-minus"></i>—</span>
            <?php else: ?>
                <span class="ms-delta <?= $clsExt ?>"><i class="ti ti-arrow-<?= $mom['claims']>0?'up':($mom['claims']<0?'down':'right') ?>"></i><?= ($mom['claims']>=0?'+':'').number_format($mom['claims'],1) ?>%</span>
            <?php endif; ?>
        </div>
        <div class="ms-tile" style="border-left-color:#dc2626">
            <div class="l" title="Primary unpaid + DOS > 60 days"><i class="ti ti-alert-triangle"></i>At-risk $</div>
            <div class="v text-danger"><?= $money($tot['at_risk']) ?></div>
            <div class="s"><?= $totalBal>0?number_format($tot['at_risk']/$totalBal*100,0):'0' ?>% of A/R</div>
        </div>
        <div class="ms-tile" style="border-left-color:#ae3ec9">
            <div class="l"><i class="ti ti-clock-bolt"></i>Recently Billed</div>
            <div class="v"><?= number_format($tot['recent_claims']) ?></div>
            <div class="s"><?= $moneyK($tot['recent_owed']) ?> still owed</div>
        </div>
        <div class="ms-tile" style="border-left-color:#7c3aed">
            <div class="l" title="Claims with primary not yet paid"><i class="ti ti-hourglass"></i>Unpaid Claims</div>
            <div class="v"><?= number_format($tot['unpaid_n']) ?></div>
            <div class="s"><?= $tot['claims']>0?number_format($tot['unpaid_n']/$tot['claims']*100,0):'0' ?>% of total</div>
        </div>
    </div>

    <!-- ============ 3-CARD ALERT ROW ============ -->
    <?php
        $topClient = $byClient[0] ?? null;
        // Find lowest-collection client with ≥50 claims to surface
        $worst = null;
        foreach ($byClient as $r) if ($r['claims']>=50 && ($worst===null || $r['col_pct']<$worst['col_pct'])) $worst=$r;
    ?>
    <div class="alert-row">
        <div class="al-card danger">
            <div class="lbl"><i class="ti ti-clock-pause text-danger me-1"></i>Aged Balance (90+ days)</div>
            <div class="big"><?= $money($over90) ?></div>
            <div class="sub"><?= number_format($over90Pct, 1) ?>% of total A/R is over 90 days old — prioritise these for follow-up.</div>
        </div>
        <div class="al-card warning">
            <div class="lbl"><i class="ti ti-building text-warning me-1"></i>Highest-A/R Process</div>
            <div class="big"><?= $topClient ? e($topClient['client']) : '—' ?></div>
            <div class="sub"><?= $topClient ? $money($topClient['total_bal']).' in open balance · '.number_format($topClient['col_pct'],1).'% collection' : 'Insufficient data' ?></div>
        </div>
        <div class="al-card info">
            <div class="lbl"><i class="ti ti-trending-down text-info me-1"></i>Weakest Collection %</div>
            <div class="big"><?= $worst ? e($worst['client']) : '—' ?></div>
            <div class="sub"><?= $worst ? number_format($worst['col_pct'],1).'% on '.number_format($worst['claims']).' claims · '.$money($worst['total_bal']).' open' : 'Need ≥50 claims/process to qualify' ?></div>
        </div>
    </div>

    <!-- ============ TREND + AGING + CARRIER ROW ============ -->
    <div class="row g-2">
        <div class="col-lg-7">
            <div class="s-card">
                <div class="s-head"><h3><i class="ti ti-chart-area-line text-primary"></i>Revenue &amp; A/R trend</h3>
                    <span class="sub">Charge · Total Paid · Total Balance (last 13 months)</span>
                </div>
                <div class="s-body"><div id="ch_trend" style="min-height:230px"></div></div>
            </div>
        </div>
        <div class="col-lg-5">
            <div class="s-card">
                <div class="s-head"><h3><i class="ti ti-clock-hour-4 text-primary"></i>Aging of open balance</h3>
                    <span class="sub">By bucket — <?= $money($totalBal) ?> total</span>
                </div>
                <div class="s-body"><div id="ch_aging" style="min-height:230px"></div></div>
            </div>
        </div>
    </div>

    <!-- ============ CLIENT SCORECARD TABLE ============ -->
    <div class="s-card">
        <div class="s-head">
            <h3><i class="ti ti-list-numbers text-primary"></i>Process scorecard</h3>
            <span class="sub"><?= count($byClient) ?> processes · sorted by total open balance</span>
        </div>
        <div class="s-body p-0">
            <div class="table-responsive" style="max-height:520px;overflow:auto">
                <table class="client-tbl">
                    <thead><tr>
                        <th>Client » Process</th>
                        <th class="text-end">Claims</th>
                        <th class="text-end">Charge</th>
                        <th class="text-end">Total Paid</th>
                        <th class="text-end">Expected</th>
                        <th class="text-end">Ins Balance</th>
                        <th class="text-end">Pat Balance</th>
                        <th class="text-end">Total A/R</th>
                        <th class="text-center">Collection %</th>
                        <th>Aging mix</th>
                    </tr></thead>
                    <tbody>
                    <?php foreach ($byClient as $c):
                        $cp = $c['col_pct'];
                        $cls = $cp >= 70 ? 'good' : ($cp >= 40 ? 'warn' : 'bad');
                        $agTot = array_sum($c['aging']);
                    ?>
                        <tr>
                            <td class="nm">
                                <?= e($c['client']) ?>
                                <small><?= number_format($c['reports']) ?> rpt</small>
                            </td>
                            <td class="text-end"><?= number_format($c['claims']) ?></td>
                            <td class="text-end text-secondary"><?= $money($c['charge']) ?></td>
                            <td class="text-end text-success"><?= $money($c['paid']) ?></td>
                            <td class="text-end text-secondary"><?= $money($c['expected']) ?></td>
                            <td class="text-end text-warning"><?= $money($c['ins_bal']) ?></td>
                            <td class="text-end" style="color:#ae3ec9"><?= $money($c['pat_bal']) ?></td>
                            <td class="text-end"><strong><?= $money($c['total_bal']) ?></strong></td>
                            <td class="text-center"><span class="cp-pill <?= $cls ?>"><?= number_format($cp, 1) ?>%</span></td>
                            <td>
                                <?php if ($agTot > 0): ?>
                                <div class="aging-mini" title="0-30: <?= $money($c['aging']['0-30']) ?> · 31-60: <?= $money($c['aging']['31-60']) ?> · 61-90: <?= $money($c['aging']['61-90']) ?> · 91-120: <?= $money($c['aging']['91-120']) ?> · 121+: <?= $money($c['aging']['121+']) ?>">
                                    <span class="b0" style="width:<?= ($c['aging']['0-30']/$agTot)*100 ?>%"></span>
                                    <span class="b1" style="width:<?= ($c['aging']['31-60']/$agTot)*100 ?>%"></span>
                                    <span class="b2" style="width:<?= ($c['aging']['61-90']/$agTot)*100 ?>%"></span>
                                    <span class="b3" style="width:<?= ($c['aging']['91-120']/$agTot)*100 ?>%"></span>
                                    <span class="b4" style="width:<?= ($c['aging']['121+']/$agTot)*100 ?>%"></span>
                                </div>
                                <?php else: ?><span class="text-secondary">—</span><?php endif; ?>
                            </td>
                        </tr>
                    <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
            <div class="px-3 py-2" style="border-top:1px solid var(--m-border);background:var(--m-surface-2)">
                <span class="aging-legend">
                    Aging legend: <span><i style="background:#16a34a"></i>0-30 days</span>
                    <span><i style="background:#84cc16"></i>31-60</span>
                    <span><i style="background:#f59e0b"></i>61-90</span>
                    <span><i style="background:#f97316"></i>91-120</span>
                    <span><i style="background:#dc2626"></i>121+</span>
                </span>
            </div>
        </div>
    </div>

    <!-- ============ CARRIER + CLIENT-BAR ROW ============ -->
    <div class="row g-2">
        <div class="col-lg-6">
            <div class="s-card">
                <div class="s-head"><h3><i class="ti ti-shield-check text-primary"></i>Where the A/R sits — top carriers</h3>
                    <span class="sub">Top 8 by open balance</span>
                </div>
                <div class="s-body"><div id="ch_carrier" style="min-height:280px"></div></div>
            </div>
        </div>
        <div class="col-lg-6">
            <div class="s-card">
                <div class="s-head"><h3><i class="ti ti-building text-primary"></i>Total balance by process</h3>
                    <span class="sub">Client » Process · Insurance + patient (top 12)</span>
                </div>
                <div class="s-body"><div id="ch_client"></div></div>
            </div>
        </div>
    </div>
<?php endif; ?>
</div></div>

<?php if ($hasData): ?>
<script src="https://cdn.jsdelivr.net/npm/apexcharts@3.45.2/dist/apexcharts.min.js"></script>
<script>
(function(){
    var M = <?= json_encode($months) ?>,
        BC = <?= json_encode(array_slice($byClient, 0, 12)) ?>,
        AG = <?= json_encode($aging) ?>,
        CAR = <?= json_encode($carriers) ?>;
    function dark(){ return document.documentElement.getAttribute('data-bs-theme')==='dark'; }
    function money(v){ v=Number(v||0); var a=Math.abs(v);
        if(a>=1e6) return '$'+(v/1e6).toFixed(2)+'M'; if(a>=1e3) return '$'+(v/1e3).toFixed(1)+'K'; return '$'+Math.round(v).toLocaleString(); }
    var grid = function(){ return dark()?'#1e2a44':'#eef0f3'; };
    var axisColor = function(){ return dark()?'#97a2b6':'#6c7a89'; };

    /* === 13-month trend (Charge / Paid / Total Balance) === */
    new ApexCharts(document.getElementById('ch_trend'), {
        chart:{ type:'area', height:230, toolbar:{show:false}, fontFamily:'inherit', background:'transparent' },
        theme:{ mode: dark()?'dark':'light' },
        stroke:{ curve:'smooth', width:2 },
        dataLabels:{ enabled:false },
        series:[
            { name:'Charge', data: M.map(m=>Math.round(m.charge)) },
            { name:'Total Paid', data: M.map(m=>Math.round(m.paid)) },
            { name:'Total Balance', data: M.map(m=>Math.round(m.ins_bal + m.pat_bal)) },
        ],
        colors:['#206bc4','#16a34a','#f59e0b'],
        fill:{ type:'gradient', gradient:{ shadeIntensity:1, opacityFrom:.45, opacityTo:.05, stops:[0,100] } },
        xaxis:{ type:'category', categories: M.map(m=>m.label), labels:{ style:{ colors:axisColor() } } },
        yaxis:{ labels:{ formatter: money, style:{ colors:axisColor() } } },
        grid:{ borderColor:grid(), strokeDashArray:3 },
        legend:{ position:'top', horizontalAlign:'right' },
        tooltip:{ y:{ formatter: money } },
    }).render();

    /* === Aging donut === */
    new ApexCharts(document.getElementById('ch_aging'), {
        chart:{ type:'donut', height:240, fontFamily:'inherit', background:'transparent' },
        theme:{ mode: dark()?'dark':'light' },
        series:[ AG['0-30'], AG['31-60'], AG['61-90'], AG['91-120'], AG['121+'] ].map(v=>Math.round(v)),
        labels:[ '0-30 days', '31-60 days', '61-90 days', '91-120 days', '121+ days' ],
        colors:['#16a34a','#84cc16','#f59e0b','#f97316','#dc2626'],
        legend:{ position:'right', fontSize:'11px' },
        dataLabels:{ formatter: v => v.toFixed(0)+'%' },
        tooltip:{ y:{ formatter: money } },
        plotOptions:{ pie:{ donut:{ size:'55%', labels:{ show:true, total:{ show:true, label:'Total', formatter: () => money(<?= round($totalBal,2) ?>) } } } } },
    }).render();

    /* === Carrier donut === */
    new ApexCharts(document.getElementById('ch_carrier'), {
        chart:{ type:'donut', height:280, fontFamily:'inherit', background:'transparent' },
        theme:{ mode: dark()?'dark':'light' },
        series: CAR.map(c=>Math.round(c.bal)),
        labels: CAR.map(c=>c.carrier.length>22 ? c.carrier.slice(0,20)+'…' : c.carrier),
        colors:['#3b82f6','#10b981','#a855f7','#f59e0b','#ef4444','#06b6d4','#84cc16','#ec4899'],
        legend:{ position:'bottom', fontSize:'10px', markers:{ width:8, height:8 } },
        dataLabels:{ formatter: v => v.toFixed(0)+'%', style:{ fontSize:'10px' } },
        tooltip:{ y:{ formatter: money } },
        plotOptions:{ pie:{ donut:{ size:'52%' } } },
    }).render();

    /* === Client horizontal bar === */
    /* Dynamic height keeps client labels from colliding when the supervisor has many
       clients in scope.  28 px per row + ~70 px chrome, 280 px floor. */
    var clientH = Math.max(280, BC.length * 28 + 70);
    var clientLabels = BC.map(function(c){ return c.client.length > 26 ? c.client.slice(0, 24) + '…' : c.client; });
    new ApexCharts(document.getElementById('ch_client'), {
        chart:{ type:'bar', height:clientH, toolbar:{show:false}, stacked:true, fontFamily:'inherit', background:'transparent' },
        theme:{ mode: dark()?'dark':'light' },
        series:[
            { name:'Insurance Balance', data: BC.map(c=>Math.round(c.ins_bal)) },
            { name:'Patient Balance',   data: BC.map(c=>Math.round(c.pat_bal)) },
        ],
        plotOptions:{ bar:{ horizontal:true, barHeight:'70%' } },
        colors:['#f76707','#ae3ec9'],
        xaxis:{ categories: clientLabels, labels:{ formatter: money, style:{ colors:axisColor() } } },
        yaxis:{ labels:{ style:{ colors:axisColor(), fontSize:'11px' }, maxWidth:200 } },
        grid:{ borderColor:grid(), strokeDashArray:3 },
        legend:{ position:'top', horizontalAlign:'right', fontSize:'11px' },
        tooltip:{ y:{ formatter: money }, x:{ formatter:function(_,o){ return BC[o.dataPointIndex] ? BC[o.dataPointIndex].client : ''; } } },
    }).render();
})();
</script>
<?php endif; ?>

<?php require __DIR__ . '/../includes/footer.php'; ?>
