<?php
/**
 * AR / Collections — FORCE ALLOCATION (ar.allocate). A dedicated workflow, separate from the tier-based
 * "Allocate inventory" page:
 *   1. Pick vertical (AR) → process.
 *   2. DOWNLOAD the open inventory (visit-grained, all headers) to review + an empty `assign_user_email`
 *      column — this same file is the upload template. (A blank headers-only template is also offered.)
 *   3. Fill `assign_user_email` for the accounts you want, UPLOAD → those whole Patient Accounts are
 *      force-assigned to the named users (insurance-balance OR patient-balance; bypasses the tier engine).
 *
 * Account-whole rule holds: rows are grouped by Patient Account #; one user per account (first non-blank
 * email wins, conflicts are counted). ar_force_allocate() snapshots balances + creates the visit-ledger rows.
 */
require_once __DIR__ . '/../includes/config.php';
$user = require_login('internal');
$pdo  = db();
$uid  = (int) $user['id'];

$CSV_HEADERS = ['process_id', 'patient_account', 'visit_id', 'carrier', 'dos', 'insurance_balance',
                'patient_balance', 'tier', 'current_user_email', 'current_status', 'allocation_type', 'priority', 'assign_user_email'];

$fVertical = (int) ($_GET['vertical_id'] ?? 0);
$fProcess  = (int) ($_GET['process_id'] ?? 0);
$fType     = in_array($_GET['alloc_type'] ?? '', ['insurance_bal', 'patient_bal', 'all'], true) ? (string) $_GET['alloc_type'] : 'insurance_bal';
$ctx = array_filter(['vertical_id' => $fVertical ?: null, 'process_id' => $fProcess ?: null, 'alloc_type' => $fType !== 'insurance_bal' ? $fType : null]);
$selfUrl = fn(array $over = []) => '/admin/ar-force.php' . (($q = array_merge($ctx, $over)) ? ('?' . http_build_query($q)) : '');

/* ============================================================ CSV DOWNLOADS (stream before any HTML) */
if (($dl = ($_GET['download'] ?? '')) !== '') {
    if (!can('ar.allocate')) { http_response_code(403); exit('Forbidden'); }
    $blank = $dl === 'template';
    if (!$blank && (!$fProcess || !ar_process_in_ar_vertical($pdo, $fProcess))) { http_response_code(403); exit('Forbidden — not an AR/Collections process.'); }
    header('Content-Type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename="ar-force-' . ($blank ? 'template' : ('inventory-p' . $fProcess)) . '.csv"');
    header('Cache-Control: no-cache, no-store, must-revalidate');
    $out = fopen('php://output', 'w');
    fwrite($out, "\xEF\xBB\xBF");
    fputcsv($out, $CSV_HEADERS);
    if (!$blank && $fProcess) {
        foreach (ar_inventory_rows($pdo, $fProcess, $fType) as $r) {
            $tier = (int) $r['tier'];
            fputcsv($out, [
                $fProcess, $r['chart_number'], $r['visit_id'], $r['carrier_name'], $r['min_dos'],
                $r['ins_bal'], $r['pat_bal'], $tier ?: '',
                $r['cur_email'] ?? '', $r['cur_status'] ?? '',
                (float) $r['ins_bal'] > 0 ? 'insurance_bal' : 'patient_bal',   // suggested allocation_type
                AR_TIER_PRIORITY[$tier] ?? 'regular',                          // suggested priority
                '',                                                           // assign_user_email — left blank for the supervisor
            ]);
        }
    }
    fclose($out);
    exit;
}

