<?php
/**
 * AR / Collections inventory allocation (ar.allocate) — the SUPERVISOR's console.
 *
 * Allocates `collection_raw` inventory (unit = a whole patient: process_id + chart_number) to AR users and
 * manages those allocations. ALL business logic lives in includes/ar.php — this page is purely the UI.
 *
 * Layout: a SHARED filter bar (vertical / process / carrier(multi) / DOS) drives context, then four TABS —
 *   1. Run allocation         — preview + run form (pick team users; priority is automatic).
 *   2. Current allocation     — this process's allocated rows; reassign / send-to-origin.
 *   3. Pull back untouched    — reset allocated-but-never-worked claims to origin.
 *   4. Reallocate by follow-up — redistribute worked inventory by next-follow-up / last-worked.
 * (Force allocation lives on its own page, linked below.)
 *
 * SCOPING: a supervisor/manager only ever allocates to / reassigns among their OWN reporting team
 * (ar_team_scope → reports_to tree); SysAdmin sees everyone. Enforced on every write, mirrored in the UI.
 *
 * GET filter state (incl. the active tab) is preserved across the PRG redirects.
 */
require_once __DIR__ . '/../includes/config.php';
$user = require_login('internal');
$pdo  = db();
$uid  = (int) $user['id'];

$team   = ar_team_scope($pdo, $uid);                       // null = unrestricted (sysadmin); else team ids incl self
$inTeam = fn(int $id) => $team === null || in_array($id, $team, true);

/* ---- Current GET filter state (also re-applied on redirect after a POST) ---- */
$fVertical = (int) ($_GET['vertical_id'] ?? 0);
$fProcess  = (int) ($_GET['process_id'] ?? 0);
$fCarriers = array_values(array_unique(array_filter(array_map('strval', (array) ($_GET['carrier'] ?? [])), fn($s) => $s !== '')));
$fDosYear  = (int) ($_GET['dos_year'] ?? 0);
$fDosMonths = array_values(array_unique(array_filter(array_map('intval', (array) ($_GET['dos_month'] ?? [])), fn($m) => $m >= 1 && $m <= 12)));
$fSeq      = in_array($_GET['seq'] ?? '', ['primary', 'secondary'], true) ? (string) $_GET['seq'] : '';   // Allocation sequence filter
$fInvStat  = in_array($_GET['inv_status'] ?? '', ['unallocated', 'allocated', 'worked_due', 'worked_waiting'], true) ? (string) $_GET['inv_status'] : '';   // lifecycle status filter (export/view)
/** Human labels for the lifecycle statuses (reused by the filter, breakdown, and export). */
$AR_STATUS_LABELS = ['unallocated' => 'Unallocated', 'allocated' => 'Allocated – yet to work',
    'worked_due' => 'Worked – completed – eligible to reallocate', 'worked_waiting' => 'Worked – completed – not eligible (awaiting follow-up)'];
$fTab      = in_array($_GET['tab'] ?? '', ['run', 'current', 'pullback', 'reallocate'], true) ? $_GET['tab'] : 'run';
/* Follow-up pull-back scope (Reallocate tab): 'waiting' = follow-up still in the future (the unreachable
 * inventory — the honest default); 'all' also takes already-due follow-ups, which Run allocation would
 * redistribute on its own via rework='repool'. */
$fHold     = ($_GET['hold'] ?? '') === 'all' ? 'all' : 'waiting';

/** Build the page URL preserving the current filter context + active tab (for redirects + tab links). */
$ctx = array_filter([
    'vertical_id' => $fVertical ?: null,
    'process_id'  => $fProcess ?: null,
    'carrier'     => $fCarriers ?: null,
    'dos_year'    => $fDosYear ?: null,
    'dos_month'   => $fDosMonths ?: null,
    'seq'         => $fSeq ?: null,
    'inv_status'  => $fInvStat ?: null,
    'hold'        => $fHold !== 'waiting' ? $fHold : null,
    'tab'         => $fTab !== 'run' ? $fTab : null,
]);
$selfUrl = fn(array $over = []) => '/admin/ar-allocation.php'
    . (($q = array_merge($ctx, $over)) ? ('?' . http_build_query($q)) : '');

/* ---- Excel export: the FOLLOW-UP HOLD list (Reallocate tab) — exactly the accounts the pull-back button acts on,
       so the supervisor can review (or keep a record of) them before releasing. Team-scoped like every read here. ---- */
if (($_GET['export'] ?? '') === 'followup') {
    if ($fProcess && !ar_process_in_ar_vertical($pdo, $fProcess)) { flash('error', 'That process is not an AR/Collections process.'); redirect($selfUrl(['tab' => 'reallocate'])); }
    $rows = ar_followup_hold_rows($pdo, $team, $fProcess ?: null, $fHold);
    $holdLabel = ['waiting' => 'Awaiting follow-up', 'due' => 'Follow-up due', 'not_worked' => 'Not yet worked'];
    $out = [];
    foreach ($rows as $r) {
        $out[] = [
            $r['cname'] . ' · ' . $r['pname'], $r['chart_number'], (string) ($r['patient_name'] ?? ''),
            (string) ($r['visit_id'] ?? ''), (string) ($r['carrier_name'] ?? ''), fmt_date($r['dos'] ?? null),
            round((float) ($r['insurance_balance'] ?? 0), 2), $r['owner_name'],
            $holdLabel[$r['hold_state']] ?? $r['hold_state'],
            fmt_date($r['last_worked_date'] ?? null), (string) ($r['claim_status'] ?? ''), (string) ($r['action_taken'] ?? ''),
            fmt_date($r['next_follow_up_date'] ?? null), (string) ($r['notes'] ?? ''),
        ];
    }
    require_once __DIR__ . '/../includes/xlsx.php';
    $x = new SimpleXlsx();
    $x->addSheet('Follow-up hold', ['Process', 'Account #', 'Patient', 'Visit ID', 'Carrier', 'DOS', 'Insurance balance',
        'Current owner', 'Hold state', 'Last worked', 'Claim status', 'Action taken', 'Next follow-up', 'Notes'], $out);
    audit_log('ar.followup.export', 'process', $fProcess ?: null, null, ['rows' => count($out), 'scope' => $fHold]);
    $x->download('ar-followup-hold' . ($fProcess ? '-p' . $fProcess : '') . '-' . $fHold . '.xlsx');
    exit;
}

/* ---- Excel export: the CURRENT-ALLOCATION detail (Current tab) — every allocated visit with its owner + work
       state, the full detail behind the on-screen user-wise summary. Team-scoped + honours carrier/DOS filters. ---- */
