<?php
/**
 * Coding reports & analytics (coding.reports). Role-aware + pivotable.
 *   Tabs: Summary · Production · Quality (DPO).
 *   Scope: coder = own charts · auditor = charts they audited · supervisor = their team ·
 *          manager = their supervisors + teams · sysadmin = everyone.
 *   Breakdown is PIVOTABLE — group by Coder / Supervisor / Manager / Auditor / Client / Vertical /
 *   Process / Facility / Provider. Filters incl. vertical + client. Excel export per view.
 */
require_once __DIR__ . '/../includes/config.php';
$user = require_login('internal');
$pdo  = db();
$uid  = (int) $user['id'];

$isTeam      = can('coding.supervise');
$isAuditor   = !$isTeam && can('coding.audit');
$canValidate = can('coding.validate');
$isValidator = !$isTeam && !$isAuditor && $canValidate;                           // a PURE validator (the RFI / Disregard hub)
$role        = $isTeam ? 'team' : ($isAuditor ? 'auditor' : ($isValidator ? 'validator' : 'coder'));
/* A user granted this page EXPLICITLY but holding no coding.* role (an AR / Billing manager given the report for
 * business oversight) is not a coder — yet $role above defaults them to 'coder', which scopes every figure to
 * `coder_id = their own id` and therefore shows an empty report. Treat the page grant as read-only oversight:
 * no coder/auditor narrowing, so they see the vertical-wide numbers the grant was meant to give them. The
 * 'team' roster report stays supervisor-only ($isTeam), since that is a management tool, not a report. */
$isPageViewer = !$isTeam && !$isAuditor && !$canValidate && !can('coding.work')
             && can(page_perm_code('coding-reports.php'));
$isManager   = user_has_role($uid, 'coding_manager');
$canValReport = $canValidate || $isTeam;                                          // Validation report: validators + supervisors/managers

$report = in_array($_GET['report'] ?? '', ['summary','production','quality','team','validation'], true) ? $_GET['report'] : ($isValidator ? 'validation' : 'summary');
if ($isValidator)                                $report = 'validation';          // a pure validator only sees the Validation report
if ($report === 'team' && !$isTeam)              $report = 'summary';             // the team roster is supervisor / manager only
if ($report === 'validation' && !$canValReport)  $report = 'summary';
$to   = preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) ($_GET['to'] ?? ''))   ? $_GET['to']   : date('Y-m-d');
$from = preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) ($_GET['from'] ?? '')) ? $_GET['from'] : date('Y-m-d', strtotime('-29 days'));
$toExcl = date('Y-m-d', strtotime($to . ' +1 day'));

$acc    = fn($opp, $def) => $opp > 0 ? round(100.0 * ($opp - $def) / $opp, 1) : null;
$accCls = fn($q) => $q === null ? 'secondary' : ($q >= 95 ? 'success' : ($q >= 90 ? 'warning' : 'danger'));

/* ---------- filters (bare column names → str_replace adds the ci. alias for breakdowns) ---------- */
$f = ['vertical_id'=>(int)($_GET['vertical_id']??0), 'client_id'=>(int)($_GET['client_id']??0),
      'process_id'=>(int)($_GET['process_id']??0), 'facility_id'=>(int)($_GET['facility_id']??0),
      'provider_id'=>(int)($_GET['provider_id']??0), 'coder_id'=>(int)($_GET['coder_id']??0)];
$teamIds   = coding_team_scope($pdo, $uid);                                   // null = sysadmin (everyone)
// A query-string coder_id must NOT widen scope: a team viewer may only narrow to a coder INSIDE their reports_to tree.
if ($f['coder_id'] && $isTeam && $teamIds !== null && !in_array($f['coder_id'], $teamIds, true)) $f['coder_id'] = 0;
$fw = ''; $fp = [];
if ($f['vertical_id'])  { $fw .= ' AND client_id IN (SELECT id FROM clients WHERE vertical_id=?)'; $fp[] = $f['vertical_id']; }
if ($f['client_id'])    { $fw .= ' AND client_id=?';   $fp[] = $f['client_id']; }
if ($f['process_id'])   { $fw .= ' AND process_id=?';  $fp[] = $f['process_id']; }
if ($f['facility_id'])  { $fw .= ' AND facility_id=?'; $fp[] = $f['facility_id']; }
if ($f['provider_id'])  { $fw .= ' AND COALESCE(coded_provider_id,provider_id)=?'; $fp[] = $f['provider_id']; }
$fwBase = $fw; $fpBase = $fp;                                                 // filters WITHOUT the coder narrow — open-queue (pre-coding) + team roll-up use this
if ($f['coder_id'] && $isTeam) { $fw .= ' AND coder_id=?'; $fp[] = $f['coder_id']; }
$ciFw = str_replace(['client_id','process_id','facility_id','coded_provider_id','provider_id','coder_id'],
                    ['ci.client_id','ci.process_id','ci.facility_id','ci.coded_provider_id','ci.provider_id','ci.coder_id'], $fw);
$teamProd  = ($role === 'team' && $teamIds !== null) ? (' AND coder_id IN (' . implode(',', $teamIds ?: [0]) . ')') : '';
// $isPageViewer → '' (no narrowing): an explicitly-granted non-coding viewer sees the vertical-wide figures.
$prodScope = $isPageViewer ? '' : ($role === 'coder' ? ' AND coder_id=' . $uid : $teamProd);         // (auditors have no production of their own)
$qualScope = $isPageViewer ? '' : ($role === 'coder' ? ' AND coder_id=' . $uid : ($role === 'auditor' ? ' AND auditor_id=' . $uid : $teamProd));
$prodScopeCi = str_replace('coder_id', 'ci.coder_id', $prodScope);
$qualScopeCi = str_replace(['coder_id','auditor_id'], ['ci.coder_id','ci.auditor_id'], $qualScope);