/* ============================================================ POST: force upload */
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    csrf_check_or_die();
    if (!can('ar.allocate')) { http_response_code(403); exit('Forbidden'); }

    if (($_POST['action'] ?? '') === 'force_upload') {
        if (!isset($_FILES['csv']) || !is_uploaded_file($_FILES['csv']['tmp_name'] ?? '')) {
            flash('error', 'Choose a CSV file to upload.'); redirect($selfUrl());
        }
        $emailToId = [];
        foreach ($pdo->query("SELECT id, LOWER(email) em FROM users WHERE status='active' AND user_type='internal'")->fetchAll() as $u)
            $emailToId[$u['em']] = (int) $u['id'];

        $byAcct = []; $conflicts = 0; $line = 0; $ci = [];
        $fh = fopen($_FILES['csv']['tmp_name'], 'r');
        if ($fh) {
            while (($row = fgetcsv($fh)) !== false) {
                $line++;
                if ($row === [null] || $row === false) continue;
                $cells = array_map(fn($c) => trim((string) $c), $row);
                if ($line === 1) {   // header row → map columns by name (robust to reordering)
                    $cells[0] = ltrim($cells[0], "\xEF\xBB\xBF");
                    foreach ($cells as $i => $h) $ci[strtolower($h)] = $i;
                    continue;
                }
                if (count(array_filter($cells, fn($c) => $c !== '')) === 0) continue;
                $get = fn($name, $alt = null) => isset($ci[$name]) ? ($cells[$ci[$name]] ?? '') : ($alt !== null && isset($ci[$alt]) ? ($cells[$ci[$alt]] ?? '') : '');
                $email = strtolower(trim((string) $get('assign_user_email', 'user_email')));
                if ($email === '') continue;                                 // unassigned row → ignore
                $pid   = (int) ltrim((string) $get('process_id'), "\xEF\xBB\xBF");
                $chart = (string) $get('patient_account', 'chart_number');
                if (!$pid || $chart === '') continue;
                $key = $pid . '|' . $chart;
                $valid = isset($emailToId[$email]);
                if (!isset($byAcct[$key])) {
                    $byAcct[$key] = ['process_id' => $pid, 'chart_number' => $chart, 'email' => ($valid ? $email : ''),
                                     'type' => (string) $get('allocation_type'), 'prio' => (string) $get('priority')];
                } elseif ($byAcct[$key]['email'] === '' && $valid) {
                    $byAcct[$key]['email'] = $email;                         // first VALID email wins (a bad first row never pre-empts a good later one)
                } elseif ($byAcct[$key]['email'] !== '' && $byAcct[$key]['email'] !== $email) {
                    $conflicts++;                                            // a different user for the same account
                }
            }
            fclose($fh);
        }

        $items = []; $badEmail = 0;
        foreach ($byAcct as $a) {
            $u = $emailToId[$a['email']] ?? 0;
            if (!$u) { $badEmail++; continue; }
            $items[] = ['process_id' => $a['process_id'], 'chart_number' => $a['chart_number'], 'user_id' => $u,
                        'allocation_type' => $a['type'] ?: 'insurance_bal', 'priority' => $a['prio']];
        }
        if (!$items) {
            flash('error', $badEmail ? "No accounts assigned — $badEmail had an unknown / inactive user email." : 'No rows had an assign_user_email to force-allocate.');
        } else {
            $res = ar_force_allocate($pdo, $items, $uid);
            $note = ($badEmail ? " · $badEmail bad email(s)" : '') . ($conflicts ? " · $conflicts conflicting row(s) ignored (one user per account)" : '');
            flash('success', "Force-allocated {$res['allocated']} account(s) (skipped {$res['skipped']})$note.");
        }
        redirect($selfUrl());
    }
    redirect($selfUrl());
}

/* ============================================================ GET — page data */
$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'
));
if ($fVertical && !in_array($fVertical, array_map(fn($v) => (int) $v['id'], $verticals), true)) $fVertical = 0;   // reject non-AR vertical
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;   // never read a non-AR process

$invRows = $fProcess ? ar_inventory_rows($pdo, $fProcess, $fType) : [];
$invAccounts = count(array_unique(array_map(fn($r) => $r['chart_number'], $invRows)));

$pageTitle = 'AR force allocation';
require __DIR__ . '/../includes/header.php';
?>
<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-file-upload me-2 text-primary"></i>AR force allocation</h2>
        <div class="text-secondary small">Assign <strong>specific</strong> patient accounts to <strong>specific</strong> users — download the open inventory, fill <code>assign_user_email</code>, and upload. A whole Patient Account # always goes to one user. Use this for one-off / patient-balance assignments that bypass the tier engine.</div></div>
    <div class="col-auto"><a href="<?= e(url('/admin/ar-allocation.php')) ?>" class="btn btn-outline-secondary"><i class="ti ti-arrows-shuffle me-1"></i>Tier allocation</a></div>