if (($_GET['export'] ?? '') === 'current') {
    if (!$fProcess || !ar_process_in_ar_vertical($pdo, $fProcess)) { flash('error', 'Pick an AR/Collections process first, then export.'); redirect($selfUrl(['tab' => 'current'])); }
    // drop carriers not in THIS process so the export mirrors the screen (the on-screen scrub runs later, after exports exit)
    $fCarriers = array_values(array_intersect($fCarriers, array_map('strval', ar_process_carriers($pdo, $fProcess))));
    $cw = ''; $cp = [$fProcess];
    if ($fCarriers) { $cw .= " AND v.carrier_name IN (" . implode(',', array_fill(0, count($fCarriers), '?')) . ")"; foreach ($fCarriers as $c) $cp[] = $c; }
    if ($fDosYear)   { $cw .= " AND YEAR(v.dos)=?";  $cp[] = $fDosYear; }
    if ($fDosMonths) { $cw .= " AND MONTH(v.dos) IN (" . implode(',', array_fill(0, count($fDosMonths), '?')) . ")"; foreach ($fDosMonths as $m) $cp[] = $m; }
    $st = $pdo->prepare("SELECT v.chart_number, v.visit_id, v.carrier_name, v.dos, a.allocation_type, v.priority,
                                v.inventory_status, v.last_worked_date, v.claim_status, v.action_taken,
                                v.next_follow_up_date, v.insurance_balance,
                                COALESCE(u.name, CONCAT('(deleted user #', v.allocated_user, ')')) user_name
            FROM ar_visit_work v
            JOIN ar_allocation a ON a.process_id = v.process_id AND a.chart_number = v.chart_number
            LEFT JOIN users u ON u.id = v.allocated_user
            WHERE v.process_id = ? AND v.allocated_user IS NOT NULL" . coding_team_in_sql($team, 'v.allocated_user') . "$cw
            ORDER BY user_name, v.priority, v.chart_number, v.visit_id");
    $st->execute($cp); $rows = $st->fetchAll();
    // patient names (per-visit) from collection_raw, keyed chart|visit — matches the run-tab export idiom
    $patient = []; $rids = ar_process_report_ids($pdo, $fProcess);
    if ($rids) {
        $in = implode(',', array_map('intval', $rids));
        foreach ($pdo->query("SELECT chart_number, visit_id, MAX(TRIM(CONCAT(COALESCE(patient_last_name,''),', ',COALESCE(patient_first_name,'')))) pt
                              FROM collection_raw WHERE report_id IN ($in) GROUP BY chart_number, visit_id") as $r)
            $patient[$r['chart_number'] . '|' . $r['visit_id']] = trim((string) $r['pt'], ', ');
    }
    $out = [];
    foreach ($rows as $r) {
        $out[] = [
            $r['user_name'], $r['chart_number'], $patient[$r['chart_number'] . '|' . $r['visit_id']] ?? '',
            $r['visit_id'], $r['carrier_name'], fmt_date($r['dos']),
            AR_ALLOC_TYPES[$r['allocation_type']] ?? ($r['allocation_type'] ?? ''),
            AR_PRIORITIES[$r['priority']] ?? ($r['priority'] ?? ''),
            $r['inventory_status'] !== null ? str_replace('_', ' ', $r['inventory_status']) : '',
            round((float) ($r['insurance_balance'] ?? 0), 2),
            fmt_date($r['last_worked_date'] ?? null), (string) ($r['claim_status'] ?? ''),
            (string) ($r['action_taken'] ?? ''), fmt_date($r['next_follow_up_date'] ?? null),
        ];
    }
    require_once __DIR__ . '/../includes/xlsx.php';
    $x = new SimpleXlsx();
    $x->addSheet('Current allocation', ['User', 'Account #', 'Patient', 'Visit ID', 'Carrier', 'DOS', 'Type', 'Priority',
        'Status', 'Insurance balance', 'Last worked', 'Claim status', 'Action taken', 'Next follow-up'], $out);
    audit_log('ar.allocation.current.export', 'process', $fProcess, null, ['rows' => count($out)]);
    $x->download('ar-current-allocation-p' . $fProcess . '.xlsx');
    exit;
}

/* ---- Excel export: the allocable candidate ("supporting data") for the current filters (process/carrier/DOS/seq) ---- */
if (($_GET['export'] ?? '') === 'xlsx') {
    if (!$fProcess || !ar_process_in_ar_vertical($pdo, $fProcess)) { flash('error', 'Pick an AR/Collections process first, then export.'); redirect($selfUrl(['tab' => 'run'])); }
    // drop carriers not in THIS process FOR THIS SEQUENCE so the export mirrors the (seq-aware) screen dropdown
    $fCarriers = array_values(array_intersect($fCarriers, array_map('strval', ar_process_carriers($pdo, $fProcess, $fSeq ?: null))));
    $rows = ar_status_visits($pdo, [
        'process_id' => $fProcess, 'carrier' => $fCarriers ?: null,
        'dos_year' => $fDosYear ?: null, 'dos_month' => $fDosMonths ?: null, 'seq' => $fSeq ?: null,
        'status' => $fInvStat ?: null,
    ]);
    $patient = []; $rids = ar_process_report_ids($pdo, $fProcess);
    if ($rids) {
        $in = implode(',', array_map('intval', $rids));
        foreach ($pdo->query("SELECT chart_number, visit_id, MAX(TRIM(CONCAT(COALESCE(patient_last_name,''),', ',COALESCE(patient_first_name,'')))) pt
                              FROM collection_raw WHERE report_id IN ($in) GROUP BY chart_number, visit_id") as $r)
            $patient[$r['chart_number'] . '|' . $r['visit_id']] = trim((string) $r['pt'], ', ');
    }
    // process (+ client) name for the new Process column — constant for this single-process export
    $pn = $pdo->prepare("SELECT c.name cname, p.name pname FROM processes p JOIN clients c ON c.id=p.client_id WHERE p.id=?");
    $pn->execute([$fProcess]); $pr = $pn->fetch(); $procName = $pr ? ($pr['cname'] . ' · ' . $pr['pname']) : ('Process #' . $fProcess);
    $seqLabel  = fn($t) => [1 => 'Primary', 2 => 'Secondary', 3 => 'Tertiary'][(int) $t] ?? '—';
    $out = [];
    foreach ($rows as $r) {
        $out[] = [
            $procName, $r['chart_number'], $r['visit_id'],
            $patient[$r['chart_number'] . '|' . $r['visit_id']] ?? '',
            (string) ($r['facility'] ?? ''), (string) ($r['provider_name'] ?? ''),
            $r['carrier_name'], fmt_date($r['min_dos']),
            round((float) $r['ins_bal'], 2), $seqLabel($r['tier']),
            $AR_STATUS_LABELS[$r['status']] ?? $r['status'],
            $r['owner_name'] ?: ($r['status'] === 'unallocated' ? 'Unallocated' : '—'),
            fmt_date($r['last_worked_date'] ?? null), fmt_date($r['next_follow_up_date'] ?? null),
        ];
    }
    require_once __DIR__ . '/../includes/xlsx.php';
    $x = new SimpleXlsx();
    $x->addSheet('AR inventory', ['Process', 'Account #', 'Visit ID', 'Patient', 'Facility', 'Provider', 'Carrier', 'DOS', 'Insurance balance', 'Sequence', 'Status', 'Current owner', 'Last worked', 'Next follow-up'], $out);
    audit_log('ar.allocation.export', 'process', $fProcess, null, ['rows' => count($out), 'seq' => $fSeq, 'status' => $fInvStat, 'dos_year' => $fDosYear, 'carriers' => $fCarriers]);
    $x->download('ar-inventory-p' . $fProcess . ($fInvStat ? '-' . $fInvStat : '') . ($fSeq ? '-' . $fSeq : '') . '.xlsx');
    exit;
}

/* ============================================================================ POST HANDLERS (PRG) */
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    csrf_check_or_die();
    if (!can('ar.allocate')) { http_response_code(403); exit('Forbidden'); }
    $act = (string) ($_POST['action'] ?? '');

    if ($act === 'run_allocation') {
        $pid      = (int) ($_POST['process_id'] ?? 0);
        $carriers = array_values(array_unique(array_filter(array_map('strval', (array) ($_POST['carrier'] ?? [])), fn($s) => $s !== '')));
        $dosYear  = (int) ($_POST['dos_year'] ?? 0);
        $dosMonths = array_values(array_unique(array_filter(array_map('intval', (array) ($_POST['dos_month'] ?? [])), fn($m) => $m >= 1 && $m <= 12)));
        $seq       = in_array($_POST['seq'] ?? '', ['primary', 'secondary'], true) ? (string) $_POST['seq'] : '';
        // team fence: a supervisor can only allocate to their own team (sysadmin = all)
        $userIds  = array_values(array_filter(array_map('intval', (array) ($_POST['user_ids'] ?? [])), $inTeam));
        $rework   = (($_POST['rework'] ?? 'keep') === 'repool') ? 'repool' : 'keep';
        if (!$pid)                                       { flash('error', 'Pick a process to allocate.'); }
        elseif (!ar_process_in_ar_vertical($pdo, $pid))  { flash('error', 'That process is not an AR/Collections process.'); }
        elseif (!$userIds)                               { flash('error', 'Pick at least one user on your team to allocate to.'); }
        else {
            $res = ar_run_allocation($pdo, [
                'process_id' => $pid,
                'carrier'    => $carriers ?: null,
                'dos_year'   => $dosYear ?: null,
                'dos_month'  => $dosMonths ?: null,
                'seq'        => $seq ?: null,
                'rework'     => $rework,
            ], $userIds, $uid);
            $nv = (int) $res['visits']; $na = (int) $res['accounts'];
            $m  = count(array_filter($res['per_user'] ?? [], fn($c) => $c > 0));
            if ($nv > 0) flash('success', "Allocated $nv visit(s) across $na account(s) to $m user(s).");
            else         flash('error', 'No allocable visits matched (already allocated, worked-and-awaiting-follow-up, or no insurance balance).');
        }
        redirect($selfUrl(['process_id' => $pid, 'carrier' => $carriers ?: null, 'dos_year' => $dosYear ?: null, 'dos_month' => $dosMonths ?: null, 'seq' => $seq ?: null, 'tab' => 'run']));
    }

    if ($act === 'reassign') {
        $ids    = array_values(array_filter(array_map('intval', (array) ($_POST['ids'] ?? []))));
        $toUser = (int) ($_POST['to_user'] ?? 0);   // 0 / '' = back to origin
        if (!$ids)                                  { flash('error', 'Select at least one claim to reassign.'); }
        elseif ($toUser && !$inTeam($toUser))       { flash('error', 'You can only reassign to a user on your own team.'); }
        else {
            $n = ar_reassign($pdo, $ids, $toUser ?: null, $uid, $team);   // $team fences source + destination
            flash('success', $toUser ? "Reassigned $n claim(s) to the selected user." : "Sent $n claim(s) back to origin (unallocated).");
        }
        redirect($selfUrl(['tab' => 'current']));
    }

    if ($act === 'pullback') {
        // process AND user are both optional now → omit both = pull back ALL untouched (team-scoped).
        $tgPid    = (int) ($_POST['process_id'] ?? 0);
        $onlyUser = (int) ($_POST['only_user'] ?? 0);
        if ($tgPid && !ar_process_in_ar_vertical($pdo, $tgPid)) { flash('error', 'That process is not an AR/Collections process.'); }
        elseif ($onlyUser && !$inTeam($onlyUser))               { flash('error', 'That user is not on your team.'); }
        else {
            // $team fences the SOURCE → a supervisor only pulls back their OWN team's untouched claims (sysadmin = all)
            $n = ar_pullback_untouched($pdo, $tgPid ?: null, $onlyUser ?: null, $uid, $team);
            flash($n ? 'success' : 'info', "Pulled $n untouched account(s) back to origin.");
        }
        redirect($selfUrl(['tab' => 'pullback']));
    }

    if ($act === 'pullback_followup') {
        // Release accounts whose worked visits are sitting on a follow-up hold, back to the allocable pool.
        // Work + audits are PRESERVED (unlike 'pullback'/send-to-origin) — see ar_pullback_followup().
        $tgPid    = (int) ($_POST['process_id'] ?? 0);
        $onlyUser = (int) ($_POST['only_user'] ?? 0);
        $scope    = ($_POST['hold'] ?? '') === 'all' ? 'all' : 'waiting';
        if ($tgPid && !ar_process_in_ar_vertical($pdo, $tgPid)) { flash('error', 'That process is not an AR/Collections process.'); }
        elseif ($onlyUser && !$inTeam($onlyUser))               { flash('error', 'That user is not on your team.'); }
        else {
            // $team fences the SOURCE → a supervisor only ever releases their OWN team's accounts (sysadmin = all)
            $res = ar_pullback_followup($pdo, $tgPid ?: null, $onlyUser ?: null, $uid, $team, $scope);
            $na = (int) $res['accounts']; $nv = (int) $res['visits'];
            if ($na) flash('success', "Pulled back $na account(s) ($nv worked visit(s)) from follow-up hold — work history kept; they are allocable again.");
            else     flash('info', 'No accounts matched — none on follow-up hold, or all were held back by a pending hand-off / open rebuttal.');
        }
        redirect($selfUrl(['process_id' => $tgPid ?: null, 'hold' => $scope !== 'waiting' ? $scope : null, 'tab' => 'reallocate']));
    }

    if ($act === 'reallocate') {
        $pid     = (int) ($_POST['process_id'] ?? 0);
        $userIds = array_values(array_filter(array_map('intval', (array) ($_POST['user_ids'] ?? [])), $inTeam));
        if (!$pid)                                      { flash('error', 'Pick a process first.'); }
        elseif (!ar_process_in_ar_vertical($pdo, $pid)) { flash('error', 'That process is not an AR/Collections process.'); }
        elseif (!$userIds) { flash('error', 'Pick at least one user on your team to redistribute across.'); }
        else {
            $n = ar_reallocate_followup($pdo, $pid, $userIds, $uid, $team);   // $team fences the redistributed inventory
            flash('success', "Re-distributed $n claim(s) by follow-up / last-worked date.");
        }
        redirect($selfUrl(['process_id' => $pid, 'tab' => 'reallocate']));
    }

    redirect($selfUrl());
}

/* ============================================================================ GET — load page data */

// AR allocation works ONLY the AR vertical — show just AR-group verticals (robust to dedup-suffixed codes).
$verticals = array_values(array_filter(
    $pdo->query("SELECT id, code, name FROM verticals WHERE deleted_at IS NULL AND status='active' ORDER BY name")->fetchAll(),
    fn($v) => app_vertical_group_canonical($v) === 'ar'
));
$arVerticalIds = array_map(fn($v) => (int) $v['id'], $verticals);
if ($fVertical && !in_array($fVertical, $arVerticalIds, true)) $fVertical = 0;
if (!$fVertical && count($verticals) === 1) $fVertical = (int) $verticals[0]['id'];

$processes = [];
if ($fVertical) {
    $st = $pdo->prepare("SELECT p.id, p.name, c.name AS client_name
        FROM processes p JOIN clients c ON c.id = p.client_id
        WHERE c.vertical_id = ? AND p.deleted_at IS NULL AND c.deleted_at IS NULL
        ORDER BY c.name, p.name");
    $st->execute([$fVertical]);
    $processes = $st->fetchAll();
}
$procIds = array_map(fn($p) => (int) $p['id'], $processes);
if ($fProcess && $procIds && !in_array($fProcess, $procIds, true)) { $fProcess = 0; }
if ($fProcess && !ar_process_in_ar_vertical($pdo, $fProcess)) { $fProcess = 0; }

/* Allocatable users — the people who report UNDER this supervisor/manager (reports_to tree), EXCLUDING the
 * actor themselves (a supervisor never allocates to their own name). Sysadmin sees everyone (minus self). */
$users = ar_allocatable_users($pdo);
$users = array_values(array_filter($users, fn($u) => (int) $u['id'] !== $uid && ($team === null || in_array((int) $u['id'], $team, true))));

// Carrier dropdown is seq-aware: seq=secondary lists the secondary/tertiary carriers (the ones actually worked),
// matching the WORKING-carrier the candidate/status queries now filter on.
$carriers = $fProcess ? ar_process_carriers($pdo, $fProcess, $fSeq ?: null) : [];
$fCarriers = array_values(array_intersect($fCarriers, array_map('strval', $carriers)));   // drop carriers not in this process/sequence

/* Preview (RUN tab): allocable VISIT counts by tier — computed in SQL (no longer fetches every candidate row). */
$preview = ['visits' => 0, 'accounts' => 0, 1 => 0, 2 => 0, 3 => 0];
if ($fTab === 'run' && $fProcess) {
    $preview = ar_candidate_preview($pdo, [
        'process_id' => $fProcess,
        'carrier'    => $fCarriers ?: null,
        'dos_year'   => $fDosYear ?: null,
        'dos_month'  => $fDosMonths ?: null,
        'seq'        => $fSeq ?: null,
    ]);
}
/* Lifecycle status breakdown (RUN tab) — Unallocated / Allocated-yet-to-work / Worked-completed for the filters. */
$statusCounts = ['unallocated' => 0, 'allocated' => 0, 'worked' => 0];
if ($fTab === 'run' && $fProcess) {
    $statusCounts = ar_status_counts($pdo, [
        'process_id' => $fProcess, 'carrier' => $fCarriers ?: null,
        'dos_year' => $fDosYear ?: null, 'dos_month' => $fDosMonths ?: null, 'seq' => $fSeq ?: null,
    ]);
}

/* Current allocation (CURRENT tab) — one row per VISIT; the reassign checkbox carries the ACCOUNT id. */
$allocRows = []; $allocSummary = [];
if ($fTab === 'current' && $fProcess) {
    // SOURCE team fence (matches the reassign write) + the shared carrier/DOS filters the bar advertises.
    $cw = ''; $cp = [$fProcess];
    if ($fCarriers) { $cw .= " AND v.carrier_name IN (" . implode(',', array_fill(0, count($fCarriers), '?')) . ")"; foreach ($fCarriers as $c) $cp[] = $c; }
    if ($fDosYear)   { $cw .= " AND YEAR(v.dos)=?";  $cp[] = $fDosYear; }
    if ($fDosMonths) { $cw .= " AND MONTH(v.dos) IN (" . implode(',', array_fill(0, count($fDosMonths), '?')) . ")"; foreach ($fDosMonths as $m) $cp[] = $m; }
    $st = $pdo->prepare("SELECT a.id AS alloc_id, v.chart_number, v.visit_id, v.carrier_name, v.dos,
                                a.allocation_type, v.priority, v.inventory_status, v.last_worked_date,
                                v.claim_status, v.action_taken, v.next_follow_up_date, v.insurance_balance,
                                v.allocated_user, u.name AS user_name
            FROM ar_visit_work v
            JOIN ar_allocation a ON a.process_id = v.process_id AND a.chart_number = v.chart_number
            LEFT JOIN users u ON u.id = v.allocated_user
            WHERE v.process_id = ? AND v.allocated_user IS NOT NULL" . coding_team_in_sql($team, 'v.allocated_user') . "$cw
            ORDER BY u.name, v.priority, v.chart_number, v.visit_id
            LIMIT 5000");
    $st->execute($cp);
    $allocRows = $st->fetchAll();

    // user-wise SUMMARY over the FULL set (not the display cap) — the default view on this tab; detail expands under it.
    $sm = $pdo->prepare("SELECT v.allocated_user uid, u.name uname,
                COUNT(DISTINCT v.chart_number) accounts, COUNT(*) visits,
                COALESCE(SUM(v.inventory_status='worked'),0) worked,
                ROUND(COALESCE(SUM(v.insurance_balance),0),2) ins_bal
            FROM ar_visit_work v LEFT JOIN users u ON u.id = v.allocated_user
            WHERE v.process_id = ? AND v.allocated_user IS NOT NULL" . coding_team_in_sql($team, 'v.allocated_user') . "$cw
            GROUP BY v.allocated_user, u.name ORDER BY u.name");
    $sm->execute($cp);
    $allocSummary = $sm->fetchAll();
}
$allocAccounts = count(array_unique(array_map(fn($r) => $r['chart_number'], $allocRows)));
/* group the (capped) detail rows by owner so each summary row can expand to its own visit table */
$allocByUser = [];
foreach ($allocRows as $r) $allocByUser[(int) $r['allocated_user']][] = $r;

/* Pull-back tab: a PROCESS-INDEPENDENT overview of all untouched inventory (team-scoped) — total + by-process + by-user. */
$untouched = ($fTab === 'pullback') ? ar_untouched_breakdown($pdo, $team) : null;

/* Reallocate tab: the FOLLOW-UP HOLD dashboard — accounts whose worked visits are parked on a follow-up date.
 * Process-scoped like the rest of this tab (heavy query, so gated on the tab AND a chosen process). */
$hold = ($fTab === 'reallocate' && $fProcess) ? ar_followup_hold_breakdown($pdo, $team, $fProcess, $fHold) : null;

/* Reallocate tab: FOLLOW-UP-DUE summary (worked, follow-up arrived, ready to reallocate) grouped client»process»
 * carrier by visit count — process-INDEPENDENT (honours the filter bar's process if one is picked). Team-scoped. */
$dueSummary = ($fTab === 'reallocate') ? ar_followup_due_summary($pdo, $team, $fProcess ?: null) : null;

/* Run tab: each candidate user's EXISTING open (allocated-but-unworked) workload, so the supervisor can see who is
 * already loaded before distributing more. Global across processes (a user busy elsewhere is still busy). */
$userLoad = ($fTab === 'run' && $users) ? ar_users_open_load($pdo, array_column($users, 'id')) : [];

$prioBadge = ['today' => 'red', 'high' => 'orange', 'regular' => 'secondary'];
$statBadge = ['allocated' => 'blue', 'in_progress' => 'azure', 'worked' => 'green'];

/* the four tabs */
$TABS = ['run' => ['Run allocation', 'filter'], 'current' => ['Current allocation', 'users'],
         'pullback' => ['Pull back untouched', 'arrow-back-up'], 'reallocate' => ['Reallocate by follow-up', 'refresh']];

$pageTitle = 'AR allocation';
require __DIR__ . '/../includes/header.php';
?>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tom-select@2.3.1/dist/css/tom-select.bootstrap5.min.css">
<script src="https://cdn.jsdelivr.net/npm/tom-select@2.3.1/dist/js/tom-select.complete.min.js"></script>
<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-arrows-shuffle me-2 text-primary"></i>AR allocation</h2>
        <div class="text-secondary small">Allocate <strong>collection inventory</strong> to your AR team. The unit of work is the <strong>Visit ID</strong>; a whole <strong>Patient Account #</strong> stays with one user. Runs on <strong>insurance-balance &gt; 0</strong> claims in tier order; a worked visit returns only after its follow-up date.</div>
    </div>
    <div class="col-auto">
        <a href="<?= e(url('/admin/ar-codes.php')) ?>" class="btn btn-outline-secondary"><i class="ti ti-list-check me-1"></i>Claim-status &amp; action lists</a>
    </div>
</div></div></div>

<div class="page-body"><div class="container-xl">

    <!-- ============================================================= SHARED FILTER BAR -->
    <div class="card mb-3">
        <div class="card-header py-2"><h3 class="card-title small"><i class="ti ti-filter me-2"></i>Filters <span class="text-secondary ms-1">— vertical » process » carrier(s) » DOS</span></h3></div>
        <div class="card-body py-2">
            <form method="GET" class="row g-2 align-items-end" id="ar_filter_form">
                <input type="hidden" name="tab" value="<?= e($fTab) ?>">
                <div class="col-md-3"><label class="form-label">Vertical</label>
                    <select name="vertical_id" class="form-select" onchange="this.form.submit()">
                        <option value="">— Select vertical —</option>
                        <?php foreach ($verticals as $v): ?><option value="<?= (int)$v['id'] ?>" <?= $fVertical===(int)$v['id']?'selected':'' ?>><?= e($v['name']) ?></option><?php endforeach; ?>
                    </select></div>
                <div class="col-md-3"><label class="form-label">Process</label>
                    <select name="process_id" class="form-select" onchange="this.form.submit()" <?= $processes?'':'disabled' ?>>
                        <option value="">— Select process —</option>
                        <?php foreach ($processes as $p): ?><option value="<?= (int)$p['id'] ?>" <?= $fProcess===(int)$p['id']?'selected':'' ?>><?= e($p['client_name'].' · '.$p['name']) ?></option><?php endforeach; ?>
                    </select></div>
                <div class="col-md-3"><label class="form-label">Carrier(s) <span class="text-secondary small">— pick one or more</span></label>
                    <select name="carrier[]" id="ar_carrier" class="form-select" multiple <?= $fProcess?'':'disabled' ?>>
                        <?php foreach ($carriers as $c): ?><option value="<?= e($c) ?>" <?= in_array((string)$c,$fCarriers,true)?'selected':'' ?>><?= e($c) ?></option><?php endforeach; ?>
                    </select></div>
                <div class="col-md-1"><label class="form-label">DOS yr</label>
                    <select name="dos_year" class="form-select">
                        <option value="">All</option>
                        <?php for ($y = (int)date('Y') + 1; $y >= 2020; $y--): ?><option value="<?= $y ?>" <?= $fDosYear===$y?'selected':'' ?>><?= $y ?></option><?php endfor; ?>
                    </select></div>
                <div class="col-md-2"><label class="form-label">DOS mo(s) <span class="text-secondary small">— one or more</span></label>
                    <select name="dos_month[]" id="ar_dosmo" class="form-select" multiple>
                        <?php for ($m = 1; $m <= 12; $m++): ?><option value="<?= $m ?>" <?= in_array($m,$fDosMonths,true)?'selected':'' ?>><?= date('M', mktime(0,0,0,$m,1)) ?></option><?php endfor; ?>
                    </select></div>
                <div class="col-md-2"><label class="form-label">Allocation sequence</label>
                    <select name="seq" class="form-select" onchange="this.form.submit()" title="Primary = primary insurance unpaid, balance open. Secondary = primary paid, balance remains. Changing this refreshes the carrier list to that sequence's carriers.">
                        <option value="">All sequences</option>
                        <option value="primary"   <?= $fSeq==='primary'?'selected':'' ?>>Primary (unpaid)</option>
                        <option value="secondary" <?= $fSeq==='secondary'?'selected':'' ?>>Secondary (rest)</option>
                    </select></div>
                <div class="col-md-3"><label class="form-label">Status</label>
                    <select name="inv_status" class="form-select" title="Filters the export/view by lifecycle status. 'Worked – eligible' = follow-up date arrived (back in the pool); 'not eligible' = follow-up still future (force only).">
                        <option value="">All statuses</option>
                        <option value="unallocated"    <?= $fInvStat==='unallocated'?'selected':'' ?>>Unallocated</option>
                        <option value="allocated"      <?= $fInvStat==='allocated'?'selected':'' ?>>Allocated – yet to work</option>
                        <option value="worked_due"     <?= $fInvStat==='worked_due'?'selected':'' ?>>Worked – eligible to reallocate (follow-up due)</option>
                        <option value="worked_waiting" <?= $fInvStat==='worked_waiting'?'selected':'' ?>>Worked – not eligible (force only)</option>
                    </select></div>
                <div class="col-md-1"><button class="btn btn-primary w-100"><i class="ti ti-check me-1"></i>Apply</button></div>
            </form>
        </div>
    </div>

    <!-- ============================================================= TABS (always visible) -->
    <ul class="nav nav-tabs mb-3">
        <?php foreach ($TABS as $key => [$lbl, $ic]): ?>
            <li class="nav-item"><a class="nav-link <?= $fTab===$key?'active':'' ?>" href="<?= e(url($selfUrl(['tab'=>$key]))) ?>"><i class="ti ti-<?= e($ic) ?> me-1"></i><?= e($lbl) ?></a></li>
        <?php endforeach; ?>
    </ul>

    <?php if ($fTab === 'pullback'): ?>
        <!-- =================== TAB 3: PULL BACK UNTOUCHED — process-INDEPENDENT overview =================== -->
        <?php $byP = $untouched['by_process']; $byU = $untouched['by_user']; $tAcc = (int)$untouched['total_accounts']; $tVis = (int)$untouched['total_visits']; ?>
        <div class="row row-cards mb-3">
            <?php foreach ([['Untouched accounts', number_format($tAcc), 'orange'], ['Untouched visits', number_format($tVis), 'default'],
                            ['Processes', number_format(count($byP)), 'default'], ['Users holding', number_format(count($byU)), 'default']] as $k): ?>
                <div class="col-6 col-md-3"><div class="card card-sm"><div class="card-body"><div class="text-secondary small text-uppercase"><?= e($k[0]) ?></div><div class="h1 m-0 text-<?= e($k[2]) ?>"><?= $k[1] ?></div></div></div></div>
            <?php endforeach; ?>
        </div>
        <div class="card mb-3"><div class="card-body d-flex flex-wrap align-items-center gap-2">
            <div><h3 class="card-title mb-0"><i class="ti ti-arrow-back-up me-2"></i>Pull back untouched</h3>
                <div class="text-secondary small">Resets <strong>allocated-but-never-worked</strong> accounts back to origin so they can be reshuffled. A partially/fully <strong>worked</strong> account is never touched. Shown across <strong>all processes</strong> (no process selection needed).</div></div>
            <form method="POST" action="<?= e(url($selfUrl(['tab'=>'pullback']))) ?>" class="ms-auto" onsubmit="return confirm('Pull back ALL <?= $tAcc ?> untouched account(s) across every process?');">
                <?= csrf_field() ?><input type="hidden" name="action" value="pullback">
                <button class="btn btn-warning" <?= $tAcc?'':'disabled' ?>><i class="ti ti-arrow-back-up me-1"></i>Pull back ALL untouched (<?= number_format($tAcc) ?>)</button>
            </form>
        </div></div>
        <div class="row">
            <div class="col-lg-6"><div class="card mb-3"><div class="card-header py-2"><h3 class="card-title small"><i class="ti ti-route me-1"></i>By process</h3></div>
                <div class="table-responsive" style="max-height:460px"><table class="table table-vcenter card-table table-sm">
                    <thead><tr><th>Process</th><th class="text-end">Accounts</th><th class="text-end">Visits</th><th class="w-1"></th></tr></thead>
                    <tbody>
                    <?php if (!$byP): ?><tr><td colspan="4" class="text-center text-secondary py-3">No untouched inventory. 🎉</td></tr>
                    <?php else: foreach ($byP as $r): ?>
                        <tr><td class="small"><?= e($r['cname'].' · '.$r['pname']) ?></td>
                            <td class="text-end fw-medium"><?= number_format((int)$r['accounts']) ?></td>
                            <td class="text-end"><?= number_format((int)$r['visits']) ?></td>
                            <td><form method="POST" action="<?= e(url($selfUrl(['tab'=>'pullback']))) ?>" onsubmit="return confirm('Pull back <?= (int)$r['accounts'] ?> untouched account(s) in <?= e(addslashes($r['pname'])) ?>?');">
                                <?= csrf_field() ?><input type="hidden" name="action" value="pullback"><input type="hidden" name="process_id" value="<?= (int)$r['process_id'] ?>">
                                <button class="btn btn-sm btn-outline-warning" title="Pull back this process"><i class="ti ti-arrow-back-up"></i></button></form></td></tr>
                    <?php endforeach; endif; ?>
                    </tbody>
                </table></div></div></div>
            <div class="col-lg-6"><div class="card mb-3"><div class="card-header py-2"><h3 class="card-title small"><i class="ti ti-user me-1"></i>By user</h3></div>
                <div class="table-responsive" style="max-height:460px"><table class="table table-vcenter card-table table-sm">
                    <thead><tr><th>User</th><th class="text-end">Accounts</th><th class="text-end">Visits</th><th class="w-1"></th></tr></thead>
                    <tbody>
                    <?php if (!$byU): ?><tr><td colspan="4" class="text-center text-secondary py-3">No untouched inventory.</td></tr>
                    <?php else: foreach ($byU as $r): ?>
                        <tr><td class="small"><?= e($r['uname'] ?? '—') ?></td>
                            <td class="text-end fw-medium"><?= number_format((int)$r['accounts']) ?></td>
                            <td class="text-end"><?= number_format((int)$r['visits']) ?></td>
                            <td><form method="POST" action="<?= e(url($selfUrl(['tab'=>'pullback']))) ?>" onsubmit="return confirm('Pull back <?= (int)$r['accounts'] ?> untouched account(s) held by <?= e(addslashes((string)$r['uname'])) ?>?');">
                                <?= csrf_field() ?><input type="hidden" name="action" value="pullback"><input type="hidden" name="only_user" value="<?= (int)$r['uid'] ?>">
                                <button class="btn btn-sm btn-outline-warning" title="Pull back this user's untouched"><i class="ti ti-arrow-back-up"></i></button></form></td></tr>
                    <?php endforeach; endif; ?>
                    </tbody>
                </table></div></div></div>
        </div>

    <?php elseif (!$fProcess && $fTab !== 'reallocate'): /* reallocate shows a cross-process follow-up summary even with no process picked */ ?>
        <div class="card"><div class="card-body text-center text-secondary py-5"><i class="ti ti-arrow-up" style="font-size:2rem"></i>
            <div class="mt-2">Select a <strong>vertical</strong> then a <strong>process</strong> above for this tab.</div></div></div>

    <?php elseif ($fTab === 'run'): ?>
        <!-- =================== TAB 1: RUN ALLOCATION =================== -->
        <div class="alert <?= $preview['visits']?'alert-info':'alert-warning' ?> d-flex align-items-center py-2 mb-3">
            <i class="ti ti-eye me-2"></i>
            <div><strong><?= number_format($preview['visits']) ?></strong> allocable visit(s) across <strong><?= number_format($preview['accounts']) ?></strong> patient account(s) match these filters
                <span class="text-secondary">— Tier&nbsp;1: <strong><?= number_format($preview[1]) ?></strong>, Tier&nbsp;2: <strong><?= number_format($preview[2]) ?></strong>, Tier&nbsp;3: <strong><?= number_format($preview[3]) ?></strong>.</span></div>
            <?php if ($fProcess): ?><a href="<?= e(url($selfUrl(['export'=>'xlsx']))) ?>" class="btn btn-sm btn-outline-success ms-auto"><i class="ti ti-file-spreadsheet me-1"></i>Export Excel</a><?php endif; ?>
        </div>
        <?php if ($fProcess): ?>
        <div class="d-flex flex-wrap align-items-center gap-2 mb-3">
            <span class="text-secondary small">Inventory status (matching filters):</span>
            <span class="badge bg-secondary-lt" title="Never assigned">Unallocated: <?= number_format($statusCounts['unallocated']) ?></span>
            <span class="badge bg-blue-lt" title="Assigned to a user, not yet worked">Allocated – yet to work: <?= number_format($statusCounts['allocated']) ?></span>
            <span class="badge bg-green-lt" title="Worked; follow-up date arrived — back in the allocable pool">Worked – eligible to reallocate: <?= number_format($statusCounts['worked_due']) ?></span>
            <span class="badge bg-orange-lt" title="Worked; follow-up date still in the future — only a forced reallocation applies">Worked – not eligible (force only): <?= number_format($statusCounts['worked_waiting']) ?></span>
            <?php if ($fInvStat): ?><span class="text-secondary small">· Export limited to <strong><?= e($AR_STATUS_LABELS[$fInvStat] ?? $fInvStat) ?></strong></span><?php endif; ?>
        </div>
        <?php endif; ?>
        <div class="card mb-3"><div class="card-body">
            <form method="POST" action="<?= e(url($selfUrl(['tab'=>'run']))) ?>">
                <?= csrf_field() ?>
                <input type="hidden" name="action" value="run_allocation">
                <input type="hidden" name="process_id" value="<?= $fProcess ?>">
                <?php foreach ($fCarriers as $c): ?><input type="hidden" name="carrier[]" value="<?= e($c) ?>"><?php endforeach; ?>
                <input type="hidden" name="dos_year" value="<?= $fDosYear ?: '' ?>">
                <?php foreach ($fDosMonths as $m): ?><input type="hidden" name="dos_month[]" value="<?= (int)$m ?>"><?php endforeach; ?>
                <input type="hidden" name="seq" value="<?= e($fSeq) ?>">
                <?php if ($fSeq !== ''): ?><div class="mb-2"><span class="badge bg-azure-lt"><i class="ti ti-filter me-1"></i>Allocation sequence: <?= $fSeq==='primary'?'Primary (unpaid)':'Secondary (rest)' ?></span> <span class="text-secondary small">only these claims will be allocated</span></div><?php endif; ?>
                <div class="mb-2 text-secondary small"><i class="ti ti-info-circle me-1"></i>Priority is automatic: <span class="badge bg-red-lt">Tier&nbsp;1 → Today's</span> <span class="badge bg-orange-lt">Tier&nbsp;2 → High</span> <span class="badge bg-secondary-lt">Tier&nbsp;3 → Regular</span> · each oldest DOS first, then balance high→low.</div>
                <div class="d-flex flex-wrap align-items-end gap-3 mb-2">
                    <div><label class="form-label mb-1 small">Search</label>
                        <input id="ar_user_search" type="search" class="form-control form-control-sm" placeholder="name / email…" oninput="arFilterUsers()"></div>
                    <div><label class="form-label mb-1 small d-block">&nbsp;</label>
                        <button type="button" class="btn btn-sm btn-outline-secondary" onclick="arUserSel(true)">Select all</button>
                        <button type="button" class="btn btn-sm btn-outline-secondary" onclick="arUserSel(false)">None</button></div>
                    <div><label class="form-label mb-1 small">When a worked claim's follow-up arrives</label>
                        <select name="rework" class="form-select form-select-sm">
                            <option value="keep">Keep rework with current owner</option>
                            <option value="repool">Return rework to the pool</option>
                        </select></div>
                </div>
                <label class="form-label">Allocate to <span class="text-secondary small">— users who report under you · whole accounts balanced by visit-id count · <span id="ar_sel_count">0</span> selected. Columns show each user's <strong>existing</strong> book (all processes): accounts &amp; visits already allocated, split <strong>Primary</strong> (tier&nbsp;1) / <strong>Secondary</strong> (tier&nbsp;2–3), how many are already worked, and the <strong>Pending</strong> backlog — sort to find who has room.</span></label>
                <?php if (!$users): ?>
                    <div class="text-secondary">No users report under you with <code>ar.work</code>. Map your team via Reports-to / <a href="<?= e(url('/admin/user-alignment.php')) ?>">user alignment</a>.</div>
                <?php else: ?>
                    <div class="table-responsive" style="max-height:460px">
                    <table class="table table-vcenter table-sm card-table" id="ar_user_table">
                        <thead>
                            <tr>
                                <th class="w-1"><input type="checkbox" class="form-check-input m-0" onclick="arUserSel(this.checked)" title="Select all visible"></th>
                                <th role="button" onclick="arSortUsers(this,1,'s')">User <i class="ti ti-arrows-sort text-secondary"></i></th>
                                <th class="text-end" role="button" onclick="arSortUsers(this,2,'n')" title="Distinct patient accounts already allocated">Accounts</th>
                                <th class="text-end" role="button" onclick="arSortUsers(this,3,'n')" title="Allocated visits · Primary = tier 1 (primary carrier unpaid)">Alloc.<br>Primary</th>
                                <th class="text-end" role="button" onclick="arSortUsers(this,4,'n')" title="Allocated visits · Secondary = tier 2–3">Alloc.<br>Secondary</th>
                                <th class="text-end" role="button" onclick="arSortUsers(this,5,'n')" title="Worked visits · Primary">Worked<br>Primary</th>
                                <th class="text-end" role="button" onclick="arSortUsers(this,6,'n')" title="Worked visits · Secondary">Worked<br>Secondary</th>
                                <th class="text-end" role="button" onclick="arSortUsers(this,7,'n')" title="Visits allocated but not yet worked — the remaining backlog (default sort: highest first)">Pending<br>total <i class="ti ti-arrow-down text-secondary" style="font-size:.7rem"></i></th>
                            </tr>
                        </thead>
                        <tbody id="ar_user_tbody">
                        <?php /* default view = highest pending backlog first (server-side, so it's right on load) */
                        $usersRun = $users;
                        usort($usersRun, fn($a, $b) => ((int)($userLoad[(int)$b['id']]['pending'] ?? 0)) <=> ((int)($userLoad[(int)$a['id']]['pending'] ?? 0)));
                        foreach ($usersRun as $u): $ld = $userLoad[(int)$u['id']] ?? ['accounts'=>0,'alloc_pri'=>0,'alloc_sec'=>0,'worked_pri'=>0,'worked_sec'=>0,'pending'=>0]; ?>
                            <tr class="ar-user" data-name="<?= e(strtolower(($u['name'] ?? '').' '.($u['email'] ?? ''))) ?>">
                                <td><input class="form-check-input m-0 ar-user-cb" type="checkbox" name="user_ids[]" value="<?= (int)$u['id'] ?>" onchange="arSelCount()"></td>
                                <td><?= e($u['name']) ?></td>
                                <td class="text-end fw-medium" data-v="<?= (int)$ld['accounts'] ?>"><?= number_format((int)$ld['accounts']) ?></td>
                                <td class="text-end" data-v="<?= (int)$ld['alloc_pri'] ?>"><?= number_format((int)$ld['alloc_pri']) ?></td>
                                <td class="text-end" data-v="<?= (int)$ld['alloc_sec'] ?>"><?= number_format((int)$ld['alloc_sec']) ?></td>
                                <td class="text-end text-secondary" data-v="<?= (int)$ld['worked_pri'] ?>"><?= number_format((int)$ld['worked_pri']) ?></td>
                                <td class="text-end text-secondary" data-v="<?= (int)$ld['worked_sec'] ?>"><?= number_format((int)$ld['worked_sec']) ?></td>
                                <td class="text-end fw-medium" data-v="<?= (int)$ld['pending'] ?>"><?php $pn=(int)$ld['pending']; ?><?= $pn ? '<span class="badge bg-blue-lt">'.number_format($pn).'</span>' : '<span class="text-secondary">0</span>' ?></td>
                            </tr>
                        <?php endforeach; ?>
                        </tbody>
                    </table>
                    </div>
                <?php endif; ?>
                <div class="mt-3">
                    <button class="btn btn-primary" <?= ($users && $preview['visits'])?'':'disabled' ?>><i class="ti ti-player-play me-1"></i>Run allocation</button>
                    <span class="text-secondary small ms-2">Assigns allocable visits — keeping each account with one user — to equalise visit counts across the checked users.</span>
                </div>
            </form>
        </div></div>
        <script>
        function arFilterUsers(){
            var q=(document.getElementById('ar_user_search').value||'').toLowerCase().trim();
            document.querySelectorAll('#ar_user_tbody .ar-user').forEach(function(el){
                var show=(!q||(el.dataset.name||'').indexOf(q)!==-1);
                el.style.display=show?'':'none';
                if(!show){ var cb=el.querySelector('.ar-user-cb'); if(cb&&cb.checked){ cb.checked=false; } }
            });
            arSelCount();
        }
        function arUserSel(on){ document.querySelectorAll('#ar_user_tbody .ar-user').forEach(function(el){ if(el.style.display!=='none'){ var cb=el.querySelector('.ar-user-cb'); if(cb) cb.checked=on; } }); arSelCount(); }
        function arSelCount(){ var n=document.querySelectorAll('#ar_user_tbody .ar-user-cb:checked').length; var t=document.getElementById('ar_sel_count'); if(t) t.textContent=n; }
        function arSortUsers(th,col,type){
            var tb=document.getElementById('ar_user_tbody'); if(!tb) return;
            var rows=Array.prototype.slice.call(tb.querySelectorAll('tr.ar-user'));
            var dir=th.dataset.dir==='asc'?'desc':'asc'; th.dataset.dir=dir;
            rows.sort(function(a,b){ var x,y;
                if(type==='n'){ x=parseFloat(a.children[col].dataset.v||0); y=parseFloat(b.children[col].dataset.v||0); }
                else { x=(a.children[col].textContent||'').trim().toLowerCase(); y=(b.children[col].textContent||'').trim().toLowerCase(); }
                if(x<y) return dir==='asc'?-1:1; if(x>y) return dir==='asc'?1:-1; return 0; });
            rows.forEach(function(r){ tb.appendChild(r); });
        }
        </script>

    <?php elseif ($fTab === 'current'): ?>
        <!-- =================== TAB 2: CURRENT ALLOCATION — user-wise summary, expand to detail =================== -->
        <div class="card mb-3">
            <div class="card-header">
                <h3 class="card-title"><i class="ti ti-users me-2"></i>Current allocation <span class="text-secondary small fw-normal ms-1">— by user</span></h3>
                <div class="card-actions d-flex align-items-center gap-2">
                    <span class="text-secondary small"><?= number_format($allocAccounts) ?> account(s) · <?= number_format(count($allocRows)) ?> visit(s) shown</span>
                    <a href="<?= e(url($selfUrl(['tab'=>'current','export'=>'current']))) ?>" class="btn btn-sm btn-outline-success"><i class="ti ti-file-spreadsheet me-1"></i>Export Excel (detail)</a>
                </div>
            </div>
            <form method="POST" action="<?= e(url($selfUrl(['tab'=>'current']))) ?>">
                <?= csrf_field() ?><input type="hidden" name="action" value="reassign">
                <div class="card-body border-bottom py-2 d-flex flex-wrap align-items-center gap-2">
                    <span class="text-secondary small">Reassign selected to:</span>
                    <select name="to_user" class="form-select form-select-sm w-auto">
                        <option value="">→ back to origin (unallocate)</option>
                        <?php foreach ($users as $u): ?><option value="<?= (int)$u['id'] ?>"><?= e($u['name']) ?></option><?php endforeach; ?>
                    </select>
                    <button class="btn btn-sm btn-primary"><i class="ti ti-arrows-exchange me-1"></i>Reassign selected</button>
                    <span class="text-secondary" style="font-size:.72rem"><i class="ti ti-info-circle me-1"></i>Expand a user, tick visits (any visit reassigns its <strong>whole patient account</strong>).</span>
                </div>
                <div class="table-responsive"><table class="table table-vcenter card-table table-sm">
                    <thead><tr>
                        <th class="w-1"></th><th>User</th>
                        <th class="text-end">Accounts</th><th class="text-end">Visits</th>
                        <th class="text-end">Worked</th><th class="text-end">Pending</th><th class="text-end">Insurance balance</th>
                    </tr></thead>
                    <tbody>
                    <?php if (!$allocSummary): ?>
                        <tr><td colspan="7" class="text-center text-secondary py-4">Nothing allocated for this process yet.</td></tr>
                    <?php else: foreach ($allocSummary as $s): $uid2 = (int) $s['uid']; $det = $allocByUser[$uid2] ?? []; $vis = (int) $s['visits']; $wk = (int) $s['worked']; ?>
                        <tr class="ar-sumrow" role="button" onclick="arToggleUser(<?= $uid2 ?>)">
                            <td><i id="ar-chev-<?= $uid2 ?>" class="ti ti-chevron-right text-secondary"></i></td>
                            <td class="fw-medium"><?= e($s['uname'] ?? ('(deleted user #'.$uid2.')')) ?></td>
                            <td class="text-end"><?= number_format((int) $s['accounts']) ?></td>
                            <td class="text-end"><?= number_format($vis) ?></td>
                            <td class="text-end"><span class="badge bg-green-lt"><?= number_format($wk) ?></span></td>
                            <td class="text-end"><span class="badge bg-blue-lt"><?= number_format($vis - $wk) ?></span></td>
                            <td class="text-end"><?= number_format((float) $s['ins_bal'], 2) ?></td>
                        </tr>
                        <tr id="ar-det-<?= $uid2 ?>" class="ar-detrow" style="display:none"><td colspan="7" class="p-0">
                            <div class="p-2" style="background:var(--tblr-bg-surface-secondary,#f8fafc)">
                            <?php if (!$det): ?>
                                <div class="text-secondary small py-2 px-1"><i class="ti ti-info-circle me-1"></i>This user's visits are beyond the on-screen detail cap — use <strong>Export Excel</strong> for the full detail.</div>
                            <?php else: ?>
                                <div class="mb-1"><label class="form-check form-check-inline small mb-0"><input type="checkbox" class="form-check-input" onclick="arSelUser(<?= $uid2 ?>,this.checked)"> <span class="ms-1">select all this user's visits</span></label></div>
                                <table class="table table-sm table-vcenter mb-0">
                                    <thead><tr><th class="w-1"></th><th>Account #</th><th>Visit ID</th><th>Carrier</th><th>DOS</th><th>Type</th><th>Priority</th><th>Status</th><th class="text-end">Ins. bal</th><th>Last worked</th><th>Claim status</th><th>Next follow-up</th></tr></thead>
                                    <tbody>
                                    <?php foreach ($det as $r): ?>
                                        <tr>
                                            <td><input type="checkbox" class="form-check-input m-0 ar-row-cb ar-row-<?= $uid2 ?>" name="ids[]" value="<?= (int)$r['alloc_id'] ?>"></td>
                                            <td class="font-mono"><?= e($r['chart_number']) ?></td>
                                            <td class="font-mono small"><?= e($r['visit_id']) ?></td>
                                            <td class="small"><?= e($r['carrier_name'] ?? '—') ?></td>
                                            <td class="small"><?= e(fmt_date($r['dos'])) ?></td>
                                            <td class="small"><?= e(AR_ALLOC_TYPES[$r['allocation_type']] ?? ($r['allocation_type'] ?? '—')) ?></td>
                                            <td><?php $pk = (string)($r['priority'] ?? ''); ?><span class="badge bg-<?= $prioBadge[$pk] ?? 'secondary' ?>-lt"><?= e(AR_PRIORITIES[$pk] ?? '—') ?></span></td>
                                            <td><?php $sk = (string)($r['inventory_status'] ?? ''); ?><span class="badge bg-<?= $statBadge[$sk] ?? 'secondary' ?>-lt"><?= e($sk !== '' ? str_replace('_',' ',$sk) : '—') ?></span></td>
                                            <td class="small text-end"><?= number_format((float)($r['insurance_balance'] ?? 0), 2) ?></td>
                                            <td class="small"><?= e(fmt_date($r['last_worked_date'])) ?></td>
                                            <td class="small text-secondary"><?= e($r['claim_status'] ?? '—') ?></td>
                                            <td class="small"><?= e(fmt_date($r['next_follow_up_date'])) ?></td>
                                        </tr>
                                    <?php endforeach; ?>
                                    </tbody>
                                </table>
                            <?php endif; ?>
                            </div>
                        </td></tr>
                    <?php endforeach; endif; ?>
                    </tbody>
                </table></div>
                <?php if (count($allocRows) >= 5000): ?><div class="card-footer text-secondary small">On-screen detail limited to 5000 visit(s); the by-user summary is complete. Use <strong>Export Excel (detail)</strong> for the full per-visit list.</div><?php endif; ?>
            </form>
        </div>
        <script>
        function arToggleUser(uid){ var d=document.getElementById('ar-det-'+uid), c=document.getElementById('ar-chev-'+uid); if(!d) return; var open=d.style.display==='none'; d.style.display=open?'':'none'; if(c) c.className='ti ti-chevron-'+(open?'down':'right')+' text-secondary'; }
        function arSelUser(uid,on){ document.querySelectorAll('.ar-row-'+uid).forEach(function(cb){ cb.checked=on; }); }
        </script>

    <?php elseif ($fTab === 'reallocate'): ?>
        <!-- =================== TAB 4: REALLOCATE BY FOLLOW-UP =================== -->

        <!-- ---------- FOLLOW-UP-DUE SUMMARY (before allocating) — client » process » carrier by visit count ---------- -->
        <div class="card mb-3">
            <div class="card-header"><h3 class="card-title"><i class="ti ti-list-numbers me-2"></i>Follow-up-due claims <span class="text-secondary small fw-normal ms-1">— ready to reallocate</span></h3>
                <div class="card-actions text-secondary small">
                    <?= number_format((int)$dueSummary['accounts']) ?> account(s) · <strong><?= number_format((int)$dueSummary['visits']) ?></strong> visit(s)<?= $fProcess ? '' : ' · across your whole team' ?>
                </div>
            </div>
            <div class="card-body py-2">
                <p class="text-secondary small mb-2">Worked claims whose <strong>follow-up date has arrived</strong> (or was left blank) and are still owned — the inventory the reallocation below draws from. Counts are by <strong>number of visits</strong>, grouped by client / process / carrier<?= $fProcess ? ' (this process)' : ', team-wide (pick a process above to narrow)' ?>.</p>
                <div class="table-responsive" style="max-height:360px"><table class="table table-vcenter card-table table-sm">
                    <thead><tr><th>Client</th><th>Process</th><th>Carrier</th><th class="text-end">Accounts</th><th class="text-end">Visits</th><th class="text-end">Insurance balance</th></tr></thead>
                    <tbody>
                    <?php if (!$dueSummary['rows']): ?>
                        <tr><td colspan="6" class="text-center text-secondary py-3">No follow-up-due claims<?= $fProcess ? ' for this process' : '' ?> right now.</td></tr>
                    <?php else: foreach ($dueSummary['rows'] as $r): ?>
                        <tr>
                            <td class="small"><?= e($r['cname']) ?></td>
                            <td class="small"><?= e($r['pname']) ?></td>
                            <td class="small"><?= e($r['carrier']) ?></td>
                            <td class="text-end"><?= number_format((int)$r['accounts']) ?></td>
                            <td class="text-end fw-medium"><?= number_format((int)$r['visits']) ?></td>
                            <td class="text-end"><?= number_format((float)$r['ins_bal'], 2) ?></td>
                        </tr>
                    <?php endforeach; endif; ?>
                    </tbody>
                    <?php if ($dueSummary['rows']): ?>
                    <tfoot><tr class="fw-bold"><td colspan="3" class="text-end">Total</td>
                        <td class="text-end"><?= number_format((int)$dueSummary['accounts']) ?></td>
                        <td class="text-end"><?= number_format((int)$dueSummary['visits']) ?></td>
                        <td class="text-end"><?= number_format((float)$dueSummary['ins_bal'], 2) ?></td></tr></tfoot>
                    <?php endif; ?>
                </table></div>
            </div>
        </div>

        <?php if (!$fProcess): ?>
            <div class="card"><div class="card-body text-center text-secondary py-4"><i class="ti ti-arrow-up" style="font-size:1.6rem"></i>
                <div class="mt-2">Select a <strong>process</strong> above to redistribute its inventory or pull back its follow-up-hold accounts. The summary above spans your whole team.</div></div></div>
        <?php else: ?>
        <div class="card mb-3">
            <div class="card-header"><h3 class="card-title"><i class="ti ti-refresh me-2"></i>Reallocate by follow-up</h3></div>
            <div class="card-body">
                <p class="text-secondary small">When nothing new is left to allocate, re-distributes the process's already-allocated inventory across the chosen team users by <strong>next follow-up date</strong> then <strong>last worked date</strong> (oldest first).</p>
                <form method="POST" action="<?= e(url($selfUrl(['tab'=>'reallocate']))) ?>">
                    <?= csrf_field() ?><input type="hidden" name="action" value="reallocate"><input type="hidden" name="process_id" value="<?= $fProcess ?>">
                    <label class="form-label">Redistribute across <span class="text-secondary small">— your team</span></label>
                    <?php if (!$users): ?>
                        <div class="text-secondary small mb-2">No allocatable users on your team.</div>
                    <?php else: ?>
                        <div class="mb-2"><button type="button" class="btn btn-sm btn-outline-secondary" onclick="arRealSel(true)">Select all</button>
                            <button type="button" class="btn btn-sm btn-outline-secondary" onclick="arRealSel(false)">None</button></div>
                        <div class="row g-1 mb-2" id="ar_real_list" style="max-height:220px;overflow:auto">
                            <?php foreach ($users as $u): ?>
                                <div class="col-md-4 col-sm-6"><label class="form-check">
                                    <input class="form-check-input ar-real-cb" type="checkbox" name="user_ids[]" value="<?= (int)$u['id'] ?>">
                                    <span class="form-check-label small"><?= e($u['name']) ?></span></label></div>
                            <?php endforeach; ?>
                        </div>
                        <script>function arRealSel(on){ document.querySelectorAll('#ar_real_list .ar-real-cb').forEach(function(c){ c.checked=on; }); }</script>
                    <?php endif; ?>
                    <button class="btn btn-outline-primary" <?= $users?'':'disabled' ?> onclick="return confirm('Re-distribute this process\'s allocated inventory by follow-up date?');"><i class="ti ti-refresh me-1"></i>Reallocate by follow-up</button>
                </form>
            </div>
        </div>

        <!-- ---------- PULL BACK ACCOUNTS ON FOLLOW-UP HOLD ---------- -->
        <?php $hAcc = (int)$hold['total_accounts']; $hVis = (int)$hold['total_worked']; $hBal = (float)$hold['total_ins_bal']; $hExc = (int)$hold['excluded']; ?>
        <div class="row row-cards mb-3">
            <?php foreach ([['Accounts on follow-up hold', number_format($hAcc), 'orange'], ['Worked visits held', number_format($hVis), 'default'],
                            ['Insurance balance', number_format($hBal, 2), 'default'], ['Users holding', number_format(count($hold['by_user'])), 'default']] as $k): ?>
                <div class="col-6 col-md-3"><div class="card card-sm"><div class="card-body"><div class="text-secondary small text-uppercase"><?= e($k[0]) ?></div><div class="h1 m-0 text-<?= e($k[2]) ?>"><?= $k[1] ?></div></div></div></div>
            <?php endforeach; ?>
        </div>
        <div class="card mb-3">
            <div class="card-header"><h3 class="card-title"><i class="ti ti-clock-pause me-2"></i>Pull back accounts on follow-up hold</h3>
                <div class="card-actions">
                    <a href="<?= e(url($selfUrl(['tab'=>'reallocate','export'=>'followup']))) ?>" class="btn btn-sm btn-outline-success"><i class="ti ti-file-spreadsheet me-1"></i>Export Excel</a>
                </div>
            </div>
            <div class="card-body">
                <p class="text-secondary small mb-2">A visit that was <strong>worked and given a follow-up date</strong> is finished for its owner — it can't be re-worked and nothing reopens it on its own, so the account just sits in that user's queue until it is re-allocated. Pulling it back <strong>releases it to the allocable pool now</strong>. The <strong>work history and audits are kept</strong> (this is not the destructive &ldquo;pull back untouched&rdquo;); only the follow-up hold and the ownership are cleared.</p>
                <form method="GET" class="d-flex flex-wrap align-items-end gap-2 mb-3">
                    <?php /* carry the whole shared filter-bar state, or changing scope would silently reset it */
                    foreach ($ctx as $k => $v): if ($k === 'hold' || $k === 'tab') continue;
                        foreach ((array) $v as $vv): ?><input type="hidden" name="<?= e($k) ?><?= is_array($v)?'[]':'' ?>" value="<?= e((string)$vv) ?>"><?php endforeach;
                    endforeach; ?>
                    <input type="hidden" name="tab" value="reallocate">
                    <div><label class="form-label mb-1 small">Which accounts</label>
                        <select name="hold" class="form-select form-select-sm" onchange="this.form.submit()">
                            <option value="waiting" <?= $fHold==='waiting'?'selected':'' ?>>Follow-up still in the future (unreachable)</option>
                            <option value="all"     <?= $fHold==='all'?'selected':'' ?>>All follow-up accounts (incl. already due)</option>
                        </select></div>
                    <?php if ($fHold === 'all'): ?><div class="text-secondary small pb-2"><i class="ti ti-info-circle me-1"></i>Already-due accounts return to the pool on their own via <strong>Run allocation</strong> with &ldquo;Return rework to the pool&rdquo;.</div><?php endif; ?>
                </form>
                <?php if ($hExc): ?>
                    <div class="alert alert-warning py-2 small mb-3"><i class="ti ti-shield-lock me-1"></i><strong><?= number_format($hExc) ?></strong> account(s) were held back and are <strong>not</strong> included above: they have a routing hand-off still awaiting &ldquo;Confirm sent&rdquo; on <a href="<?= e(url('/admin/ar-verify.php')) ?>">Verify &amp; route</a>, or an open audit rebuttal. Releasing those would strand the hand-off or destroy the rebuttal.</div>
                <?php endif; ?>
                <form method="POST" action="<?= e(url($selfUrl(['tab'=>'reallocate']))) ?>" class="mb-3"
                      onsubmit="return confirm('Pull back ALL <?= $hAcc ?> account(s) on follow-up hold in this process? Their work history is kept.');">
                    <?= csrf_field() ?><input type="hidden" name="action" value="pullback_followup">
                    <input type="hidden" name="process_id" value="<?= $fProcess ?>"><input type="hidden" name="hold" value="<?= e($fHold) ?>">
                    <button class="btn btn-warning" <?= $hAcc?'':'disabled' ?>><i class="ti ti-arrow-back-up me-1"></i>Pull back ALL on hold (<?= number_format($hAcc) ?>)</button>
                </form>
                <div class="table-responsive" style="max-height:420px"><table class="table table-vcenter card-table table-sm">
                    <thead><tr><th>User</th><th class="text-end">Accounts</th><th class="text-end">Worked visits</th><th class="text-end">Insurance balance</th><th class="w-1"></th></tr></thead>
                    <tbody>
                    <?php if (!$hold['by_user']): ?><tr><td colspan="5" class="text-center text-secondary py-3">No accounts are on follow-up hold for this process.</td></tr>
                    <?php else: foreach ($hold['by_user'] as $r): ?>
                        <tr><td class="small"><?= e($r['uname'] ?? '—') ?></td>
                            <td class="text-end fw-medium"><?= number_format((int)$r['accounts']) ?></td>
                            <td class="text-end"><?= number_format((int)$r['worked_visits']) ?></td>
                            <td class="text-end"><?= number_format((float)$r['ins_bal'], 2) ?></td>
                            <td><form method="POST" action="<?= e(url($selfUrl(['tab'=>'reallocate']))) ?>"
                                      onsubmit="return confirm('Pull back <?= (int)$r['accounts'] ?> account(s) held by <?= e(addslashes((string)$r['uname'])) ?>? Their work history is kept.');">
                                <?= csrf_field() ?><input type="hidden" name="action" value="pullback_followup">
                                <input type="hidden" name="process_id" value="<?= $fProcess ?>"><input type="hidden" name="hold" value="<?= e($fHold) ?>">
                                <input type="hidden" name="only_user" value="<?= (int)$r['uid'] ?>">
                                <button class="btn btn-sm btn-outline-warning" title="Pull back this user's follow-up hold"><i class="ti ti-arrow-back-up"></i></button></form></td></tr>
                    <?php endforeach; endif; ?>
                    </tbody>
                </table></div>
            </div>
        </div>
        <?php endif; /* $fProcess (reallocate + hold cards) */ ?>
    <?php endif; ?>

    <!-- ============================================================= FORCE ALLOCATION (own page) -->
    <div class="card mb-3"><div class="card-body d-flex flex-wrap align-items-center gap-3">
        <div><h3 class="card-title mb-1"><i class="ti ti-file-upload me-2"></i>Force allocation</h3>
            <div class="text-secondary small">Assign specific patient accounts to specific users — download the open inventory, fill <code>assign_user_email</code>, upload. For patient-balance &amp; one-off assignments that bypass the tier engine.</div></div>
        <a href="<?= e(url('/admin/ar-force.php' . ($fProcess ? ('?vertical_id=' . $fVertical . '&process_id=' . $fProcess) : ''))) ?>" class="btn btn-primary ms-auto"><i class="ti ti-arrow-right me-1"></i>Go to Force allocation</a>
    </div></div>

</div></div>
<script>
(function(){ if(typeof TomSelect==='undefined') return;
    var c=document.getElementById('ar_carrier');
    if(c&&!c.tomselect) new TomSelect(c,{plugins:['remove_button'],maxOptions:2000,placeholder:'All carriers'});
    var dm=document.getElementById('ar_dosmo');
    if(dm&&!dm.tomselect) new TomSelect(dm,{plugins:['remove_button'],placeholder:'All months'});
})();
</script>
<?php require __DIR__ . '/../includes/footer.php'; ?>