/* ---------- KPI / summary aggregates ---------- */
$pst = $pdo->prepare("SELECT COALESCE(SUM(status='completed'),0) completed, COALESCE(SUM(status='rfi'),0) rfi,
        COALESCE(SUM(status='disregard'),0) disregard, COALESCE(SUM(in_sample=1 AND status='completed'),0) sampled,
        COUNT(*) total,
        ROUND(AVG(CASE WHEN status='completed' AND started_at IS NOT NULL AND submitted_at IS NOT NULL THEN TIMESTAMPDIFF(HOUR,started_at,submitted_at) END),1) tat
    FROM coding_inventory WHERE submitted_at>=? AND submitted_at<? $prodScope $fw");
$pst->execute(array_merge([$from,$toExcl], $fp)); $P = $pst->fetch();

$qst = $pdo->prepare("SELECT COALESCE(SUM(audit_result IS NOT NULL),0) audited, COALESCE(SUM(audit_opportunities),0) opp,
        COALESCE(SUM(audit_defects),0) def, COALESCE(SUM(rebuttal_status='raised'),0) reb_raised,
        COALESCE(SUM(rebuttal_status='accepted'),0) reb_accepted, COALESCE(SUM(audit_result='error'),0) errcharts
    FROM coding_inventory WHERE audited_at>=? AND audited_at<? $qualScope $fw");
$qst->execute(array_merge([$from,$toExcl], $fp)); $Q = $qst->fetch();
$overallQ = $acc((int)$Q['opp'], (int)$Q['def']);

/* previous equal-length period (immediately before [from,to]) → for MoM-style deltas on the dashboard */
$spanDays   = max(1, (int) round((strtotime($toExcl) - strtotime($from)) / 86400));
$prevFrom   = date('Y-m-d', strtotime($from) - $spanDays * 86400);
$prevToExcl = $from;
$pst->execute(array_merge([$prevFrom,$prevToExcl], $fp)); $Pp = $pst->fetch();
$qst->execute(array_merge([$prevFrom,$prevToExcl], $fp)); $Qp = $qst->fetch();
$prevQ = $acc((int)$Qp['opp'], (int)$Qp['def']);
$pctDelta = function ($cur, $prev) { $cur=(float)$cur; $prev=(float)$prev; if ($prev <= 0) return $cur > 0 ? 100.0 : null; return round(100.0 * ($cur - $prev) / $prev, 1); };
$ptDelta  = function ($cur, $prev) { return ($cur===null||$prev===null) ? null : round($cur - $prev, 1); };   // absolute points (for % metrics)

$openScope = $isTeam ? ($teamIds !== null ? ' AND assigned_to IN (' . implode(',', $teamIds ?: [0]) . ')' : '') : ' AND assigned_to=' . $uid;
$open = $pdo->prepare("SELECT COALESCE(SUM(status='pending'),0) pend, COALESCE(SUM(status='in_progress'),0) inp, COALESCE(SUM(status='hold'),0) hld
    FROM coding_inventory WHERE status IN ('pending','in_progress','hold') $openScope $fwBase");   // open = pre-coding → no coder_id filter
$open->execute($fpBase); $open = $open->fetch();

$myAudits = null; $rebPending = 0;
if ($isAuditor) {
    $st = $pdo->prepare("SELECT COUNT(*) tot, COALESCE(SUM(audit_result='error'),0) err, COALESCE(SUM(audit_status='rfi'),0) rfi,
            COALESCE(SUM(audit_status='disregard'),0) dis, COALESCE(SUM(audit_opportunities),0) opp, COALESCE(SUM(audit_defects),0) def
        FROM coding_inventory WHERE auditor_id=? AND audited_at>=? AND audited_at<? $fw");
    $st->execute(array_merge([$uid,$from,$toExcl], $fp)); $myAudits = $st->fetch();
    $rebPending = (int) $pdo->query("SELECT COUNT(*) FROM coding_inventory WHERE auditor_id=$uid AND rebuttal_status='raised'")->fetchColumn();
}

/* defect categories (role-scoped) */
$ecScope = $isTeam ? ($teamIds !== null ? ' AND ci.coder_id IN (' . implode(',', $teamIds ?: [0]) . ')' : '') : ($isAuditor ? ' AND ci.auditor_id=' . $uid : ' AND ci.coder_id=' . $uid);
$ec = $pdo->prepare("SELECT ac.code_type, COALESCE(NULLIF(ac.error_category,''),'Uncategorised') cat, COUNT(*) n
    FROM coding_audit_codes ac JOIN coding_inventory ci ON ci.id=ac.inventory_id
    WHERE ac.result<>'correct' AND ci.audited_at>=? AND ci.audited_at<? $ecScope $ciFw
    GROUP BY ac.code_type, cat ORDER BY n DESC LIMIT 25");
$ec->execute(array_merge([$from,$toExcl], $fp)); $ecRows = $ec->fetchAll();
$ecTotal = array_sum(array_column($ecRows, 'n'));
$ecByType = ['cpt'=>0,'icd'=>0,'modifier'=>0];
foreach ($ecRows as $r) $ecByType[$r['code_type']] = ($ecByType[$r['code_type']] ?? 0) + (int) $r['n'];

/* daily activity */
$daily = [];
for ($d = $from; $d <= $to; $d = date('Y-m-d', strtotime($d . ' +1 day'))) $daily[$d] = ['completed'=>0,'audited'=>0,'opp'=>0,'def'=>0];
if ($role !== 'auditor') {
    $st = $pdo->prepare("SELECT DATE(submitted_at) d, COUNT(*) n FROM coding_inventory WHERE status='completed' AND submitted_at>=? AND submitted_at<? $prodScope $fw GROUP BY DATE(submitted_at)");
    $st->execute(array_merge([$from,$toExcl], $fp));
    foreach ($st->fetchAll() as $r) if (isset($daily[$r['d']])) $daily[$r['d']]['completed'] = (int) $r['n'];
}
$st = $pdo->prepare("SELECT DATE(audited_at) d, COUNT(*) n, SUM(audit_opportunities) opp, SUM(audit_defects) def
    FROM coding_inventory WHERE audit_result IS NOT NULL AND audited_at>=? AND audited_at<? $qualScope $fw GROUP BY DATE(audited_at)");
$st->execute(array_merge([$from,$toExcl], $fp));
foreach ($st->fetchAll() as $r) if (isset($daily[$r['d']])) { $daily[$r['d']]['audited']=(int)$r['n']; $daily[$r['d']]['opp']=(int)$r['opp']; $daily[$r['d']]['def']=(int)$r['def']; }
$dailyActive = array_reverse(array_filter($daily, fn($v) => $v['completed'] || $v['audited']), true);

/* ---------- PIVOT dimensions for the breakdown tables ---------- */
$dimDefs = [
    'coder'      => ['Coder',      "COALESCE(cu.name,'(unassigned)')", 'ci.coder_id',  'LEFT JOIN users cu ON cu.id=ci.coder_id'],
    'supervisor' => ['Supervisor', "COALESCE(sup.name,'(none)')",      'sup.id',       'LEFT JOIN users cu ON cu.id=ci.coder_id LEFT JOIN users sup ON sup.id=cu.reports_to'],
    'manager'    => ['Manager',    "COALESCE(mgr.name,'(none)')",      'mgr.id',       'LEFT JOIN users cu ON cu.id=ci.coder_id LEFT JOIN users sup ON sup.id=cu.reports_to LEFT JOIN users mgr ON mgr.id=sup.reports_to'],
    'auditor'    => ['Auditor',    "COALESCE(auu.name,'(unaudited)')", 'ci.auditor_id','LEFT JOIN users auu ON auu.id=ci.auditor_id'],
    'client'     => ['Client',     'cf.name',                          'cf.id',        ''],
    'vertical'   => ['Vertical',   "COALESCE(vv.name,'—')",            'vv.id',        'LEFT JOIN verticals vv ON vv.id=cf.vertical_id'],
    'process'    => ['Process',    'pp.name',                          'pp.id',        'JOIN processes pp ON pp.id=ci.process_id'],
    'facility'   => ['Facility',   'ff.name',                          'ff.id',        'JOIN coding_facilities ff ON ff.id=ci.facility_id'],
    'provider'   => ['Provider',   'pv.name',                          'pv.id',        'JOIN coding_providers pv ON pv.id=COALESCE(ci.coded_provider_id,ci.provider_id)'],
];
$prodDims = ['coder','supervisor','manager','client','vertical','process','facility','provider'];
$qualDims = ['coder','auditor','supervisor','manager','client','vertical','process','facility','provider'];
$allowedDims = $report === 'quality' ? $qualDims : $prodDims;
$by = in_array($_GET['by'] ?? '', $allowedDims, true) ? $_GET['by'] : ($isManager ? 'supervisor' : 'coder');
$D = $dimDefs[$by];
$baseFrom = "coding_inventory ci JOIN clients cf ON cf.id=ci.client_id " . $D[3];

$prodRows = $qualRows = [];
if ($report === 'production' && $role !== 'auditor') {
    $st = $pdo->prepare("SELECT {$D[1]} grp,
            SUM(ci.status='completed') completed, SUM(ci.status='rfi') rfi, SUM(ci.status='disregard') disregard,
            SUM(ci.in_sample=1 AND ci.status='completed') sampled, COUNT(*) total,
            ROUND(AVG(CASE WHEN ci.started_at IS NOT NULL AND ci.submitted_at IS NOT NULL THEN TIMESTAMPDIFF(HOUR, ci.started_at, ci.submitted_at) END),1) tat
        FROM $baseFrom
        WHERE ci.submitted_at>=? AND ci.submitted_at<? $prodScopeCi $ciFw GROUP BY {$D[2]} ORDER BY total DESC LIMIT 1000");
    $st->execute(array_merge([$from,$toExcl], $fp)); $prodRows = $st->fetchAll();
}
if ($report === 'quality') {
    $st = $pdo->prepare("SELECT {$D[1]} grp,
            COUNT(*) audited, SUM(ci.audit_opportunities) opp, SUM(ci.audit_defects) def,
            SUM(ci.audit_result='error') errcharts, SUM(ci.rebuttal_status IN('raised','accepted','rejected')) rebuttals
        FROM $baseFrom
        WHERE ci.audit_result IS NOT NULL AND ci.audited_at>=? AND ci.audited_at<? $qualScopeCi $ciFw GROUP BY {$D[2]} ORDER BY audited DESC LIMIT 1000");
    $st->execute(array_merge([$from,$toExcl], $fp)); $qualRows = $st->fetchAll();
}

/* ---------- dashboard breakdown panels (multi-dimension, role-aware) ---------- */
$dimIcon = ['coder'=>'user','supervisor'=>'users-group','manager'=>'briefcase','auditor'=>'shield-check',
            'client'=>'building','vertical'=>'category-2','process'=>'route','facility'=>'building-hospital','provider'=>'stethoscope'];
$dimFilter = ['client'=>'client_id','process'=>'process_id','facility'=>'facility_id','provider'=>'provider_id','coder'=>'coder_id','vertical'=>'vertical_id'];
$panelData = function (string $dimKey, string $mode) use ($pdo,$dimDefs,$prodScopeCi,$qualScopeCi,$ciFw,$fp,$from,$toExcl) {
    $d = $dimDefs[$dimKey];
    $fromSql = "coding_inventory ci JOIN clients cf ON cf.id=ci.client_id " . $d[3];
    if ($mode === 'prod') {
        $sql = "SELECT {$d[2]} gid, {$d[1]} grp, SUM(ci.status='completed') metric, COUNT(*) total
                FROM $fromSql WHERE ci.submitted_at>=? AND ci.submitted_at<? $prodScopeCi $ciFw
                GROUP BY {$d[2]} ORDER BY metric DESC, total DESC LIMIT 8";
    } else {
        $sql = "SELECT {$d[2]} gid, {$d[1]} grp, COUNT(*) metric, SUM(ci.audit_opportunities) opp, SUM(ci.audit_defects) def
                FROM $fromSql WHERE ci.audit_result IS NOT NULL AND ci.audited_at>=? AND ci.audited_at<? $qualScopeCi $ciFw
                GROUP BY {$d[2]} ORDER BY metric DESC LIMIT 8";
    }
    $st = $pdo->prepare($sql); $st->execute(array_merge([$from,$toExcl], $fp)); return $st->fetchAll();
};
$prodPanels = $isManager ? ['supervisor','coder','client','process','facility','provider']
            : ($role === 'team' ? ['coder','client','process','facility','provider']
            : ['client','process','facility','provider']);
$qualPanels = $isManager ? ['supervisor','coder','auditor','client','process','facility']
            : ($role === 'team' ? ['coder','auditor','client','process','facility']
            : ($role === 'auditor' ? ['coder','client','facility']
            : ['client','process','facility','auditor']));
$panels = [];
if ($report === 'production' && $role !== 'auditor') { foreach ($prodPanels as $pk) $panels[$pk] = $panelData($pk, 'prod'); }
if ($report === 'quality') { foreach ($qualPanels as $pk) $panels[$pk] = $panelData($pk, 'qual'); }

/* trend-chart series (chronological from→to) */
$trendLabels    = array_map(fn($d) => date('M j', strtotime($d)), array_keys($daily));
$trendCompleted = array_map(fn($v) => (int)$v['completed'], array_values($daily));
$trendAudited   = array_map(fn($v) => (int)$v['audited'], array_values($daily));
$trendAcc       = array_map(fn($v) => $v['opp'] ? round(100*($v['opp']-$v['def'])/$v['opp'],1) : null, array_values($daily));
$prodActiveDays = count(array_filter($daily, fn($v) => $v['completed'] > 0));
$qualActiveDays = count(array_filter($daily, fn($v) => $v['audited'] > 0));

/* ---------- per-report KPI strips (with MoM-style deltas vs the previous equal period) ---------- */
$pc = (int)$P['completed']; $pr = (int)$P['rfi']; $pd = (int)$P['disregard']; $ps = (int)$P['sampled']; $ptot = (int)$P['total'];
$pcP=(int)$Pp['completed']; $prP=(int)$Pp['rfi']; $pdP=(int)$Pp['disregard']; $psP=(int)$Pp['sampled']; $tatP=$Pp['tat'];
$qOpp = (int)$Q['opp']; $qDef = (int)$Q['def']; $qAud = (int)$Q['audited']; $qErr = (int)$Q['errcharts'];
$qOppP=(int)$Qp['opp']; $qDefP=(int)$Qp['def']; $qAudP=(int)$Qp['audited']; $qErrP=(int)$Qp['errcharts'];
$rate = fn($n,$den) => $den > 0 ? round(100*$n/$den,1).'%' : '—';
$dl  = fn($cur,$prev,$inv=false) => ['v'=>$pctDelta($cur,$prev), 'u'=>'%', 'inv'=>$inv];   // % delta
$dlp = fn($cur,$prev,$inv=false) => ['v'=>$ptDelta($cur,$prev),  'u'=>'pt','inv'=>$inv];   // point delta (for % metrics)
$prodKpis = [
    ['Completed',       number_format($pc),                                  $ptot.' charts touched', 'success', $dl($pc,$pcP)],
    ['Throughput / day',$prodActiveDays ? number_format(round($pc/$prodActiveDays,1)) : '0', $prodActiveDays.' active day'.($prodActiveDays==1?'':'s'), 'default', null],
    ['Sampled',         number_format($ps),                                  $rate($ps,$pc).' of completed', 'default', $dl($ps,$psP)],
    ['RFI',             number_format($pr),                                  $rate($pr,$ptot).' of charts', 'orange', $dl($pr,$prP,true)],
    ['Disregard',       number_format($pd),                                  $rate($pd,$ptot).' of charts', 'orange', $dl($pd,$pdP,true)],
    ['Avg TAT',         $P['tat']!==null ? $P['tat'].'h' : '—',              'start → submit', 'default', $dl($P['tat'],$tatP,true)],
];
$qualKpis = [
    ['Accuracy % (DPO)', $overallQ===null?'—':$overallQ.'%',                 $qDef.' / '.$qOpp.' defects/opp', $accCls($overallQ), $dlp($overallQ,$prevQ)],
    ['Audited',          number_format($qAud),                               $qualActiveDays.' active day'.($qualActiveDays==1?'':'s'), 'default', $dl($qAud,$qAudP)],
    ['Defects',          number_format($qDef),                               $rate($qDef,$qOpp).' defect rate', $qDef?'danger':'success', $dl($qDef,$qDefP,true)],
    ['Charts w/ error',  number_format($qErr),                               $rate($qErr,$qAud).' of audited', $qErr?'danger':'success', $dl($qErr,$qErrP,true)],
    ['Opportunities',    number_format($qOpp),                               'codes reviewed', 'default', $dl($qOpp,$qOppP)],
    ['Rebuttals',        number_format((int)$Q['reb_raised']+(int)$Q['reb_accepted']), (int)$Q['reb_accepted'].' accepted', 'default', null],
];

/* ---------- gauge scorecards (radialBar) ---------- */
$g = fn($n,$d) => $d > 0 ? round(100*$n/$d,1) : 0;
$prodVsPrev = $pcP > 0 ? round(100*$pc/$pcP,1) : null;   // null = no prior-period baseline
$prodGauges = [
    ['id'=>'gP1','name'=>'Productivity','arc'=>$prodVsPrev===null?0:min(100,(float)$prodVsPrev),'label'=>$prodVsPrev===null?'—':round($prodVsPrev).'%','sub'=>$pcP>0?'vs prev period ('.$pcP.')':'no prior-period baseline','color'=>'#206bc4'],
    ['id'=>'gP2','name'=>'Audit coverage','arc'=>$g($ps,$pc),'label'=>$g($ps,$pc).'%','sub'=>$ps.' sampled of '.$pc,'color'=>'#0ea5e9'],
    ['id'=>'gP3','name'=>'Codeable rate','arc'=>$g($pc,$pc+$pr+$pd),'label'=>$g($pc,$pc+$pr+$pd).'%','sub'=>$pc.' coded · '.($pr+$pd).' RFI/Disreg','color'=>'#2fb344'],
];
$qualGauges = [
    ['id'=>'gQ1','name'=>'Accuracy (DPO)','arc'=>(float)($overallQ??0),'label'=>($overallQ===null?'—':$overallQ.'%'),'sub'=>$qDef.' defects / '.$qOpp.' opp','color'=>'#7048e8'],
    ['id'=>'gQ2','name'=>'Audit pass rate','arc'=>$g($qAud-$qErr,$qAud),'label'=>$g($qAud-$qErr,$qAud).'%','sub'=>($qAud-$qErr).' clean of '.$qAud,'color'=>'#2fb344'],
];
// 3rd quality gauge: coverage (audited÷completed) is only meaningful where both share a population
// (coder/team). For a lone auditor, $pc (completed) is unscoped, so show their error rate instead.
if ($role === 'auditor') {
    $qualGauges[] = ['id'=>'gQ3','name'=>'Charts w/ error','arc'=>$g($qErr,$qAud),'label'=>$g($qErr,$qAud).'%','sub'=>$qErr.' of '.$qAud.' audited','color'=>'#f76707'];
} else {
    $qualGauges[] = ['id'=>'gQ3','name'=>'Audit coverage','arc'=>min(100,$g($qAud,$pc)),'label'=>min(100,$g($qAud,$pc)).'%','sub'=>$qAud.' audited of '.$pc.' completed','color'=>'#0ea5e9'];
}
/* status-mix bar (production) */
$statusBar = ['Open'=>(int)$open['pend'],'In-progress'=>(int)$open['inp'],'On hold'=>(int)$open['hld'],'Completed'=>$pc,'RFI'=>$pr,'Disregard'=>$pd];

/* ---------- filter dropdown options (scoped) ---------- */
$baseScope = $role === 'coder' ? ' AND ci.coder_id=' . $uid : ($role === 'auditor' ? ' AND ci.auditor_id=' . $uid : '');
$optVerticals = $pdo->query("SELECT DISTINCT v.id,v.name FROM coding_inventory ci JOIN clients c ON c.id=ci.client_id JOIN verticals v ON v.id=c.vertical_id WHERE 1 $baseScope ORDER BY v.name")->fetchAll();
$optClients   = $pdo->query("SELECT DISTINCT c.id,c.name FROM coding_inventory ci JOIN clients c ON c.id=ci.client_id WHERE 1 $baseScope ORDER BY c.name")->fetchAll();
$optProcesses = $pdo->query("SELECT DISTINCT p.id,p.name FROM coding_inventory ci JOIN processes p ON p.id=ci.process_id WHERE 1 $baseScope ORDER BY p.name")->fetchAll();
$optFac       = $pdo->query("SELECT DISTINCT f.id,f.name FROM coding_inventory ci JOIN coding_facilities f ON f.id=ci.facility_id WHERE 1 $baseScope ORDER BY f.name")->fetchAll();
$optProv      = $pdo->query("SELECT DISTINCT pr.id,pr.name FROM coding_inventory ci JOIN coding_providers pr ON pr.id=COALESCE(ci.coded_provider_id,ci.provider_id) WHERE 1 $baseScope ORDER BY pr.name")->fetchAll();
$optCoders    = $isTeam ? $pdo->query("SELECT DISTINCT u.id,u.name FROM coding_inventory ci JOIN users u ON u.id=ci.coder_id WHERE ci.coder_id IS NOT NULL" . ($teamIds !== null ? ' AND ci.coder_id IN (' . implode(',', $teamIds ?: [0]) . ')' : '') . " ORDER BY u.name")->fetchAll() : [];

/* ---------- TEAM roster + per-member performance (supervisor / manager only) ----------
   Driven by the mapped users.reports_to hierarchy: a supervisor sees their direct reports;
   a manager sees the tree (their supervisors → each supervisor's coders). Idle members (0 completed
   in the window) still appear, because the roster comes from the org tree — not from inventory. */
$teamNodes = []; $teamChildren = []; $teamRootIds = []; $teamProdU = []; $teamQualU = []; $teamOpenU = [];
$teamTot = ['completed'=>0,'rfi'=>0,'disregard'=>0,'sampled'=>0,'opp'=>0,'def'=>0,'audited'=>0,'open'=>0,'coders'=>0,'idle'=>0,'active'=>0];
$teamDaily = []; $teamTopN = []; $teamFallback = false;
if ($isTeam && $report === 'team') {
    $rosterIds = coding_managed_user_ids($pdo, $uid);                                     // reports_to tree (primary)
    if (!$rosterIds) { $rosterIds = coding_team_member_ids($pdo, $uid); $teamFallback = !empty($rosterIds); }   // operational fallback: members sharing this supervisor's client scope
    if ($rosterIds) {
        $in = implode(',', array_map('intval', $rosterIds));
        foreach ($pdo->query("SELECT u.id, u.name, u.reports_to,
                    MAX(r.code IN('coding_supervisor','coding_manager')) is_lead,
                    COALESCE(GROUP_CONCAT(DISTINCT r.name ORDER BY r.name SEPARATOR ', '),'') roles
                FROM users u LEFT JOIN user_roles ur ON ur.user_id=u.id LEFT JOIN roles r ON r.id=ur.role_id
                WHERE u.id IN ($in) GROUP BY u.id") as $r) {
            $id = (int) $r['id']; $teamNodes[$id] = $r; $teamChildren[(int) $r['reports_to']][] = $id;
        }
        // Tree mode: render the viewer's direct reports (recursion shows the sub-tree). Fallback (scope-shared)
        // members are PEERS — not in the viewer's reports_to tree — so render them as a flat list.
        if ($teamFallback) { $teamRootIds = array_keys($teamNodes); $teamChildren = []; }
        else               { $teamRootIds = $teamChildren[$uid] ?? []; }
        $ps = $pdo->prepare("SELECT coder_id, SUM(status='completed') completed, SUM(status='rfi') rfi, SUM(status='disregard') disregard,
                SUM(in_sample=1 AND status='completed') sampled, COUNT(*) total,
                ROUND(AVG(CASE WHEN status='completed' AND started_at IS NOT NULL AND submitted_at IS NOT NULL THEN TIMESTAMPDIFF(HOUR,started_at,submitted_at) END),1) tat
            FROM coding_inventory WHERE coder_id IN ($in) AND submitted_at>=? AND submitted_at<? $fwBase GROUP BY coder_id");
        $ps->execute(array_merge([$from,$toExcl], $fpBase)); foreach ($ps->fetchAll() as $r) $teamProdU[(int) $r['coder_id']] = $r;
        $qs = $pdo->prepare("SELECT coder_id, COUNT(*) audited, SUM(audit_opportunities) opp, SUM(audit_defects) def, SUM(audit_result='error') errcharts
            FROM coding_inventory WHERE coder_id IN ($in) AND audit_result IS NOT NULL AND audited_at>=? AND audited_at<? $fwBase GROUP BY coder_id");
        $qs->execute(array_merge([$from,$toExcl], $fpBase)); foreach ($qs->fetchAll() as $r) $teamQualU[(int) $r['coder_id']] = $r;
        $os = $pdo->prepare("SELECT assigned_to, SUM(status='pending') pend, SUM(status='in_progress') inp, SUM(status='hold') hld
            FROM coding_inventory WHERE assigned_to IN ($in) AND status IN('pending','in_progress','hold') $fwBase GROUP BY assigned_to");
        $os->execute($fpBase); foreach ($os->fetchAll() as $r) $teamOpenU[(int) $r['assigned_to']] = $r;
        foreach ($teamNodes as $id => $n) {
            $c = (int) ($teamProdU[$id]['completed'] ?? 0); $o = $teamOpenU[$id] ?? [];
            $teamTot['completed'] += $c; $teamTot['rfi'] += (int) ($teamProdU[$id]['rfi'] ?? 0); $teamTot['disregard'] += (int) ($teamProdU[$id]['disregard'] ?? 0);
            $teamTot['sampled'] += (int) ($teamProdU[$id]['sampled'] ?? 0); $teamTot['opp'] += (int) ($teamQualU[$id]['opp'] ?? 0); $teamTot['def'] += (int) ($teamQualU[$id]['def'] ?? 0);
            $teamTot['audited'] += (int) ($teamQualU[$id]['audited'] ?? 0); $teamTot['open'] += (int) ($o['pend'] ?? 0) + (int) ($o['inp'] ?? 0) + (int) ($o['hld'] ?? 0);
            if (!(int) $n['is_lead']) { $teamTot['coders']++; if ($c > 0) $teamTot['active']++; else $teamTot['idle']++; }
        }
        // ---- richer analytics (team-scoped) : daily activity trend + per-member ranking ----
        for ($d = $from; $d <= $to; $d = date('Y-m-d', strtotime($d.' +1 day'))) $teamDaily[$d] = ['completed'=>0,'audited'=>0,'opp'=>0,'def'=>0];
        $td = $pdo->prepare("SELECT DATE(submitted_at) d, COUNT(*) n FROM coding_inventory WHERE status='completed' AND coder_id IN ($in) AND submitted_at>=? AND submitted_at<? $fwBase GROUP BY DATE(submitted_at)");
        $td->execute(array_merge([$from,$toExcl], $fpBase)); foreach ($td->fetchAll() as $r) if (isset($teamDaily[$r['d']])) $teamDaily[$r['d']]['completed'] = (int) $r['n'];
        $td = $pdo->prepare("SELECT DATE(audited_at) d, COUNT(*) n, SUM(audit_opportunities) opp, SUM(audit_defects) def FROM coding_inventory WHERE audit_result IS NOT NULL AND coder_id IN ($in) AND audited_at>=? AND audited_at<? $fwBase GROUP BY DATE(audited_at)");
        $td->execute(array_merge([$from,$toExcl], $fpBase)); foreach ($td->fetchAll() as $r) if (isset($teamDaily[$r['d']])) { $teamDaily[$r['d']]['audited']=(int)$r['n']; $teamDaily[$r['d']]['opp']=(int)$r['opp']; $teamDaily[$r['d']]['def']=(int)$r['def']; }
        foreach ($teamNodes as $id => $n) { if ((int) $n['is_lead']) continue;
            $teamTopN[] = ['name'=>$n['name'], 'completed'=>(int)($teamProdU[$id]['completed']??0),
                'acc'=>$acc((int)($teamQualU[$id]['opp']??0),(int)($teamQualU[$id]['def']??0)),
                'open'=>(int)(($teamOpenU[$id]['pend']??0)+($teamOpenU[$id]['inp']??0)+($teamOpenU[$id]['hld']??0))]; }
        usort($teamTopN, fn($a,$b) => $b['completed'] <=> $a['completed']);
    }
}
$teamAcc = $acc($teamTot['opp'], $teamTot['def']);
// chart series (empty when not on the team tab)
$teamTrendLabels    = array_map(fn($d) => date('M j', strtotime($d)), array_keys($teamDaily));
$teamTrendCompleted = array_map(fn($v) => (int) $v['completed'], array_values($teamDaily));
$teamTrendAudited   = array_map(fn($v) => (int) $v['audited'], array_values($teamDaily));
$teamTrendAcc       = array_map(fn($v) => $v['opp'] ? round(100*($v['opp']-$v['def'])/$v['opp'],1) : null, array_values($teamDaily));
$teamBarNames       = array_map(fn($x) => $x['name'], array_slice($teamTopN, 0, 12));
$teamBarCompleted   = array_map(fn($x) => (int) $x['completed'], array_slice($teamTopN, 0, 12));
$teamStatusMix      = ['Completed'=>$teamTot['completed'], 'RFI'=>$teamTot['rfi'], 'Disregard'=>$teamTot['disregard'], 'Open queue'=>$teamTot['open']];

/* ---------- VALIDATION report (the RFI / Disregard pipeline) — validators + supervisors / managers ----------
   Validator work lives in coding_chart_events (validate_tag = confirm RFI/Disregard, validate_return = send back; actor =
   the validator) + coding_inventory.audit_status / client_sent_at. A PURE validator sees the whole coding pipeline
   (vertical-wide); a supervisor / manager sees only their team's coders' charts. */
$V = ['toreview'=>0,'rfi_conf'=>0,'dis_conf'=>0,'sent_back'=>0,'sent_client'=>0,'validated'=>0,'tat'=>null];
$vByReason = []; $vByCoder = []; $vByValidator = []; $vDaily = [];
if ($report === 'validation' && $canValReport) {
    $vScope = $isValidator ? '' : ($teamIds !== null ? ' AND ci.coder_id IN (' . implode(',', $teamIds ?: [0]) . ')' : '');
    // clean ci-aliased page filters (built directly from $f, NOT str_replace — which corrupts coded_provider_id)
    $ciFwB = '';
    if ($f['vertical_id']) $ciFwB .= ' AND ci.client_id IN (SELECT id FROM clients WHERE vertical_id=?)';
    if ($f['client_id'])   $ciFwB .= ' AND ci.client_id=?';
    if ($f['process_id'])  $ciFwB .= ' AND ci.process_id=?';
    if ($f['facility_id']) $ciFwB .= ' AND ci.facility_id=?';
    if ($f['provider_id']) $ciFwB .= ' AND COALESCE(ci.coded_provider_id,ci.provider_id)=?';   // $fpBase already holds these in this order

    $st = $pdo->prepare("SELECT COUNT(*) FROM coding_inventory ci WHERE ci.status IN ('rfi','disregard') AND ci.audit_status IS NULL $vScope $ciFwB");
    $st->execute($fpBase); $V['toreview'] = (int) $st->fetchColumn();
    $st = $pdo->prepare("SELECT COUNT(*) FROM coding_inventory ci WHERE ci.client_sent_at>=? AND ci.client_sent_at<? $vScope $ciFwB");
    $st->execute(array_merge([$from,$toExcl], $fpBase)); $V['sent_client'] = (int) $st->fetchColumn();
    $st = $pdo->prepare("SELECT
            COALESCE(SUM(e.event_type='validate_tag' AND e.to_state='rfi'),0) rfi_conf,
            COALESCE(SUM(e.event_type='validate_tag' AND e.to_state='disregard'),0) dis_conf,
            COALESCE(SUM(e.event_type='validate_return'),0) sent_back,
            COUNT(DISTINCT CASE WHEN e.event_type='validate_tag' THEN e.inventory_id END) validated,
            ROUND(AVG(CASE WHEN e.event_type='validate_tag' AND ci.submitted_at IS NOT NULL AND e.created_at>=ci.submitted_at THEN TIMESTAMPDIFF(HOUR, ci.submitted_at, e.created_at) END),1) tat
        FROM coding_chart_events e JOIN coding_inventory ci ON ci.id=e.inventory_id
        WHERE e.event_type IN ('validate_tag','validate_return') AND e.created_at>=? AND e.created_at<? $vScope $ciFwB");
    $st->execute(array_merge([$from,$toExcl], $fpBase)); $vr = $st->fetch() ?: [];
    $V['rfi_conf']=(int)($vr['rfi_conf']??0); $V['dis_conf']=(int)($vr['dis_conf']??0); $V['sent_back']=(int)($vr['sent_back']??0);
    $V['validated']=(int)($vr['validated']??0); $V['tat']=$vr['tat']??null;
    $st = $pdo->prepare("SELECT e.to_state tag, COALESCE(NULLIF(ci.audit_secondary_reason,''),'(no reason)') reason, COUNT(*) n
        FROM coding_chart_events e JOIN coding_inventory ci ON ci.id=e.inventory_id
        WHERE e.event_type='validate_tag' AND e.created_at>=? AND e.created_at<? $vScope $ciFwB
        GROUP BY e.to_state, reason ORDER BY n DESC LIMIT 20");
    $st->execute(array_merge([$from,$toExcl], $fpBase)); $vByReason = $st->fetchAll();
    $st = $pdo->prepare("SELECT COALESCE(cu.name,'(unassigned)') coder,
            SUM(e.event_type='validate_tag' AND e.to_state='rfi') rfi, SUM(e.event_type='validate_tag' AND e.to_state='disregard') dis,
            SUM(e.event_type='validate_return') sent_back
        FROM coding_chart_events e JOIN coding_inventory ci ON ci.id=e.inventory_id LEFT JOIN users cu ON cu.id=ci.coder_id
        WHERE e.event_type IN ('validate_tag','validate_return') AND e.created_at>=? AND e.created_at<? $vScope $ciFwB
        GROUP BY ci.coder_id ORDER BY COUNT(*) DESC LIMIT 15");
    $st->execute(array_merge([$from,$toExcl], $fpBase)); $vByCoder = $st->fetchAll();
    $st = $pdo->prepare("SELECT COALESCE(vu.name,'(unknown)') validator,
            SUM(e.event_type='validate_tag' AND e.to_state='rfi') rfi, SUM(e.event_type='validate_tag' AND e.to_state='disregard') dis,
            SUM(e.event_type='validate_return') sent_back
        FROM coding_chart_events e JOIN coding_inventory ci ON ci.id=e.inventory_id LEFT JOIN users vu ON vu.id=e.actor_id
        WHERE e.event_type IN ('validate_tag','validate_return') AND e.created_at>=? AND e.created_at<? $vScope $ciFwB
        GROUP BY e.actor_id ORDER BY COUNT(*) DESC LIMIT 15");
    $st->execute(array_merge([$from,$toExcl], $fpBase)); $vByValidator = $st->fetchAll();
    for ($d=$from; $d<=$to; $d=date('Y-m-d',strtotime($d.' +1 day'))) $vDaily[$d]=['rfi'=>0,'dis'=>0,'back'=>0];
    $st = $pdo->prepare("SELECT DATE(e.created_at) d,
            SUM(e.event_type='validate_tag' AND e.to_state='rfi') rfi, SUM(e.event_type='validate_tag' AND e.to_state='disregard') dis,
            SUM(e.event_type='validate_return') back
        FROM coding_chart_events e JOIN coding_inventory ci ON ci.id=e.inventory_id
        WHERE e.event_type IN ('validate_tag','validate_return') AND e.created_at>=? AND e.created_at<? $vScope $ciFwB GROUP BY DATE(e.created_at)");
    $st->execute(array_merge([$from,$toExcl], $fpBase));
    foreach ($st->fetchAll() as $r) if (isset($vDaily[$r['d']])) $vDaily[$r['d']] = ['rfi'=>(int)$r['rfi'],'dis'=>(int)$r['dis'],'back'=>(int)$r['back']];
}
$vDailyActive = array_reverse(array_filter($vDaily, fn($v)=>$v['rfi']||$v['dis']||$v['back']), true);
$teamSum = function ($id) use (&$teamSum, $teamChildren, $teamProdU, $teamQualU) {           // subtree rollup for a lead row
    $p = $teamProdU[$id] ?? []; $q = $teamQualU[$id] ?? [];
    $s = ['completed'=>(int)($p['completed']??0),'rfi'=>(int)($p['rfi']??0),'disregard'=>(int)($p['disregard']??0),'sampled'=>(int)($p['sampled']??0),'opp'=>(int)($q['opp']??0),'def'=>(int)($q['def']??0),'n'=>1];
    foreach (($teamChildren[$id] ?? []) as $k) { $cs = $teamSum($k); foreach ($s as $kk=>$vv) $s[$kk] += $cs[$kk]; }
    return $s;
};
$renderTeamRows = function ($id, $depth) use (&$renderTeamRows, $teamNodes, $teamChildren, $teamProdU, $teamQualU, $teamOpenU, $teamSum, $acc, $accCls) {
    $n = $teamNodes[$id] ?? null; if (!$n) return; $kids = $teamChildren[$id] ?? []; $isLead = !empty($kids) || (int) $n['is_lead'] === 1;
    $p = $teamProdU[$id] ?? []; $q = $teamQualU[$id] ?? []; $o = $teamOpenU[$id] ?? [];
    $comp = (int)($p['completed']??0); $rfi = (int)($p['rfi']??0); $dis = (int)($p['disregard']??0); $smp = (int)($p['sampled']??0); $tat = $p['tat']??null;
    $aq = $acc((int)($q['opp']??0), (int)($q['def']??0)); $open = (int)($o['pend']??0)+(int)($o['inp']??0)+(int)($o['hld']??0); $pad = 8 + $depth*20;
    echo '<tr class="'.($isLead?'table-active':'').'">';
    echo '<td style="padding-left:'.$pad.'px" class="text-nowrap">'.($isLead?'<i class="ti ti-users-group me-1 text-primary"></i>':'<i class="ti ti-user me-1 text-secondary"></i>').'<strong>'.e($n['name']).'</strong>';
    if ($isLead)            echo ' <span class="badge bg-blue-lt ms-1" style="font-size:.6rem">'.($depth?'SUPERVISOR':'LEAD').'</span>';
    elseif ($comp === 0)    echo ' <span class="badge bg-secondary-lt ms-1" style="font-size:.6rem">idle</span>';
    echo '</td>';
    echo '<td class="text-end">'.($comp?'<strong>'.$comp.'</strong>':'<span class="text-secondary">0</span>').'</td>';
    echo '<td class="text-end text-secondary">'.(($rfi+$dis)?:'·').'</td>';
    echo '<td class="text-end text-secondary">'.($smp?:'·').'</td>';
    echo '<td class="text-end text-secondary">'.($tat!==null?$tat.'h':'·').'</td>';
    echo '<td class="text-end">'.($aq===null?'<span class="text-secondary">—</span>':'<span class="badge bg-'.$accCls($aq).'-lt">'.$aq.'%</span>').'</td>';
    echo '<td class="text-end text-secondary">'.($open?:'·').'</td></tr>';
    foreach ($kids as $k) $renderTeamRows($k, $depth+1);
    if ($isLead && $kids) { $s = $teamSum($id); $sq = $acc($s['opp'], $s['def']); $m = $s['n']-1;
        echo '<tr class="text-secondary" style="font-size:.8rem;background:var(--tblr-bg-surface-secondary,#f8fafc)"><td style="padding-left:'.($pad+22).'px">↳ team total ('.$m.' member'.($m==1?'':'s').')</td>';
        echo '<td class="text-end"><strong>'.$s['completed'].'</strong></td><td class="text-end">'.(($s['rfi']+$s['disregard'])?:'·').'</td><td class="text-end">'.($s['sampled']?:'·').'</td><td></td>';
        echo '<td class="text-end">'.($sq===null?'—':'<span class="badge bg-'.$accCls($sq).'-lt">'.$sq.'%</span>').'</td><td></td></tr>';
    }
};

/* ---------- Excel export (active report, current pivot) ---------- */
if (($_GET['export'] ?? '') === 'xlsx') {
    require_once __DIR__ . '/../includes/xlsx.php';
    $x = new SimpleXlsx();
    if ($report === 'validation') {                                                      // VALIDATION — detailed multi-sheet workbook with supporting data
        // ---- Sheet 1: Summary (KPIs + report context: date range, scope, applied filters) ----
        $vRoleTxt  = $isValidator ? 'Validator' : ($isManager ? 'Manager' : ($isTeam ? 'Supervisor' : 'Coder'));
        $vScopeTxt = $isValidator ? 'All coding (vertical-wide)' : ($teamIds !== null ? 'My team' : 'All coders');
        $pickName = function ($opts, $id) { foreach ($opts as $o) if ((int)$o['id'] === (int)$id) return (string)$o['name']; return (string)$id; };
        $fBits = [];
        if ($f['vertical_id']) $fBits[] = 'Vertical: ' . $pickName($optVerticals, $f['vertical_id']);
        if ($f['client_id'])   $fBits[] = 'Client: '   . $pickName($optClients,   $f['client_id']);
        if ($f['process_id'])  $fBits[] = 'Process: '  . $pickName($optProcesses, $f['process_id']);
        if ($f['facility_id']) $fBits[] = 'Facility: ' . $pickName($optFac,       $f['facility_id']);
        if ($f['provider_id']) $fBits[] = 'Provider: ' . $pickName($optProv,      $f['provider_id']);
        if ($f['coder_id'])    $fBits[] = 'Coder: '    . $pickName($optCoders,    $f['coder_id']);
        $x->addSheet('Summary', ['Metric', 'Value'], [
            ['Report', 'Coding — Validation (RFI / Disregard pipeline)'],
            ['Date range', $from . '  to  ' . $to],
            ['Scope', $vRoleTxt . ' · ' . $vScopeTxt],
            ['Filters', $fBits ? implode(' · ', $fBits) : 'None'],
            ['', ''],
            ['To review (queue now)', (int)$V['toreview']],
            ['RFI confirmed (period)', (int)$V['rfi_conf']],
            ['Disregard confirmed (period)', (int)$V['dis_conf']],
            ['Sent back to coder (period)', (int)$V['sent_back']],
            ['Sent to client (period)', (int)$V['sent_client']],
            ['Avg turnaround (hrs)', $V['tat'] !== null ? (float)$V['tat'] : ''],
        ]);

        // ---- Sheet 2: Validation events — one row per validate action (the supporting data behind every KPI) ----
        $ev = $pdo->prepare("SELECT e.created_at, e.event_type, e.to_state, e.note,
                ci.patient_name, ci.patient_mrn, c.name client, p.name process, f.name facility,
                COALESCE(cp.name, pv.name) provider, cu.name coder, vu.name validator,
                ci.audit_secondary_reason reason, ci.dos, ci.submitted_at, ci.status, ci.audit_status
            FROM coding_chart_events e
            JOIN coding_inventory ci ON ci.id=e.inventory_id
            JOIN clients c ON c.id=ci.client_id
            LEFT JOIN processes p ON p.id=ci.process_id
            LEFT JOIN coding_facilities f ON f.id=ci.facility_id
            LEFT JOIN coding_providers pv ON pv.id=ci.provider_id
            LEFT JOIN coding_providers cp ON cp.id=ci.coded_provider_id
            LEFT JOIN users cu ON cu.id=ci.coder_id
            LEFT JOIN users vu ON vu.id=e.actor_id
            WHERE e.event_type IN ('validate_tag','validate_return') AND e.created_at>=? AND e.created_at<? $vScope $ciFwB
            ORDER BY e.created_at DESC LIMIT 20000");
        $ev->execute(array_merge([$from, $toExcl], $fpBase));
        $actLabel = ['rfi' => 'RFI confirmed', 'disregard' => 'Disregard confirmed'];
        $evData = array_map(function ($r) use ($actLabel) {
            $action = $r['event_type'] === 'validate_return' ? 'Sent back to coder' : ($actLabel[$r['to_state']] ?? ('Validated (' . $r['to_state'] . ')'));
            $tat = '';
            if ($r['event_type'] === 'validate_tag' && $r['submitted_at'] && $r['created_at'] >= $r['submitted_at'])
                $tat = round((strtotime($r['created_at']) - strtotime($r['submitted_at'])) / 3600, 1);
            return [$r['created_at'], $action, $r['patient_name'], $r['patient_mrn'], $r['client'], $r['process'], $r['facility'],
                    $r['provider'], $r['coder'], $r['validator'], $r['reason'], $r['note'], $r['dos'], $r['submitted_at'], $tat, $r['status'], $r['audit_status']];
        }, $ev->fetchAll());
        $x->addSheet('Validation events',
            ['Date/time','Action','Patient','MRN','Client','Process','Facility','Provider','Coder','Validator','Reason','Note','DOS','Coding submitted','Turnaround (hrs)','Current status','Audit status'],
            $evData);

        // ---- Sheet 3: To review queue — coder-flagged RFI/Disregard awaiting validation (the "To review" KPI) ----
        $tr = $pdo->prepare("SELECT ci.patient_name, ci.patient_mrn, c.name client, p.name process, f.name facility,
                COALESCE(cp.name, pv.name) provider, cu.name coder, ci.status coder_tag, ci.secondary_reason reason, ci.comment, ci.submitted_at, ci.dos
            FROM coding_inventory ci
            JOIN clients c ON c.id=ci.client_id
            LEFT JOIN processes p ON p.id=ci.process_id
            LEFT JOIN coding_facilities f ON f.id=ci.facility_id
            LEFT JOIN coding_providers pv ON pv.id=ci.provider_id
            LEFT JOIN coding_providers cp ON cp.id=ci.coded_provider_id
            LEFT JOIN users cu ON cu.id=ci.coder_id
            WHERE ci.status IN ('rfi','disregard') AND ci.audit_status IS NULL $vScope $ciFwB
            ORDER BY ci.submitted_at ASC LIMIT 20000");
        $tr->execute($fpBase);
        $now = time();
        $trData = array_map(function ($r) use ($now) {
            $age = $r['submitted_at'] ? max(0, (int)floor(($now - strtotime($r['submitted_at'])) / 86400)) : '';
            return [$r['patient_name'], $r['patient_mrn'], $r['client'], $r['process'], $r['facility'], $r['provider'], $r['coder'],
                    strtoupper((string)$r['coder_tag']), $r['reason'], $r['comment'], $r['submitted_at'], $r['dos'], $age];
        }, $tr->fetchAll());
        $x->addSheet('To review queue',
            ['Patient','MRN','Client','Process','Facility','Provider','Coder','Coder tag','Reason','Comment','Flagged at','DOS','Age (days)'],
            $trData);

        // ---- Sheet 4: Sent to client — RFI/Disregard delivered to the client in this period ----
        $sc = $pdo->prepare("SELECT ci.patient_name, ci.patient_mrn, c.name client, p.name process, f.name facility,
                COALESCE(cp.name, pv.name) provider, cu.name coder, ci.audit_status disposition, ci.audit_secondary_reason reason, ci.client_sent_at, ci.dos
            FROM coding_inventory ci
            JOIN clients c ON c.id=ci.client_id
            LEFT JOIN processes p ON p.id=ci.process_id
            LEFT JOIN coding_facilities f ON f.id=ci.facility_id
            LEFT JOIN coding_providers pv ON pv.id=ci.provider_id
            LEFT JOIN coding_providers cp ON cp.id=ci.coded_provider_id
            LEFT JOIN users cu ON cu.id=ci.coder_id
            WHERE ci.client_sent_at>=? AND ci.client_sent_at<? $vScope $ciFwB
            ORDER BY ci.client_sent_at DESC LIMIT 20000");
        $sc->execute(array_merge([$from, $toExcl], $fpBase));
        $scData = array_map(fn($r) => [$r['patient_name'], $r['patient_mrn'], $r['client'], $r['process'], $r['facility'], $r['provider'],
                $r['coder'], strtoupper((string)$r['disposition']), $r['reason'], $r['client_sent_at'], $r['dos']], $sc->fetchAll());
        $x->addSheet('Sent to client',
            ['Patient','MRN','Client','Process','Facility','Provider','Coder','Disposition','Reason','Sent to client at','DOS'],
            $scData);

        // ---- Sheets 5-8: aggregate breakdowns (mirror the on-screen panels) ----
        $x->addSheet('By validator', ['Validator','RFI confirmed','Disregard confirmed','Sent back','Total'],
            array_map(fn($r) => [$r['validator'], (int)$r['rfi'], (int)$r['dis'], (int)$r['sent_back'], (int)$r['rfi']+(int)$r['dis']+(int)$r['sent_back']], $vByValidator));
        $x->addSheet('By coder', ['Coder','RFI confirmed','Disregard confirmed','Sent back'],
            array_map(fn($r) => [$r['coder'], (int)$r['rfi'], (int)$r['dis'], (int)$r['sent_back']], $vByCoder));
        $x->addSheet('By reason', ['Tag','Reason','Count'],
            array_map(fn($r) => [strtoupper((string)$r['tag']), $r['reason'], (int)$r['n']], $vByReason));
        $dailyData = [];
        foreach ($vDaily as $d => $v) if ($v['rfi'] || $v['dis'] || $v['back']) $dailyData[] = [$d, (int)$v['rfi'], (int)$v['dis'], (int)$v['back']];
        $x->addSheet('Daily activity', ['Date','RFI confirmed','Disregard confirmed','Sent back'], $dailyData);

        $x->download('coding-validation-' . $from . '_' . $to . '.xlsx');
    }
    if ($report === 'team') {                                                            // TEAM roster export (one row per member)
        $hdr = ['Member','Reports to','Roles','Completed','RFI','Disregard','Sampled','Avg TAT (hrs)','Audited','Accuracy %','Open queue'];
        $data = [];
        foreach ($teamNodes as $id => $n) { $p = $teamProdU[$id] ?? []; $q = $teamQualU[$id] ?? []; $o = $teamOpenU[$id] ?? [];
            $data[] = [$n['name'], $teamNodes[(int)$n['reports_to']]['name'] ?? '', $n['roles'],
                (int)($p['completed']??0),(int)($p['rfi']??0),(int)($p['disregard']??0),(int)($p['sampled']??0),$p['tat']??'',
                (int)($q['audited']??0), $acc((int)($q['opp']??0),(int)($q['def']??0)) ?? '', (int)($o['pend']??0)+(int)($o['inp']??0)+(int)($o['hld']??0)];
        }
        $x->addSheet('Team performance', $hdr, $data);
        $x->download('coding-team-' . $from . '_' . $to . '.xlsx');
    }
    // Sheet 1 — SUMMARY (the on-screen grouped pivot)
    if ($report === 'quality') {
        $hdr = [$D[0],'Audited','Opportunities','Defects','Accuracy %','Charts w/ error','Rebuttals'];
        $data = array_map(fn($r) => [$r['grp'],(int)$r['audited'],(int)$r['opp'],(int)$r['def'],$acc((int)$r['opp'],(int)$r['def']) ?? '',(int)$r['errcharts'],(int)$r['rebuttals']], $qualRows);
    } else {
        $hdr = [$D[0],'Completed','RFI','Disregard','Sampled','Total','Avg TAT (hrs)'];
        $data = array_map(fn($r) => [$r['grp'],(int)$r['completed'],(int)$r['rfi'],(int)$r['disregard'],(int)$r['sampled'],(int)$r['total'],$r['tat']], $prodRows);
    }
    $x->addSheet('Summary by ' . $D[0], $hdr, $data);

    // Sheet 2 — SUPPORTING DETAIL: one row per chart behind the summary (same role-scope + filters + date range)
    $cols = "ci.patient_name, ci.patient_mrn, cf.name client, ff.name facility,
             COALESCE(cp.name, pv.name) provider, cu.name coder, ci.dos";
    $from2 = "coding_inventory ci JOIN clients cf ON cf.id=ci.client_id
              LEFT JOIN coding_facilities ff ON ff.id=ci.facility_id
              LEFT JOIN coding_providers pv ON pv.id=ci.provider_id
              LEFT JOIN coding_providers cp ON cp.id=ci.coded_provider_id
              LEFT JOIN users cu ON cu.id=ci.coder_id";
    if ($report === 'quality') {
        $dst = $pdo->prepare("SELECT $cols, auu.name auditor, ci.audited_at, ci.audit_opportunities opp, ci.audit_defects def,
                ci.audit_result, ci.audit_status, ci.rebuttal_status
            FROM $from2 LEFT JOIN users auu ON auu.id=ci.auditor_id
            WHERE ci.audit_result IS NOT NULL AND ci.audited_at>=? AND ci.audited_at<? $qualScopeCi $ciFw
            ORDER BY ci.audited_at DESC LIMIT 20000");
        $dst->execute(array_merge([$from,$toExcl], $fp));
        $dHdr = ['Patient','MRN','Client','Facility','Provider','Coder','DOS','Auditor','Audited','Opportunities','Defects','Accuracy %','Result','Disposition','Rebuttal'];
        $dData = array_map(fn($r) => [$r['patient_name'],$r['patient_mrn'],$r['client'],$r['facility'],$r['provider'],$r['coder'],$r['dos'],
            $r['auditor'],$r['audited_at'],(int)$r['opp'],(int)$r['def'],$acc((int)$r['opp'],(int)$r['def']) ?? '',$r['audit_result'],$r['audit_status'],$r['rebuttal_status']], $dst->fetchAll());
    } else {
        $dst = $pdo->prepare("SELECT $cols, ci.status, ci.submitted_at, ci.audited_at, ci.audit_status, ci.in_sample
            FROM $from2
            WHERE ci.submitted_at>=? AND ci.submitted_at<? $prodScopeCi $ciFw
            ORDER BY ci.submitted_at DESC LIMIT 20000");
        $dst->execute(array_merge([$from,$toExcl], $fp));
        $dHdr = ['Patient','MRN','Client','Facility','Provider','Coder','DOS','Status','Coding completed','Audit completed','Audit status','Sampled'];
        $dData = array_map(fn($r) => [$r['patient_name'],$r['patient_mrn'],$r['client'],$r['facility'],$r['provider'],$r['coder'],$r['dos'],
            $r['status'],$r['submitted_at'],$r['audited_at'],$r['audit_status'],((int)$r['in_sample']?'Yes':'')], $dst->fetchAll());
    }
    $x->addSheet('Detail (charts)', $dHdr, $dData);
    $x->download('coding-' . $report . '-' . $from . '_' . $to . '.xlsx');
}

/* KPI tiles (summary) */
$kpis = [];
if ($role !== 'auditor') {
    $kpis[] = ['Completed', number_format((int)$P['completed']), (int)$P['sampled'].' sampled', 'success'];
    $kpis[] = ['Accuracy % (DPO)', $overallQ===null?'—':$overallQ.'%', (int)$Q['def'].'/'.(int)$Q['opp'].' defects/opp', $accCls($overallQ)];
    $kpis[] = ['Audited', number_format((int)$Q['audited']), '', 'default'];
    $kpis[] = ['RFI / Disregard', (int)$P['rfi'].' / '.(int)$P['disregard'], '', 'orange'];
    $kpis[] = ['Open queue', (int)$open['pend']+(int)$open['inp']+(int)$open['hld'], $open['pend'].' pend · '.$open['inp'].' in-prog · '.$open['hld'].' hold', 'default'];
    $kpis[] = ['Rebuttals', (int)$Q['reb_raised']+(int)$Q['reb_accepted'], (int)$Q['reb_accepted'].' accepted', 'default'];
} else {
    $opp=(int)($myAudits['opp']??0); $def=(int)($myAudits['def']??0); $aq=$acc($opp,$def);
    $kpis[] = ['Audits finalized', number_format((int)($myAudits['tot']??0)), '', 'default'];
    $kpis[] = ['Accuracy found (DPO)', $aq===null?'—':$aq.'%', $def.'/'.$opp.' defects/opp', $accCls($aq)];
    $kpis[] = ['Charts with error', number_format((int)($myAudits['err']??0)), '', 'danger'];
    $kpis[] = ['Defects found', number_format($def), '', 'danger'];
    $kpis[] = ['Tagged RFI / Disregard', (int)($myAudits['rfi']??0).' / '.(int)($myAudits['dis']??0), '', 'orange'];
    $kpis[] = ['Rebuttals pending', number_format($rebPending), '', $rebPending?'warning':'default'];
}

$qbase = array_filter(array_merge(['from'=>$from,'to'=>$to], $f), fn($v)=>$v!=='' && $v!==0);
$urlFor = function(array $over) use ($qbase) { return url('/admin/coding-reports.php?' . http_build_query(array_merge($qbase, $over))); };

/* breakdown-panel renderer (production = volume bar · quality = accuracy badge) */
$renderPanel = function (string $pk, array $rows, string $mode) use ($dimDefs,$dimIcon,$dimFilter,$urlFor,$report,$acc,$accCls,$isTeam) {
    $lab = $dimDefs[$pk][0]; $icon = $dimIcon[$pk] ?? 'chart-bar';
    $max = 0; foreach ($rows as $r) $max = max($max, (int)$r['metric']);
    $fk = $dimFilter[$pk] ?? null; if ($pk === 'coder' && !$isTeam) $fk = null;
    echo '<div class="rpt-panel"><div class="card h-100">';
    echo '<div class="rpt-h"><i class="ti ti-' . e($icon) . ' me-1"></i>By ' . e($lab);
    echo '<a class="ms-auto rpt-mini-link" href="' . e($urlFor(['report'=>$report,'by'=>$pk])) . '" title="Group the detailed table by ' . e($lab) . '">table <i class="ti ti-arrow-down"></i></a></div>';
    echo '<div class="table-responsive"><table class="table table-sm table-vcenter rpt-tbl mb-0"><tbody>';
    if (!$rows) { echo '<tr><td class="text-center text-secondary py-3 small">No data in scope.</td></tr>'; }
    foreach ($rows as $r) {
        $name = $r['grp']; $gid = (int)$r['gid']; $metric = (int)$r['metric'];
        $nameCell = ($fk && $gid) ? '<a href="' . e($urlFor(['report'=>$report, $fk=>$gid])) . '">' . e($name) . '</a>' : '<strong>' . e($name) . '</strong>';
        echo '<tr><td class="rpt-pn">' . $nameCell . '</td>';
        if ($mode === 'prod') {
            $p = $max > 0 ? round(100*$metric/$max) : 0;
            echo '<td class="text-end" style="width:46%"><span class="rpt-bar" style="--p:' . $p . '%"><i></i><b>' . $metric . '</b></span></td>';
        } else {
            $q = $acc((int)$r['opp'], (int)$r['def']);
            echo '<td class="text-end text-secondary small" style="width:24%">' . $metric . '</td>';
            echo '<td class="text-end" style="width:26%">' . ($q===null ? '<span class="text-secondary">—</span>' : '<span class="badge bg-' . $accCls($q) . '-lt">' . $q . '%</span>') . '</td>';
        }
        echo '</tr>';
    }
    echo '</tbody></table></div></div></div>';
};
/* KPI delta pill: green when good, red when bad (inv = "down is good") */
$deltaHtml = function ($d) {
    if (!$d || $d['v'] === null) return '';
    $v = $d['v']; $inv = !empty($d['inv']);
    $good = $inv ? ($v < 0) : ($v > 0);
    $flat = abs($v) < 0.05;
    $cls = $flat ? 'flat' : ($good ? 'up' : 'down');
    $ic  = $flat ? 'minus' : ($v > 0 ? 'trending-up' : 'trending-down');
    $txt = ($v > 0 ? '+' : '') . rtrim(rtrim(number_format($v,1),'0'),'.') . ($d['u'] === 'pt' ? ' pt' : '%');
    return '<div class="rpt-d ' . $cls . '"><i class="ti ti-' . $ic . '"></i> ' . $txt . ' <span>vs prev</span></div>';
};
$gaugeJs = fn(array $g) => json_encode(array_map(fn($x)=>['id'=>$x['id'],'arc'=>(float)$x['arc'],'label'=>$x['label'],'name'=>$x['name'],'color'=>$x['color']], $g));
$tabs = $role === 'auditor' ? ['summary'=>'Summary','quality'=>'Quality']
      : ($isValidator ? ['validation'=>'Validation']                             // a pure validator: only the Validation report
      : ['summary'=>'Summary','production'=>'Production','quality'=>'Quality']);
if ($isTeam) $tabs['team'] = 'My team';                                          // supervisor/manager: per-member roll-up
if ($canValReport && !isset($tabs['validation'])) $tabs['validation'] = 'Validation';   // validators + supervisors/managers
$roleLabel = $role==='team' ? ($isManager?'Manager · team rollup':'Supervisor · team')
           : ($role==='auditor'?'Auditor · my audits' : ($role==='validator'?'Validator · RFI / Disregard hub':'Coder · my performance'));

$pageTitle = 'Coding reports';
require __DIR__ . '/../includes/header.php';
?>
<link rel="stylesheet" href="<?= e(url('/admin/coding-ui.css')) ?>">
<div class="cw">
<div class="page-header"><div class="container-xl"><div class="row align-items-center">
    <div class="col"><h2 class="page-title"><i class="ti ti-report-analytics me-2 text-primary"></i>Coding reports
        <span class="badge bg-blue-lt ms-2"><?= e($roleLabel) ?></span></h2>
        <div class="text-secondary small"><?= e(fmt_date($from)) ?> — <?= e(fmt_date($to)) ?></div>
    </div>
    <div class="col-auto"><a href="<?= e($urlFor(['report'=>$report,'by'=>$by,'export'=>'xlsx'])) ?>" class="btn btn-sm btn-outline-success"><i class="ti ti-file-spreadsheet me-1"></i>Excel</a></div>
</div></div></div>

<div class="page-body"><div class="container-xl">
    <ul class="nav nav-tabs mb-3">
        <?php foreach ($tabs as $k=>$lab): ?>
        <li class="nav-item"><a class="nav-link <?= $report===$k?'active':'' ?>" href="<?= e($urlFor(['report'=>$k])) ?>"><?= e($lab) ?></a></li>
        <?php endforeach; ?>
    </ul>

    <!-- filter bar -->
    <div class="card mb-3 cw-tight"><div class="card-body"><form method="GET" class="row g-2 align-items-end">
        <input type="hidden" name="report" value="<?= e($report) ?>"><input type="hidden" name="by" value="<?= e($by) ?>">
        <div class="col-6 col-md-auto"><label class="form-label">From</label><input type="date" name="from" class="form-control form-control-sm" value="<?= e($from) ?>"></div>
        <div class="col-6 col-md-auto"><label class="form-label">To</label><input type="date" name="to" class="form-control form-control-sm" value="<?= e($to) ?>"></div>
        <?php
        $sel = function($name, $opts, $cur) { $h='<select name="'.e($name).'" class="form-select form-select-sm"><option value="">All</option>';
            foreach ($opts as $o) $h.='<option value="'.(int)$o['id'].'"'.($cur===(int)$o['id']?' selected':'').'>'.e($o['name']).'</option>'; return $h.'</select>'; }; ?>
        <div class="col-6 col-md-2"><label class="form-label">Vertical</label><?= $sel('vertical_id',$optVerticals,$f['vertical_id']) ?></div>
        <div class="col-6 col-md-2"><label class="form-label">Client</label><?= $sel('client_id',$optClients,$f['client_id']) ?></div>
        <div class="col-6 col-md-2"><label class="form-label">Process</label><?= $sel('process_id',$optProcesses,$f['process_id']) ?></div>
        <div class="col-6 col-md-2"><label class="form-label">Facility</label><?= $sel('facility_id',$optFac,$f['facility_id']) ?></div>
        <div class="col-6 col-md-2"><label class="form-label">Provider</label><?= $sel('provider_id',$optProv,$f['provider_id']) ?></div>
        <?php if ($isTeam): ?><div class="col-6 col-md-2"><label class="form-label">Coder</label><?= $sel('coder_id',$optCoders,$f['coder_id']) ?></div><?php endif; ?>
        <div class="col-auto"><button class="btn btn-sm btn-primary"><i class="ti ti-filter me-1"></i>Apply</button>
            <a href="<?= e(url('/admin/coding-reports.php?report='.$report)) ?>" class="btn btn-sm btn-ghost-secondary">Clear</a></div>
        <div class="col-auto pt-3"><a href="<?= e($urlFor(['report'=>$report,'from'=>date('Y-m-d',strtotime('-6 days')),'to'=>date('Y-m-d')])) ?>" class="btn btn-sm btn-link px-1">7d</a>
            <a href="<?= e($urlFor(['report'=>$report,'from'=>date('Y-m-01'),'to'=>date('Y-m-d')])) ?>" class="btn btn-sm btn-link px-1">MTD</a></div>
    </form></div></div>

<?php if ($report === 'summary'): ?>
    <div class="rpt-kpis mb-3">
        <?php foreach ($kpis as $k): [$lab,$val,$sub,$col]=$k; ?>
        <div class="rpt-kpi rpt-<?= e($col) ?>"><div class="l"><?= e($lab) ?></div><div class="v"><?= $val ?></div><?php if($sub): ?><div class="s"><?= e($sub) ?></div><?php endif; ?></div>
        <?php endforeach; ?>
    </div>
    <div class="row g-3">
        <div class="col-lg-6"><div class="card"><div class="rpt-h"><i class="ti ti-alert-triangle me-1"></i>Defect categories
            <span class="ms-auto rpt-chips"><span class="rpt-chip cpt">CPT <?= $ecByType['cpt'] ?></span><span class="rpt-chip icd">ICD <?= $ecByType['icd'] ?></span><span class="rpt-chip mod">MOD <?= $ecByType['modifier'] ?></span></span></div>
            <div class="table-responsive"><table class="table table-sm table-vcenter rpt-tbl mb-0">
                <thead><tr><th>Type</th><th>Category</th><th class="text-end">Count</th><th class="text-end">Share</th></tr></thead><tbody>
                <?php foreach ($ecRows as $r): $pct=$ecTotal?round(100*$r['n']/$ecTotal):0; ?>
                    <tr><td><span class="code-tag <?= $r['code_type']==='modifier'?'mod':e($r['code_type']) ?>"><?= $r['code_type']==='modifier'?'MOD':e(strtoupper($r['code_type'])) ?></span></td>
                        <td><?= e($r['cat']) ?></td><td class="text-end"><strong><?= (int)$r['n'] ?></strong></td>
                        <td class="text-end"><span class="rpt-bar" style="--p:<?= $pct ?>%"><i></i><b><?= $pct ?>%</b></span></td></tr>
                <?php endforeach; ?>
                <?php if(!$ecRows): ?><tr><td colspan="4" class="text-center text-secondary py-4">No defects recorded — clean quality.</td></tr><?php endif; ?>
                </tbody></table></div></div></div>
        <div class="col-lg-6"><div class="card"><div class="rpt-h"><i class="ti ti-calendar-stats me-1"></i>Daily activity</div>
            <div class="table-responsive"><table class="table table-sm table-vcenter rpt-tbl mb-0">
                <thead><tr><th>Date</th><?php if($role!=='auditor'): ?><th class="text-end">Completed</th><?php endif; ?><th class="text-end">Audited</th><th class="text-end">Def/Opp</th><th class="text-end">Acc%</th></tr></thead><tbody>
                <?php foreach ($dailyActive as $d=>$v): $q=$acc($v['opp'],$v['def']); ?>
                    <tr><td class="text-nowrap"><?= e(date('D, M j',strtotime($d))) ?></td>
                        <?php if($role!=='auditor'): ?><td class="text-end"><?= $v['completed']?:'<span class="text-secondary">·</span>' ?></td><?php endif; ?>
                        <td class="text-end text-secondary"><?= $v['audited']?:'·' ?></td>
                        <td class="text-end"><?php if($v['opp']): ?><span class="text-<?= $v['def']?'danger':'secondary' ?>"><?= $v['def'] ?></span><span class="text-secondary">/<?= $v['opp'] ?></span><?php else: ?><span class="text-secondary">·</span><?php endif; ?></td>
                        <td class="text-end"><?php if($q===null): ?><span class="text-secondary">—</span><?php else: ?><span class="badge bg-<?= $accCls($q) ?>-lt"><?= $q ?>%</span><?php endif; ?></td></tr>
                <?php endforeach; ?>
                <?php if(!$dailyActive): ?><tr><td colspan="<?= $role==='auditor'?4:5 ?>" class="text-center text-secondary py-4">No activity in this period.</td></tr><?php endif; ?>
                </tbody></table></div></div></div>
    </div>

<?php elseif ($report === 'production'): ?>
    <?php if ($role === 'auditor'): ?>
        <div class="card"><div class="card-body text-center text-secondary py-5">Production figures apply to coders. As an auditor, see the <a href="<?= e($urlFor(['report'=>'quality'])) ?>">Quality</a> report.</div></div>
    <?php else:
        $tot=['completed'=>0,'rfi'=>0,'disregard'=>0,'sampled'=>0,'total'=>0]; foreach ($prodRows as $r) foreach($tot as $k=>$_) $tot[$k]+=(int)$r[$k]; ?>
    <!-- production KPI strip (with vs-prev deltas) -->
    <div class="rpt-kpis mb-3">
        <?php foreach ($prodKpis as $k): [$lab,$val,$sub,$col,$dlt]=array_pad($k,5,null); ?>
        <div class="rpt-kpi rpt-<?= e($col) ?>"><div class="l"><?= e($lab) ?></div><div class="v"><?= $val ?></div>
            <?= $deltaHtml($dlt) ?><?php if($sub): ?><div class="s"><?= e($sub) ?></div><?php endif; ?></div>
        <?php endforeach; ?>
    </div>
    <!-- scorecard gauges + daily trend -->
    <div class="row row-deck row-cards mb-3">
        <div class="col-lg-5"><div class="card h-100"><div class="rpt-h"><i class="ti ti-gauge me-1"></i>Scorecard</div>
            <div class="card-body"><div class="cw-gauges">
                <?php foreach ($prodGauges as $gg): ?><div class="cw-gauge"><div id="<?= e($gg['id']) ?>"></div><div class="cw-gsub"><?= e($gg['sub']) ?></div></div><?php endforeach; ?>
            </div></div></div></div>
        <div class="col-lg-7"><div class="card h-100"><div class="rpt-h"><i class="ti ti-chart-bar me-1"></i>Completed charts · daily trend
            <span class="ms-auto text-secondary" style="text-transform:none;font-weight:600"><?= number_format($pc) ?> in <?= count($daily) ?> days</span></div>
            <div class="card-body py-2"><div id="rptTrend" style="min-height:235px"></div></div></div></div>
    </div>
    <!-- inventory by stage (like runtime/downtime) -->
    <div class="card mb-3"><div class="rpt-h"><i class="ti ti-stack-2 me-1"></i>Inventory by stage
        <span class="ms-auto text-secondary" style="text-transform:none;font-weight:500;font-size:.62rem">Open / In-progress / Hold = current backlog · Completed / RFI / Disregard = selected period</span></div>
        <div class="card-body py-2"><div id="rptStatusBar" style="min-height:160px"></div></div></div>
    <!-- multi-dimension breakdown panels -->
    <div class="rpt-section-h"><i class="ti ti-layout-grid me-1"></i>Production breakdown <span class="text-secondary">— completed volume by dimension</span></div>
    <div class="rpt-panels mb-3">
        <?php foreach ($panels as $pk=>$rows) $renderPanel($pk, $rows, 'prod'); ?>
    </div>
    <!-- detailed pivot table (drill + export) -->
    <div class="card"><div class="rpt-h"><i class="ti ti-table me-1"></i>Detailed · grouped by <?= e($D[0]) ?>
        <span class="ms-3" style="text-transform:none;font-weight:600"><?php require __DIR__ . '/_coding-report-pivot.php'; ?></span>
        <span class="ms-auto text-secondary" style="text-transform:none;font-weight:600"><?= count($prodRows) ?> rows</span></div>
        <div class="table-responsive"><table class="table table-sm table-vcenter rpt-tbl mb-0">
            <thead><tr><th><?= e($D[0]) ?></th><th class="text-end">Completed</th><th class="text-end">RFI</th><th class="text-end">Disreg</th><th class="text-end">Sampled</th><th class="text-end">Total</th><th class="text-end">Avg TAT</th></tr></thead>
            <tbody>
            <?php foreach ($prodRows as $r): ?>
                <tr><td><strong><?= e($r['grp']) ?></strong></td>
                    <td class="text-end"><?= (int)$r['completed'] ?></td>
                    <td class="text-end"><?= (int)$r['rfi']?:'<span class="text-secondary">·</span>' ?></td>
                    <td class="text-end"><?= (int)$r['disregard']?:'<span class="text-secondary">·</span>' ?></td>
                    <td class="text-end text-secondary"><?= (int)$r['sampled'] ?></td>
                    <td class="text-end"><strong><?= (int)$r['total'] ?></strong></td>
                    <td class="text-end text-secondary"><?= $r['tat']!==null?e($r['tat']).'h':'·' ?></td></tr>
            <?php endforeach; ?>
            <?php if(!$prodRows): ?><tr><td colspan="7" class="text-center text-secondary py-4">No production in this period / filter.</td></tr>
            <?php else: ?><tr class="rpt-total"><td>Total</td><td class="text-end"><?= $tot['completed'] ?></td><td class="text-end"><?= $tot['rfi'] ?></td><td class="text-end"><?= $tot['disregard'] ?></td><td class="text-end"><?= $tot['sampled'] ?></td><td class="text-end"><?= $tot['total'] ?></td><td></td></tr><?php endif; ?>
            </tbody></table></div></div>
    <?php endif; ?>

<?php elseif ($report === 'quality'): /* quality */
    $qt=['audited'=>0,'def'=>0,'opp'=>0,'errcharts'=>0,'rebuttals'=>0]; foreach ($qualRows as $r) foreach($qt as $k=>$_) $qt[$k]+=(int)$r[$k]; ?>
    <!-- quality KPI strip (with vs-prev deltas) -->
    <div class="rpt-kpis mb-3">
        <?php foreach ($qualKpis as $k): [$lab,$val,$sub,$col,$dlt]=array_pad($k,5,null); ?>
        <div class="rpt-kpi rpt-<?= e($col) ?>"><div class="l"><?= e($lab) ?></div><div class="v"><?= $val ?></div>
            <?= $deltaHtml($dlt) ?><?php if($sub): ?><div class="s"><?= e($sub) ?></div><?php endif; ?></div>
        <?php endforeach; ?>
    </div>
    <!-- quality scorecard gauges -->
    <div class="card mb-3"><div class="rpt-h"><i class="ti ti-gauge me-1"></i>Quality scorecard</div>
        <div class="card-body"><div class="cw-gauges cw-gauges-row">
            <?php foreach ($qualGauges as $gg): ?><div class="cw-gauge"><div id="<?= e($gg['id']) ?>"></div><div class="cw-gsub"><?= e($gg['sub']) ?></div></div><?php endforeach; ?>
        </div></div></div>
    <div class="row g-3 mb-3">
        <!-- accuracy trend -->
        <div class="col-lg-7"><div class="card h-100"><div class="rpt-h"><i class="ti ti-chart-line me-1"></i>Accuracy (DPO) · daily trend
            <span class="ms-auto text-secondary" style="text-transform:none;font-weight:600"><?= $overallQ===null?'—':$overallQ.'%' ?> overall</span></div>
            <div class="card-body py-2"><div id="rptTrend" style="min-height:200px"></div></div></div></div>
        <!-- defect categories -->
        <div class="col-lg-5"><div class="card h-100"><div class="rpt-h"><i class="ti ti-alert-triangle me-1"></i>Defect categories
            <span class="ms-auto rpt-chips"><span class="rpt-chip cpt">CPT <?= $ecByType['cpt'] ?></span><span class="rpt-chip icd">ICD <?= $ecByType['icd'] ?></span><span class="rpt-chip mod">MOD <?= $ecByType['modifier'] ?></span></span></div>
            <div class="table-responsive" style="max-height:240px"><table class="table table-sm table-vcenter rpt-tbl mb-0">
                <thead><tr><th>Type</th><th>Category</th><th class="text-end">Count</th><th class="text-end">Share</th></tr></thead><tbody>
                <?php foreach ($ecRows as $r): $pct=$ecTotal?round(100*$r['n']/$ecTotal):0; ?>
                    <tr><td><span class="code-tag <?= $r['code_type']==='modifier'?'mod':e($r['code_type']) ?>"><?= $r['code_type']==='modifier'?'MOD':e(strtoupper($r['code_type'])) ?></span></td>
                        <td><?= e($r['cat']) ?></td><td class="text-end"><strong><?= (int)$r['n'] ?></strong></td>
                        <td class="text-end"><span class="rpt-bar" style="--p:<?= $pct ?>%"><i></i><b><?= $pct ?>%</b></span></td></tr>
                <?php endforeach; ?>
                <?php if(!$ecRows): ?><tr><td colspan="4" class="text-center text-secondary py-4">No defects recorded — clean quality.</td></tr><?php endif; ?>
                </tbody></table></div></div></div>
    </div>
    <!-- multi-dimension breakdown panels -->
    <div class="rpt-section-h"><i class="ti ti-layout-grid me-1"></i>Quality breakdown <span class="text-secondary">— audited volume &amp; accuracy by dimension</span></div>
    <div class="rpt-panels mb-3">
        <?php foreach ($panels as $pk=>$rows) $renderPanel($pk, $rows, 'qual'); ?>
    </div>
    <div class="card"><div class="rpt-h"><i class="ti ti-table me-1"></i>Detailed · grouped by <?= e($D[0]) ?>
        <span class="ms-3" style="text-transform:none;font-weight:600"><?php require __DIR__ . '/_coding-report-pivot.php'; ?></span>
        <span class="ms-auto text-secondary" style="text-transform:none;font-weight:600"><?= count($qualRows) ?> rows</span></div>
        <div class="table-responsive"><table class="table table-sm table-vcenter rpt-tbl mb-0">
            <thead><tr><th><?= e($D[0]) ?></th><th class="text-end">Audited</th><th class="text-end">Defects</th><th class="text-end">Opp</th><th class="text-end">Accuracy %</th><th class="text-end">Err charts</th><th class="text-end">Reb</th></tr></thead>
            <tbody>
            <?php foreach ($qualRows as $r): $q=$acc((int)$r['opp'],(int)$r['def']); ?>
                <tr><td><strong><?= e($r['grp']) ?></strong></td>
                    <td class="text-end"><?= (int)$r['audited'] ?></td>
                    <td class="text-end text-<?= (int)$r['def']?'danger':'secondary' ?>"><?= (int)$r['def'] ?></td>
                    <td class="text-end text-secondary"><?= (int)$r['opp'] ?></td>
                    <td class="text-end"><?php if($q===null): ?><span class="text-secondary">—</span><?php else: ?><span class="badge bg-<?= $accCls($q) ?>-lt"><?= $q ?>%</span><?php endif; ?></td>
                    <td class="text-end text-<?= (int)$r['errcharts']?'danger':'secondary' ?>"><?= (int)$r['errcharts'] ?></td>
                    <td class="text-end text-secondary"><?= (int)$r['rebuttals']?:'·' ?></td></tr>
            <?php endforeach; ?>
            <?php if(!$qualRows): ?><tr><td colspan="7" class="text-center text-secondary py-4">No audited charts in this period / filter.</td></tr>
            <?php else: $tq=$acc($qt['opp'],$qt['def']); ?><tr class="rpt-total"><td>Total</td><td class="text-end"><?= $qt['audited'] ?></td><td class="text-end"><?= $qt['def'] ?></td><td class="text-end"><?= $qt['opp'] ?></td><td class="text-end"><?= $tq===null?'—':$tq.'%' ?></td><td class="text-end"><?= $qt['errcharts'] ?></td><td class="text-end"><?= $qt['rebuttals'] ?></td></tr><?php endif; ?>
            </tbody></table></div></div>

<?php elseif ($report === 'team'): ?>
    <?php if ($teamFallback): ?>
        <div class="alert alert-info py-2 px-3 small mb-3"><i class="ti ti-info-circle me-1"></i>No one is mapped under you via <em>reports&nbsp;to</em> yet — showing the members working <strong>your aligned client(s)</strong> (operational team). For a precise org roll-up, set each member's supervisor on the <a href="<?= e(url('/admin/users.php')) ?>">Users</a> page.</div>
    <?php endif; ?>
    <div class="rpt-kpis mb-3">
        <div class="rpt-kpi rpt-default"><div class="l">Team members</div><div class="v"><?= $teamTot['coders'] ?></div><div class="s"><?= count($teamNodes)-$teamTot['coders'] ?> lead(s) · <?= count($teamNodes) ?> total</div></div>
        <div class="rpt-kpi rpt-success"><div class="l">Completed</div><div class="v"><?= number_format($teamTot['completed']) ?></div><div class="s"><?= $teamTot['active'] ?> active · <?= $teamTot['sampled'] ?> sampled</div></div>
        <div class="rpt-kpi rpt-<?= $accCls($teamAcc) ?>"><div class="l">Team accuracy (DPO)</div><div class="v"><?= $teamAcc===null?'—':$teamAcc.'%' ?></div><div class="s"><?= $teamTot['def'] ?>/<?= $teamTot['opp'] ?> defects/opp</div></div>
        <div class="rpt-kpi rpt-orange"><div class="l">RFI / Disregard</div><div class="v"><?= $teamTot['rfi'] ?> / <?= $teamTot['disregard'] ?></div></div>
        <div class="rpt-kpi rpt-default"><div class="l">Open queue</div><div class="v"><?= $teamTot['open'] ?></div></div>
        <div class="rpt-kpi rpt-<?= $teamTot['idle']?'orange':'default' ?>"><div class="l">Idle members</div><div class="v"><?= $teamTot['idle'] ?></div><div class="s">0 completed in range</div></div>
    </div>

    <?php if (!$teamRootIds): ?>
        <div class="card"><div class="card-body text-center text-secondary py-5">
            <i class="ti ti-users-group" style="font-size:2.4rem"></i>
            <div class="mt-2 h4 text-body">No team mapped yet</div>
            <div style="max-width:560px;margin:0 auto">Map your coders so their completed work rolls up here — set each one's supervisor (<em>reports&nbsp;to</em> = you) on the <a href="<?= e(url('/admin/users.php')) ?>">Users</a> page, or align them to your clients on <a href="<?= e(url('/admin/coding-access.php')) ?>">Coder access</a>. Members working your clients then appear automatically.</div>
        </div></div>
    <?php else:
        // highlights
        $withAcc = array_values(array_filter($teamTopN, fn($x)=>$x['acc']!==null && $x['completed']>0));
        $bestAcc=null; $worstAcc=null; foreach ($withAcc as $x){ if($bestAcc===null||$x['acc']>$bestAcc['acc'])$bestAcc=$x; if($worstAcc===null||$x['acc']<$worstAcc['acc'])$worstAcc=$x; }
        $topProd = $teamTopN[0] ?? null; $busiest=null; foreach($teamTopN as $x){ if($busiest===null||$x['open']>$busiest['open'])$busiest=$x; } ?>
        <div class="row g-3 mb-3">
            <div class="col-lg-7"><div class="card h-100"><div class="rpt-h"><i class="ti ti-chart-line me-1"></i>Daily team activity <span class="text-secondary">— completed vs audited (+ accuracy)</span></div>
                <div class="card-body pt-2"><div id="teamTrend" style="min-height:250px"></div></div></div></div>
            <div class="col-lg-5"><div class="card h-100"><div class="rpt-h"><i class="ti ti-chart-donut me-1"></i>Work mix <span class="text-secondary">— this period</span></div>
                <div class="card-body pt-2"><div id="teamMix" style="min-height:250px"></div></div></div></div>
        </div>
        <div class="row g-3 mb-3">
            <div class="col-lg-8"><div class="card h-100"><div class="rpt-h"><i class="ti ti-trophy me-1"></i>Productivity by member <span class="text-secondary">— top <?= count($teamBarNames) ?> by completed</span></div>
                <div class="card-body pt-2"><div id="teamBar" style="min-height:300px"></div></div></div></div>
            <div class="col-lg-4"><div class="card h-100"><div class="rpt-h"><i class="ti ti-bulb me-1"></i>Highlights</div>
                <div class="card-body">
                    <div class="d-flex align-items-center gap-2 mb-3"><span class="avatar avatar-sm bg-green-lt"><i class="ti ti-trophy"></i></span><div><div class="text-secondary small">Top producer</div><div class="fw-medium"><?= $topProd? e($topProd['name']).' · '.$topProd['completed'].' completed' : '—' ?></div></div></div>
                    <div class="d-flex align-items-center gap-2 mb-3"><span class="avatar avatar-sm bg-blue-lt"><i class="ti ti-target-arrow"></i></span><div><div class="text-secondary small">Best accuracy</div><div class="fw-medium"><?= $bestAcc? e($bestAcc['name']).' · '.$bestAcc['acc'].'%' : '—' ?></div></div></div>
                    <div class="d-flex align-items-center gap-2 mb-3"><span class="avatar avatar-sm bg-red-lt"><i class="ti ti-alert-triangle"></i></span><div><div class="text-secondary small">Needs attention</div><div class="fw-medium"><?= $worstAcc && $worstAcc['acc']<95 ? e($worstAcc['name']).' · '.$worstAcc['acc'].'% acc' : ($teamTot['idle'].' idle member'.($teamTot['idle']==1?'':'s')) ?></div></div></div>
                    <div class="d-flex align-items-center gap-2"><span class="avatar avatar-sm bg-orange-lt"><i class="ti ti-inbox"></i></span><div><div class="text-secondary small">Biggest open queue</div><div class="fw-medium"><?= $busiest && $busiest['open']>0 ? e($busiest['name']).' · '.$busiest['open'].' open' : 'none open' ?></div></div></div>
                </div></div></div></div>
        </div>

        <div class="card"><div class="rpt-h"><i class="ti ti-sitemap me-1"></i><?= $isManager ? 'Team tree — supervisors → their coders' : 'My team — each member’s performance' ?>
            <a class="ms-auto rpt-mini-link" href="<?= e($urlFor(['report'=>'team','export'=>'xlsx'])) ?>"><i class="ti ti-file-spreadsheet me-1"></i>Excel</a></div>
            <div class="table-responsive"><table class="table table-sm table-vcenter rpt-tbl mb-0">
                <thead><tr><th>Member</th><th class="text-end">Completed</th><th class="text-end">RFI/Disreg</th><th class="text-end">Sampled</th><th class="text-end">Avg TAT</th><th class="text-end">Accuracy (DPO)</th><th class="text-end">Open</th></tr></thead>
                <tbody>
                <?php foreach ($teamRootIds as $rid) $renderTeamRows($rid, 0); ?>
                    <tr class="rpt-total"><td>Team total</td><td class="text-end"><?= $teamTot['completed'] ?></td><td class="text-end"><?= $teamTot['rfi']+$teamTot['disregard'] ?></td><td class="text-end"><?= $teamTot['sampled'] ?></td><td></td><td class="text-end"><?= $teamAcc===null?'—':$teamAcc.'%' ?></td><td class="text-end"><?= $teamTot['open'] ?></td></tr>
                </tbody></table></div></div>
    <?php endif; ?>

<?php elseif ($report === 'validation'): ?>
    <div class="rpt-kpis mb-3">
        <div class="rpt-kpi rpt-orange"><div class="l">To review (queue)</div><div class="v"><?= number_format($V['toreview']) ?></div><div class="s">coder-flagged · awaiting validation</div></div>
        <div class="rpt-kpi rpt-default"><div class="l">RFI confirmed</div><div class="v"><?= number_format($V['rfi_conf']) ?></div><div class="s">in this period</div></div>
        <div class="rpt-kpi rpt-default"><div class="l">Disregard confirmed</div><div class="v"><?= number_format($V['dis_conf']) ?></div><div class="s">in this period</div></div>
        <div class="rpt-kpi rpt-orange"><div class="l">Sent back to coder</div><div class="v"><?= number_format($V['sent_back']) ?></div><div class="s">rework</div></div>
        <div class="rpt-kpi rpt-success"><div class="l">Sent to client</div><div class="v"><?= number_format($V['sent_client']) ?></div><div class="s">RFI / Disregard delivered</div></div>
        <div class="rpt-kpi rpt-default"><div class="l">Avg turnaround</div><div class="v"><?= $V['tat']!==null?$V['tat'].'h':'—' ?></div><div class="s">flag → decision</div></div>
    </div>
    <div class="row g-3 mb-3">
        <div class="col-lg-6"><div class="card h-100"><div class="rpt-h"><i class="ti ti-user me-1"></i>By coder <span class="text-secondary">— whose charts went to validation</span></div>
            <div class="table-responsive"><table class="table table-sm table-vcenter rpt-tbl mb-0">
                <thead><tr><th>Coder</th><th class="text-end">RFI</th><th class="text-end">Disregard</th><th class="text-end">Sent back</th></tr></thead><tbody>
                <?php foreach ($vByCoder as $r): ?><tr><td><?= e($r['coder']) ?></td><td class="text-end"><?= (int)$r['rfi'] ?></td><td class="text-end"><?= (int)$r['dis'] ?></td><td class="text-end text-<?= (int)$r['sent_back']?'orange':'secondary' ?>"><?= (int)$r['sent_back']?:'·' ?></td></tr><?php endforeach; ?>
                <?php if(!$vByCoder): ?><tr><td colspan="4" class="text-center text-secondary py-4">No validation activity in this period.</td></tr><?php endif; ?>
                </tbody></table></div></div></div>
        <div class="col-lg-6"><div class="card h-100"><div class="rpt-h"><i class="ti ti-list-details me-1"></i>By reason <span class="text-secondary">— confirmed RFI / Disregard</span></div>
            <div class="table-responsive"><table class="table table-sm table-vcenter rpt-tbl mb-0">
                <thead><tr><th>Tag</th><th>Reason</th><th class="text-end">Count</th></tr></thead><tbody>
                <?php foreach ($vByReason as $r): ?><tr><td><span class="badge bg-<?= $r['tag']==='rfi'?'azure':'orange' ?>-lt"><?= e(strtoupper((string)$r['tag'])) ?></span></td><td class="small"><?= e($r['reason']) ?></td><td class="text-end"><strong><?= (int)$r['n'] ?></strong></td></tr><?php endforeach; ?>
                <?php if(!$vByReason): ?><tr><td colspan="3" class="text-center text-secondary py-4">No confirmed RFI / Disregard in this period.</td></tr><?php endif; ?>
                </tbody></table></div></div></div>
    </div>
    <?php if ($vByValidator && (count($vByValidator) > 1 || $isTeam)): ?>
    <div class="card mb-3"><div class="rpt-h"><i class="ti ti-shield-check me-1"></i>By validator <span class="text-secondary">— who validated</span></div>
        <div class="table-responsive"><table class="table table-sm table-vcenter rpt-tbl mb-0">
            <thead><tr><th>Validator</th><th class="text-end">RFI confirmed</th><th class="text-end">Disregard confirmed</th><th class="text-end">Sent back</th><th class="text-end">Total</th></tr></thead><tbody>
            <?php foreach ($vByValidator as $r): ?><tr><td><?= e($r['validator']) ?></td><td class="text-end"><?= (int)$r['rfi'] ?></td><td class="text-end"><?= (int)$r['dis'] ?></td><td class="text-end"><?= (int)$r['sent_back'] ?></td><td class="text-end"><strong><?= (int)$r['rfi']+(int)$r['dis']+(int)$r['sent_back'] ?></strong></td></tr><?php endforeach; ?>
            </tbody></table></div></div>
    <?php endif; ?>
    <div class="card"><div class="rpt-h"><i class="ti ti-calendar-stats me-1"></i>Daily validation activity</div>
        <div class="table-responsive"><table class="table table-sm table-vcenter rpt-tbl mb-0">
            <thead><tr><th>Date</th><th class="text-end">RFI confirmed</th><th class="text-end">Disregard confirmed</th><th class="text-end">Sent back</th></tr></thead><tbody>
            <?php foreach ($vDailyActive as $d=>$v): ?><tr><td class="text-nowrap"><?= e(date('D, M j', strtotime($d))) ?></td><td class="text-end"><?= $v['rfi']?:'·' ?></td><td class="text-end"><?= $v['dis']?:'·' ?></td><td class="text-end text-secondary"><?= $v['back']?:'·' ?></td></tr><?php endforeach; ?>
            <?php if(!$vDailyActive): ?><tr><td colspan="4" class="text-center text-secondary py-4">No validation activity in this period.</td></tr><?php endif; ?>
            </tbody></table></div></div>
<?php endif; ?>
</div></div>
</div><!-- /.cw -->
<?php if ($report === 'team' && $teamRootIds): ?>
<script>
(function(){
  if(!window.ApexCharts) return;
  function isDark(){ return document.documentElement.getAttribute('data-bs-theme')==='dark'; }
  function gridColor(){ return isDark()?'#1e2a44':'#eef0f3'; }
  function axisColor(){ return isDark()?'#97a2b6':'#6c7a89'; }
  var reg=(window._cwCharts=window._cwCharts||{});
  function add(id,opts){ var el=document.querySelector('#'+id); if(!el) return; try{ var c=new ApexCharts(el,opts); c.render(); reg[id]=c; }catch(e){} }
  var labels=<?= json_encode($teamTrendLabels) ?>;
  add('teamTrend',{
    chart:{type:'line',height:260,toolbar:{show:false},fontFamily:'inherit',background:'transparent'}, theme:{mode:isDark()?'dark':'light'},
    series:[{name:'Completed',type:'column',data:<?= json_encode($teamTrendCompleted) ?>},{name:'Audited',type:'column',data:<?= json_encode($teamTrendAudited) ?>},{name:'Accuracy %',type:'line',data:<?= json_encode($teamTrendAcc) ?>}],
    colors:['#2fb344','#cbd5e1','#7048e8'], stroke:{curve:'smooth',width:[0,0,3]}, markers:{size:[0,0,4]}, dataLabels:{enabled:false}, plotOptions:{bar:{borderRadius:2,columnWidth:'55%'}},
    xaxis:{categories:labels,labels:{rotate:0,hideOverlappingLabels:true,style:{colors:axisColor()}}},
    yaxis:[{seriesName:'Completed',labels:{formatter:function(v){return Math.round(v);},style:{colors:axisColor()}}},{seriesName:'Audited',show:false},{seriesName:'Accuracy %',opposite:true,min:0,max:100,labels:{formatter:function(v){return Math.round(v)+'%';},style:{colors:axisColor()}}}],
    tooltip:{shared:true,y:{formatter:function(v){return v==null?'—':v;}}}, grid:{borderColor:gridColor()}, legend:{position:'top',fontSize:'11px',labels:{colors:axisColor()}}
  });
  add('teamMix',{
    chart:{type:'donut',height:260,fontFamily:'inherit',background:'transparent'}, theme:{mode:isDark()?'dark':'light'},
    series:<?= json_encode(array_values($teamStatusMix)) ?>, labels:<?= json_encode(array_keys($teamStatusMix)) ?>,
    colors:['#2fb344','#f76707','#e8590c','#94a3b8'], legend:{position:'bottom',fontSize:'12px',labels:{colors:axisColor()}},
    dataLabels:{enabled:true,formatter:function(v){return Math.round(v)+'%';}}, plotOptions:{pie:{donut:{labels:{show:true,total:{show:true,label:'Charts',color:axisColor()}}}}}
  });
  add('teamBar',{
    chart:{type:'bar',height:Math.max(260,<?= count($teamBarNames) ?>*26+40),toolbar:{show:false},fontFamily:'inherit',background:'transparent'}, theme:{mode:isDark()?'dark':'light'},
    series:[{name:'Completed',data:<?= json_encode($teamBarCompleted) ?>}], colors:['#206bc4'], plotOptions:{bar:{horizontal:true,borderRadius:3,barHeight:'62%'}}, dataLabels:{enabled:true,style:{fontSize:'11px'}},
    xaxis:{categories:<?= json_encode($teamBarNames) ?>,labels:{style:{colors:axisColor()}}}, yaxis:{labels:{style:{colors:axisColor()}}}, grid:{borderColor:gridColor()}
  });
})();
</script>
<?php endif; ?>
<?php $isProd = ($report==='production' && $role!=='auditor'); if ($isProd || $report === 'quality'): ?>
<script>
(function(){
  if(!window.ApexCharts) return;
  function isDark(){ return document.documentElement.getAttribute('data-bs-theme')==='dark'; }
  function gridColor(){ return isDark()?'#1e2a44':'#eef0f3'; }
  function axisColor(){ return isDark()?'#97a2b6':'#6c7a89'; }
  var reg = (window._cwCharts = window._cwCharts || {});
  function add(id,opts){ var el=document.querySelector('#'+id); if(!el) return; try{ var c=new ApexCharts(el,opts); c.render(); reg[id]=c; }catch(e){} }
  var labels = <?= json_encode($trendLabels) ?>, MODE = <?= json_encode($report) ?>;

  /* daily trend */
  if (MODE==='production') {
    add('rptTrend',{
      chart:{type:'bar',height:235,toolbar:{show:false},fontFamily:'inherit',background:'transparent'},
      theme:{mode:isDark()?'dark':'light'}, series:[{name:'Completed',data:<?= json_encode($trendCompleted) ?>}],
      colors:['#2fb344'], plotOptions:{bar:{borderRadius:3,columnWidth:'55%'}}, dataLabels:{enabled:false},
      xaxis:{categories:labels,labels:{rotate:0,hideOverlappingLabels:true,style:{colors:axisColor()}}},
      yaxis:{labels:{formatter:function(v){return Math.round(v);},style:{colors:axisColor()}}}, grid:{borderColor:gridColor()}
    });
  } else {
    add('rptTrend',{
      chart:{type:'line',height:235,toolbar:{show:false},fontFamily:'inherit',background:'transparent'},
      theme:{mode:isDark()?'dark':'light'}, series:[{name:'Accuracy %',type:'line',data:<?= json_encode($trendAcc) ?>},{name:'Audited',type:'column',data:<?= json_encode($trendAudited) ?>}],
      colors:['#7048e8','#cbd5e1'], stroke:{curve:'smooth',width:[3,0]}, markers:{size:[4,0]}, dataLabels:{enabled:false},
      plotOptions:{bar:{borderRadius:2,columnWidth:'45%'}},
      xaxis:{categories:labels,labels:{rotate:0,hideOverlappingLabels:true,style:{colors:axisColor()}}},
      yaxis:[{seriesName:'Accuracy %',min:0,max:100,labels:{formatter:function(v){return Math.round(v)+'%';},style:{colors:axisColor()}}},
             {seriesName:'Audited',opposite:true,labels:{formatter:function(v){return Math.round(v);},style:{colors:axisColor()}}}],
      tooltip:{shared:true,y:{formatter:function(v){return v==null?'—':v;}}}, grid:{borderColor:gridColor()}, legend:{position:'top',fontSize:'11px',labels:{colors:axisColor()}}
    });
  }

  /* scorecard gauges */
  var gauges = <?= $isProd ? $gaugeJs($prodGauges) : $gaugeJs($qualGauges) ?>;
  gauges.forEach(function(g){
    add(g.id,{
      chart:{type:'radialBar',height:200,background:'transparent'},
      theme:{mode:isDark()?'dark':'light'}, series:[g.arc], labels:[g.name], colors:[g.color],
      plotOptions:{radialBar:{startAngle:-135,endAngle:135,hollow:{size:'56%'},
        track:{background:isDark()?'#1e2a44':'#e2e8f0',strokeWidth:'100%'},
        dataLabels:{name:{offsetY:22,color:axisColor(),fontSize:'11px'},
          value:{offsetY:-6,formatter:function(){return g.label;},fontSize:'21px',fontWeight:700,color:isDark()?'#e7ecf5':'#0f172a'}}}},
      fill:{type:'gradient',gradient:{shade:'light',type:'horizontal',shadeIntensity:.3,gradientToColors:[g.color],opacityFrom:1,opacityTo:1,stops:[0,100]}}
    });
  });

<?php if ($isProd): ?>
  /* inventory by stage */
  add('rptStatusBar',{
    chart:{type:'bar',height:160,toolbar:{show:false},fontFamily:'inherit',background:'transparent'},
    theme:{mode:isDark()?'dark':'light'}, series:[{name:'Charts',data:<?= json_encode(array_values($statusBar)) ?>}],
    plotOptions:{bar:{borderRadius:3,columnWidth:'45%',distributed:true}}, dataLabels:{enabled:true,offsetY:-18,style:{colors:[axisColor()]}},
    legend:{show:false}, colors:['#f59e0b','#0ea5e9','#94a3b8','#2fb344','#f76707','#d6336c'],
    xaxis:{categories:<?= json_encode(array_keys($statusBar)) ?>,labels:{style:{colors:axisColor()}}},
    yaxis:{labels:{formatter:function(v){return Math.round(v);},style:{colors:axisColor()}}}, grid:{borderColor:gridColor()}
  });
<?php endif; ?>

  window.addEventListener('m-theme-change',function(e){
    var dark=e.detail&&e.detail.theme==='dark';
    Object.keys(reg).forEach(function(k){ try{ reg[k].updateOptions({theme:{mode:dark?'dark':'light'}},false,true);}catch(err){} });
  });
})();
</script>
<?php endif; ?>
<?php require __DIR__ . '/../includes/footer.php'; ?>