</div></div></div>

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

    <div class="card mb-3"><div class="card-body">
        <form method="GET" class="row g-2 align-items-end">
            <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-4"><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>
        </form>
    </div></div>

    <?php if ($fProcess): ?>
    <!-- Step 1: download -->
    <div class="card mb-3">
        <div class="card-header"><h3 class="card-title"><i class="ti ti-download me-2"></i>1 · Download inventory <span class="text-secondary fw-normal small ms-1"><?= number_format(count($invRows)) ?> open visit(s) · <?= number_format($invAccounts) ?> account(s)</span></h3></div>
        <div class="card-body">
            <p class="text-secondary small mb-2">Pick which balance to pull, download the open inventory (every column the system knows, plus an empty <code>assign_user_email</code>), put a user's email next to each account you want to force-assign, and upload it in step 2.</p>
            <form method="GET" class="row g-2 align-items-end mb-2">
                <input type="hidden" name="vertical_id" value="<?= $fVertical ?>"><input type="hidden" name="process_id" value="<?= $fProcess ?>">
                <div class="col-auto"><label class="form-label small mb-1">Allocation type to download</label>
                    <select name="alloc_type" class="form-select form-select-sm" onchange="this.form.submit()">
                        <option value="insurance_bal" <?= $fType==='insurance_bal'?'selected':'' ?>>Insurance balance (&gt; 0)</option>
                        <option value="patient_bal"   <?= $fType==='patient_bal'?'selected':'' ?>>Patient balance (&gt; 0)</option>
                        <option value="all"           <?= $fType==='all'?'selected':'' ?>>All open (insurance or patient)</option>
                    </select></div>
                <div class="col-auto text-secondary small mb-1"><?= number_format(count($invRows)) ?> visit(s) match</div>
            </form>
            <div class="d-flex flex-wrap gap-2">
                <a href="<?= e(url($selfUrl(['download' => 'inventory']))) ?>" class="btn btn-primary"><i class="ti ti-table-export me-1"></i>Download inventory (CSV)</a>
                <a href="<?= e(url($selfUrl(['download' => 'template']))) ?>" class="btn btn-outline-secondary"><i class="ti ti-file-text me-1"></i>Blank template</a>
            </div>
        </div>
    </div>

    <!-- Step 2: upload -->
    <div class="card mb-3">
        <div class="card-header"><h3 class="card-title"><i class="ti ti-upload me-2"></i>2 · Upload force assignments</h3></div>
        <div class="card-body">
            <p class="text-secondary small mb-2">Upload the filled CSV. Only rows with an <code>assign_user_email</code> are actioned; rows are grouped by <strong>Patient Account #</strong> and the whole account goes to that user (insurance + patient balance). Columns are matched by header name, so column order doesn't matter.</p>
            <form method="POST" action="<?= e(url($selfUrl())) ?>" enctype="multipart/form-data" class="d-flex align-items-end gap-2 flex-wrap">
                <?= csrf_field() ?><input type="hidden" name="action" value="force_upload">
                <div><label class="form-label">CSV file</label><input type="file" name="csv" accept=".csv,text/csv" class="form-control" required></div>
                <button class="btn btn-primary"><i class="ti ti-upload me-1"></i>Upload &amp; force-allocate</button>
            </form>
        </div>
    </div>

    <!-- Inventory preview -->
    <div class="card">
        <div class="card-header"><h3 class="card-title"><i class="ti ti-list me-2"></i>Open inventory preview</h3></div>
        <div class="table-responsive"><table class="table table-vcenter card-table table-sm">
            <thead><tr><th>Patient Account #</th><th>Visit ID</th><th>Carrier</th><th>DOS</th><th class="text-end">Ins. balance</th><th>Tier</th><th>Current user</th><th>Status</th></tr></thead>
            <tbody>
            <?php if (!$invRows): ?><tr><td colspan="8" class="text-center text-secondary py-4">No open insurance-balance inventory for this process.</td></tr>
            <?php else: foreach (array_slice($invRows, 0, 500) as $r): ?>
                <tr>
                    <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['min_dos'])) ?></td>
                    <td class="text-end small"><?= number_format((float)$r['ins_bal'], 2) ?></td>
                    <td><span class="badge bg-secondary-lt"><?= (int)$r['tier'] ?: '—' ?></span></td>
                    <td class="small"><?= e($r['cur_name'] ?? '—') ?></td>
                    <td class="small"><?= e($r['cur_status'] ? str_replace('_',' ',$r['cur_status']) : 'unallocated') ?></td>
                </tr>
            <?php endforeach; endif; ?>
            </tbody>
        </table></div>
        <?php if (count($invRows) > 500): ?><div class="card-footer text-secondary small">Previewing first 500 of <?= number_format(count($invRows)) ?> — the download has them all.</div><?php endif; ?>
    </div>
    <?php else: ?>
        <div class="card"><div class="card-body text-secondary"><i class="ti ti-arrow-up me-1"></i>Select a <strong>vertical</strong> then a <strong>process</strong> to download its inventory and force-allocate.</div></div>
    <?php endif; ?>

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