<?php
/**
 * Collection Raw upload — always replace_all with atomic swap (old data stays
 * live until new file is fully ingested and validated).
 */
require_once __DIR__ . '/../includes/config.php';
require_once __DIR__ . '/../includes/collection-engine.php';

$me  = require_login('internal');
$pdo = db();

/* Resolve the parent report context (Billing › PY-Medical SNF › Collection Dashboard) */
$reportId = (int) ($_GET['id'] ?? $_POST['id'] ?? 0);
if (!$reportId) {
    try {
        $st = $pdo->query("SELECT id FROM reports WHERE code='COLL-DASH' AND deleted_at IS NULL LIMIT 1");
        $reportId = $st ? (int) $st->fetchColumn() : 0;
    } catch (Throwable $e) { /* tables not yet created */ }
}
if ($reportId) require_report_access($reportId);   // can only replace data for a report they're granted
$backUrl = $reportId ? url('/admin/collection.php?id=' . $reportId) : url('/admin/reports.php');

/* Pre-flight: required tables */
try {
    $pdo->query('SELECT 1 FROM collection_raw LIMIT 1');
    $pdo->query('SELECT 1 FROM collection_uploads LIMIT 1');
} catch (Throwable $e) {
    $pageTitle = 'Upload Collection';
    require __DIR__ . '/../includes/header.php';
    echo '<div class="container-xl"><div class="alert alert-danger mt-4">'
       . '<h3><i class="ti ti-alert-octagon me-1"></i>Collection schema not applied</h3>'
       . '<p>Run <code>mysql -u root medmecs_mis &lt; sql/collection-dashboard.sql</code> and refresh.</p>'
       . '<p class="small mb-0"><strong>Detail:</strong> ' . e($e->getMessage()) . '</p></div></div>';
    require __DIR__ . '/../includes/footer.php';
    exit;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $backParam = $reportId ? '?id='.$reportId : '';

    // A POST body larger than PHP's post_max_size is silently discarded — $_POST and
    // $_FILES come back empty. Detect that and explain it, instead of a confusing error.
    if (empty($_POST) && empty($_FILES) && (int) ($_SERVER['CONTENT_LENGTH'] ?? 0) > 0) {
        flash('error', 'That file is larger than the server upload limit (post_max_size). Raise the PHP limits in cPanel, OR upload the CSV with File Manager into storage/uploads/collection/ and use “Ingest a file already on the server” below.');
        redirect('/admin/upload-collection.php' . $backParam);
    }

    csrf_check_or_die();
    if ((string)($_POST['confirm'] ?? '') !== 'REPLACE') {
        flash('error', 'Type REPLACE to confirm. The old data is kept active until the new file is fully validated.');
        redirect('/admin/upload-collection.php' . $backParam);
    }

    $dir = __DIR__ . '/../storage/uploads/collection';
    if (!is_dir($dir)) mkdir($dir, 0755, true);

    // Source = (a) a file already on the server (for large files), or (b) an HTTP upload.
    $serverFile = trim((string) ($_POST['server_file'] ?? ''));
    if ($serverFile !== '') {
        $dest = $dir . '/' . basename($serverFile);          // basename() blocks path traversal
        if (!is_file($dest)) {
            flash('error', 'Server file not found in storage/uploads/collection/: ' . basename($serverFile));
            redirect('/admin/upload-collection.php' . $backParam);
        }
        $ext = strtolower(pathinfo($dest, PATHINFO_EXTENSION));
        if (!in_array($ext, ['csv','tsv'], true)) {
            flash('error', "Only .csv / .tsv accepted (got .$ext).");
            redirect('/admin/upload-collection.php' . $backParam);
        }
    } else {
        if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
            $err = (int) ($_FILES['file']['error'] ?? -1);
            $msg = ($err === UPLOAD_ERR_INI_SIZE || $err === UPLOAD_ERR_FORM_SIZE)
                 ? 'The file exceeds the server upload limit. Raise PHP upload_max_filesize / post_max_size in cPanel, or use “Ingest a file already on the server” below.'
                 : 'No file uploaded.';
            flash('error', $msg);
            redirect('/admin/upload-collection.php' . $backParam);
        }
        $ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
        if (!in_array($ext, ['csv','tsv'], true)) {
            flash('error', "Only .csv / .tsv accepted (got .$ext).");
            redirect('/admin/upload-collection.php' . $backParam);
        }
        $dest = $dir . '/' . date('YmdHis') . '_' . bin2hex(random_bytes(4)) . '.' . $ext;
        if (!move_uploaded_file($_FILES['file']['tmp_name'], $dest)) {
            flash('error', 'Failed to save file.');
            redirect('/admin/upload-collection.php' . $backParam);
        }
    }

    try {
        set_time_limit(0);
        ini_set('memory_limit', '1G');
        $eng = new CollectionEngine();
        if (!$reportId) {
            flash('error', 'A report context is required.  Open the Collection Dashboard for a report and use its Replace Collection button.');
            redirect($backUrl);
        }
        $res = $eng->ingestCollection($dest, (int)$me['id'], $reportId);
        audit_log('collection.upload','collection', null, null, $res);
        flash('success', sprintf('Collection data replaced: %d valid, %d errors (out of %d total). DOS year/month + facility + expected payment derived.',
            $res['valid'], $res['errors'], $res['total']));
        redirect($reportId ? '/admin/collection.php?id='.$reportId : '/admin/reports.php');
    } catch (Throwable $t) {
        flash('error', 'Ingest failed: ' . $t->getMessage());
        redirect('/admin/upload-collection.php' . $backParam);
    }
}

$st = $pdo->prepare("SELECT * FROM collection_uploads WHERE report_id = ? AND kind='collection' ORDER BY created_at DESC LIMIT 1");  $st->execute([$reportId]); $last    = $st->fetch();
$st = $pdo->prepare("SELECT * FROM collection_uploads WHERE report_id = ? AND kind='collection' ORDER BY created_at DESC LIMIT 12"); $st->execute([$reportId]); $history = $st->fetchAll();

/* Live row count = valid_rows of the latest COMPLETED upload (data is fully
   replaced per upload), so we avoid a COUNT(*) over collection_raw on load. */
$st = $pdo->prepare("SELECT valid_rows FROM collection_uploads
                      WHERE report_id = ? AND kind='collection' AND status='completed'
                      ORDER BY completed_at DESC LIMIT 1");
$st->execute([$reportId]);
$liveCount = $st->fetchColumn();
if ($liveCount === false) {
    $st = $pdo->prepare('SELECT COUNT(*) FROM collection_raw WHERE report_id = ?');
    $st->execute([$reportId]); $liveCount = (int) $st->fetchColumn();
} else {
    $liveCount = (int) $liveCount;
}

/* Collection files uploaded to the server but not yet processed — survive a page reload.
   Facility-mapping uploads are handled on their own page and intentionally excluded here. */
$pendRows = [];
try {
    $ps = $pdo->prepare("SELECT * FROM pending_uploads WHERE report_id = ? AND status='pending' AND kind='collection' ORDER BY id DESC");
    $ps->execute([$reportId]);
    $pendRows = $ps->fetchAll();
} catch (Throwable $e) { /* pending_uploads not present yet */ }
$pendColl = $pendRows[0] ?? null;

$pageTitle = 'Upload Collection Raw';
require __DIR__ . '/../includes/header.php';
?>
<div class="page-header"><div class="container-xl">
    <div class="row align-items-center">
        <div class="col">
            <a href="<?= e($backUrl) ?>" class="text-secondary small text-decoration-none"><i class="ti ti-chevron-left"></i> Collection Dashboard</a>
            <h2 class="page-title mt-1"><i class="ti ti-cloud-upload me-2 text-primary"></i>Replace Collection Data</h2>
            <div class="text-secondary">Upload the new Collection Raw CSV. Old data stays live until the new file is fully ingested.</div>
        </div>
        <div class="col-auto d-flex gap-2 flex-wrap">
            <button type="button" id="clearBtn" class="btn btn-outline-danger" title="Wipe all collection data for this report (keeps facility mapping)">
                <i class="ti ti-trash me-1"></i>Clear all data
            </button>
            <a href="<?= e(url('/admin/template.php?kind=collection')) ?>" class="btn btn-outline-primary" download>
                <i class="ti ti-download me-1"></i>Download CSV template
            </a>
        </div>
    </div>
</div></div>

<div class="page-body"><div class="container-xl">
    <div class="row row-cards">
        <div class="col-md-7">
            <div class="card">
                <div class="card-body">
                    <?php if ($pendRows): ?>
                    <!-- ============ FILES READY TO PROCESS (persist across reloads) ============ -->
                    <div class="mb-3">
                        <div class="mb-2"><span class="badge bg-azure-lt text-azure"><i class="ti ti-clock-check me-1"></i>On server — ready to process</span></div>
                        <div class="list-group mb-2">
                            <?php foreach ($pendRows as $pr): ?>
                            <div class="list-group-item d-flex align-items-center py-2">
                                <span class="badge bg-<?= $pr['kind']==='collection'?'blue':'purple' ?>-lt me-2"><?= $pr['kind']==='collection'?'Collection':'Mapping' ?></span>
                                <div class="flex-grow-1 text-truncate">
                                    <span class="small"><?= e($pr['orig_name'] ?: $pr['file_name']) ?></span>
                                    <span class="text-secondary small ms-1">· <?= $pr['file_size'] ? number_format($pr['file_size']/1048576,1).' MB' : '' ?> · <?= e(fmt_dt($pr['created_at'])) ?></span>
                                </div>
                                <button type="button" class="btn btn-sm btn-ghost-danger discardBtn" data-token="<?= e($pr['token']) ?>" data-kind="<?= e($pr['kind']) ?>" title="Discard this file"><i class="ti ti-trash"></i></button>
                            </div>
                            <?php endforeach; ?>
                        </div>
                        <?php if ($pendColl): ?>
                            <label class="form-label required mb-1">Type <code>APPEND</code> to confirm, then click Append</label>
                            <div class="d-flex gap-2 align-items-center flex-wrap">
                                <input type="text" id="procConfirm" class="form-control" placeholder="APPEND" style="max-width:220px">
                                <button type="button" id="appendBtn" class="btn btn-primary"
                                        data-coll-token="<?= e($pendColl['token']) ?>" data-map-token="">
                                    <i class="ti ti-row-insert-bottom me-1"></i>Append (add to existing)
                                </button>
                            </div>
                            <div class="form-hint mt-1">
                                Adds these rows to whatever's already there. Use <em>Clear all data</em> first if you want to start fresh, or upload a big file in pieces and Append each one.
                            </div>
                            <div id="procProgWrap" class="mt-3 d-none">
                                <div class="d-flex justify-content-between small mb-1"><span id="procStatus" class="text-secondary">Processing…</span><span id="procPct" class="fw-bold">0%</span></div>
                                <div class="progress" style="height:1.1rem"><div id="procBar" class="progress-bar progress-bar-striped progress-bar-animated bg-warning" style="width:0%"></div></div>
                            </div>
                            <div id="procErr" class="alert alert-danger mt-2 d-none"></div>
                        <?php else: ?>
                            <div class="text-warning small"><i class="ti ti-alert-triangle me-1"></i>A <strong>Collection Raw</strong> file is required to process — upload one below.</div>
                        <?php endif; ?>
                    </div>
                    <hr class="my-3">
                    <?php endif; ?>

                    <div class="alert alert-warning d-flex align-items-start">
                        <i class="ti ti-shield-check me-2 mt-1"></i>
                        <div>
                            <strong><?= $pendRows ? 'Upload more / replace a file' : 'Two steps: upload, then process' ?>:</strong>
                            <ul class="mb-0 small mt-1">
                                <li>Upload the <strong>Collection Raw</strong> file — it's just <em>stored on the server</em> first.</li>
                                <li>They then appear above as <strong>“ready to process”</strong>; click <strong>Process</strong> to run the mapping + import. This survives a page reload.</li>
                                <li>Processing loads into staging, derives DOS/facility/expected, then swaps staging → live in one transaction. If anything fails, the previous data is preserved.</li>
                            </ul>
                        </div>
                    </div>
                    <form id="uplForm" onsubmit="return false">
                        <div class="text-secondary small mb-2"><strong>Step 1 — upload the Collection Raw file to the server.</strong> Stored only; nothing changes until you click Append.</div>
                        <div class="d-flex align-items-center justify-content-between mb-1">
                            <label class="form-label mb-0">Collection Raw file (CSV / TSV)</label>
                            <a href="<?= e(url('/admin/template.php?kind=collection')) ?>" class="small text-decoration-none" download><i class="ti ti-download me-1"></i>Collection template</a>
                        </div>
                        <input type="file" id="uplFile" accept=".csv,.tsv" class="form-control mb-1">
                        <div id="collState" class="form-hint mb-3"></div>

                        <button type="button" id="uplBtn" class="btn btn-primary"><i class="ti ti-cloud-upload me-1"></i>Upload to server</button>
                        <span class="ms-2 small text-secondary">Currently live: <strong><?= number_format($liveCount) ?></strong> rows</span>

                        <div id="uplProgWrap" class="mt-3 d-none">
                            <div class="d-flex justify-content-between small mb-1">
                                <span id="uplStatus" class="text-secondary">Uploading…</span>
                                <span id="uplPct" class="fw-bold">0%</span>
                            </div>
                            <div class="progress" style="height:1.1rem">
                                <div id="uplBar" class="progress-bar progress-bar-striped progress-bar-animated" style="width:0%"></div>
                            </div>
                            <div class="form-hint mt-1"><i class="ti ti-alert-triangle me-1"></i>Please keep this page open until it finishes.</div>
                        </div>
                        <div id="uplErr" class="alert alert-danger mt-3 d-none"></div>
                    </form>
                    <div class="small text-secondary mt-2"><i class="ti ti-info-circle me-1"></i>Large files upload in pieces with a live progress bar — no size limit, no cPanel needed.</div>
                </div>
            </div>
        </div>
        <div class="col-md-5">
            <div class="card">
                <div class="card-header"><h3 class="card-title small mb-0"><i class="ti ti-history me-1"></i>Upload history</h3></div>
                <div class="table-responsive">
                    <table class="table table-sm card-table">
                        <thead><tr><th>When</th><th>File</th><th class="text-end">Rows</th><th>Status</th></tr></thead>
                        <tbody>
                        <?php if (!$history): ?>
                            <tr><td colspan="4" class="text-center text-secondary py-3">No uploads yet.</td></tr>
                        <?php else: foreach ($history as $h): ?>
                            <tr>
                                <td class="small text-secondary text-nowrap"><?= e(fmt_dt($h['created_at'])) ?></td>
                                <td class="small text-truncate" style="max-width:160px"><?= e($h['file_name']) ?></td>
                                <td class="text-end"><?= number_format((int)$h['valid_rows']) ?> / <?= number_format((int)$h['total_rows']) ?></td>
                                <td><span class="badge bg-<?= $h['status']==='completed'?'success':($h['status']==='failed'?'danger':'info') ?>-lt"><?= e($h['status']) ?></span></td>
                            </tr>
                        <?php endforeach; endif; ?>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div></div>
<?php require __DIR__ . '/../includes/chunk-upload-js.php'; ?>
<script>
(function(){
    function g(id){ return document.getElementById(id); }
    var REPORT=<?= (int)$reportId ?>, CSRF=<?= json_encode(csrf_token()) ?>,
        ENDPOINT=<?= json_encode(url('/admin/upload-chunk.php')) ?>, REDIRECT=<?= json_encode(url('/admin/collection.php?id='.$reportId)) ?>;
    function postJSON(fd){ return fetch(ENDPOINT,{method:'POST',body:fd,credentials:'same-origin'})
        .then(function(r){ return r.json().catch(function(){ throw new Error('Unexpected server response (HTTP '+r.status+').'); }); }); }

    /* ---------- Step 1: upload (store) file(s), then reload so the "ready to process" list updates ---------- */
    var upBtn=g('uplBtn');
    if(upBtn){
        var fileEl=g('uplFile'), wrap=g('uplProgWrap'), bar=g('uplBar'),
            pct=g('uplPct'), statusEl=g('uplStatus'), errBox=g('uplErr');
        function uFail(msg){ errBox.textContent=msg; errBox.classList.remove('d-none'); bar.classList.add('bg-danger'); statusEl.textContent='Failed';
            upBtn.disabled=false; fileEl.disabled=false; }
        function uProg(label){ return function(p){ bar.style.width=p+'%'; pct.textContent=p+'%'; statusEl.textContent=label+': uploading '+p+'%…'; }; }
        upBtn.addEventListener('click', function(){
            errBox.classList.add('d-none');
            if(!(fileEl.files && fileEl.files[0])){ return uFail('Choose a Collection Raw file.'); }
            upBtn.disabled=true; fileEl.disabled=true; wrap.classList.remove('d-none');
            bar.style.width='0%'; bar.classList.remove('bg-success','bg-danger');
            mChunkUpload({ file:fileEl.files[0], kind:'collection', reportId:REPORT, csrf:CSRF, storeOnly:true, endpoint:ENDPOINT,
                onProgress:uProg('Collection raw'),
                onDone:function(){ bar.classList.add('bg-success'); pct.textContent='✓';
                    statusEl.textContent='Uploaded to server. Reloading…'; setTimeout(function(){ window.location.reload(); }, 700); },
                onError:uFail });
        });
    }

    /* ---------- Step 2: append the stored collection file ---------- */
    var appendBtn=g('appendBtn');
    if(appendBtn){
        var pConf=g('procConfirm'), pWrap=g('procProgWrap'), pBar=g('procBar'), pPct=g('procPct'), pStat=g('procStatus'), pErr=g('procErr');
        var collToken=appendBtn.getAttribute('data-coll-token')||'';
        function pFail(msg){ pErr.textContent=msg; pErr.classList.remove('d-none'); pBar.classList.remove('bg-warning'); pBar.classList.add('bg-danger'); pStat.textContent='Failed';
            appendBtn.disabled=false; pConf.disabled=false; }
        appendBtn.addEventListener('click', function(){
            pErr.classList.add('d-none');
            if(!collToken){ return pFail('No collection file to process.'); }
            if((pConf.value||'').trim().toUpperCase() !== 'APPEND'){ return pFail('Type APPEND to confirm.'); }
            appendBtn.disabled=true; pConf.disabled=true; pWrap.classList.remove('d-none');
            pBar.style.width='100%'; pBar.classList.remove('bg-success','bg-danger'); pBar.classList.add('bg-warning'); pPct.textContent='100%';
            var started=Date.now();
            var timer=setInterval(function(){ var t=Math.round((Date.now()-started)/1000);
                pStat.textContent='Appending on the server — '+(t>=60?(Math.floor(t/60)+'m '+(t%60)+'s'):(t+'s'))+' elapsed. Please wait…'; },1000);
            function done(j){ clearInterval(timer); pBar.classList.remove('bg-warning'); pBar.classList.add('bg-success'); pPct.textContent='✓';
                pStat.textContent='Done — '+Number(j.valid||0).toLocaleString()+' rows. Redirecting…'; setTimeout(function(){ window.location.href=j.redirect||REDIRECT; },1100); }
            function f9(msg){ clearInterval(timer); pFail(msg); }
            function poll(){
                if(Date.now()-started>45*60*1000){ return f9('Still processing after 45 min — reopen the report shortly; it may finish in the background.'); }
                var sfd=new FormData(); sfd.append('action','status'); sfd.append('token',collToken); sfd.append('kind','collection'); sfd.append('report_id',REPORT); sfd.append('_csrf',CSRF);
                postJSON(sfd).then(function(s){ if(s.status==='completed')done(s); else if(s.status==='failed')f9(s.note||'Processing failed.'); else setTimeout(poll,3000); }).catch(function(){ setTimeout(poll,4000); });
            }
            var fd=new FormData(); fd.append('action','process'); fd.append('token',collToken); fd.append('kind','collection');
            fd.append('map_token',''); fd.append('report_id',REPORT); fd.append('_csrf',CSRF);
            fd.append('confirm','APPEND'); fd.append('append','1');
            postJSON(fd).then(function(j){ if(j.processing){ poll(); return; } if(j.ok){ done(j); } else { f9(j.error||'Processing failed.'); } }).catch(function(){ poll(); });
        });
    }

    /* ---------- Clear ALL data for this report (keeps facility mapping) ---------- */
    var clearBtn=g('clearBtn');
    if(clearBtn){
        clearBtn.addEventListener('click', function(){
            var typed = prompt('⚠ This will WIPE the live collection data for this report.\n\nPRESERVED (kept on purpose):\n  • Facility Mapping\n  • Snapshot history — so the Compare tab keeps working\n  • Upload history\n\nA final snapshot of the current data is captured BEFORE wiping, so you can still compare\n"before clear" vs "after the next append" in the Compare tab.\n\nType CLEAR (exactly) to confirm:');
            if(typed === null) return;
            if((typed||'').trim().toUpperCase() !== 'CLEAR'){ alert('Cancelled — confirmation text did not match.'); return; }
            clearBtn.disabled=true;
            var prev=clearBtn.innerHTML; clearBtn.innerHTML='<i class="ti ti-loader-2"></i> Clearing…';
            var fd=new FormData(); fd.append('action','clear'); fd.append('kind','collection');
            fd.append('report_id',REPORT); fd.append('_csrf',CSRF); fd.append('confirm','CLEAR');
            postJSON(fd).then(function(j){
                if(!j.ok){ alert('Clear failed: '+(j.error||'unknown')); clearBtn.disabled=false; clearBtn.innerHTML=prev; return; }
                var c=j.counts||{};
                var snap = c.snapshot_taken ? ' · Pre-clear snapshot saved for Compare.' : '';
                alert('Cleared. Removed: live='+(c.live||0)+', stage='+(c.stage||0)+', pending='+(c.pending||0)+' rows.' + snap);
                window.location.reload();
            }).catch(function(e){ alert('Clear request failed.'); clearBtn.disabled=false; clearBtn.innerHTML=prev; });
        });
    }

    /* ---------- Discard a pending (stored-but-unprocessed) file ---------- */
    Array.prototype.forEach.call(document.querySelectorAll('.discardBtn'), function(b){
        b.addEventListener('click', function(){
            if(!confirm('Discard this uploaded file?')) return;
            b.disabled=true;
            var fd=new FormData(); fd.append('action','discard'); fd.append('token',b.getAttribute('data-token'));
            fd.append('kind',b.getAttribute('data-kind')); fd.append('report_id',REPORT); fd.append('_csrf',CSRF);
            postJSON(fd).then(function(){ window.location.reload(); }).catch(function(){ window.location.reload(); });
        });
    });
})();
</script>
<?php require __DIR__ . '/../includes/footer.php'; ?>
