<?php

declare(strict_types=1);

require DENTAL_ROOT . '/app/bootstrap.php';
require_once DENTAL_ROOT . '/app/tooth_model.php';
require_once DENTAL_ROOT . '/app/transaction_integrity.php';
require_once DENTAL_ROOT . '/app/inventory_integrity.php';
require_once DENTAL_ROOT . '/app/revenue_integrity.php';
require_once DENTAL_ROOT . '/app/clinical_record_completion.php';
require_login();
$previewType = trim((string) ($_GET['type'] ?? ''));
$previewDocument = trim((string) ($_GET['document'] ?? ''));
$cashierRoutinePrint = in_array(active_role(), ['cashier','staff'], true)
    && (in_array($previewType, ['invoice','receipt','payment_adjustment'], true)
        || ($previewType === 'patient_summary' && $previewDocument === 'ledger'));
$queueTicketPrint = $previewType === 'queue_ticket';
if ($queueTicketPrint) {
    require_permission('queue.manage', ['super_admin','clinic_admin','receptionist','staff','dentist','dental_assistant','cashier']);
} elseif ($cashierRoutinePrint) {
    require_permission('billing.manage', ['cashier','staff']);
} else {
    require_permission('records.print', ['super_admin','clinic_admin','dentist','receptionist','staff','dental_assistant','inventory_officer']);
}
require_documentation_schema();

$pdo = db();
$type = $previewType;
$id = (int) ($_GET['id'] ?? 0);
$reason = mb_substr(trim((string) ($_GET['reason'] ?? '')),0,255);
$date = trim((string) ($_GET['date'] ?? date('Y-m-d')));
$role = active_role();

function pr_requires_print_reason(string $type, string $document = ''): bool
{
    $type = trim($type);
    $document = trim($document);

    // Reason is required only for clinical/confidential record exports where the copy
    // leaves the normal operational workflow. Routine business documents should print
    // directly and still be audited with an empty/optional reason.
    if ($type === 'patient_summary') {
        return in_array($document, ['complete','medical'], true);
    }

    return in_array($type, [
        'encounter',
        'treatment_plan',
        'prescription',
        'audit_log',
    ], true);
}

$printDocument = trim((string) ($_GET['document'] ?? ''));
$requiresReason = pr_requires_print_reason($type, $printDocument);
if ($requiresReason && $reason === '') {
    $brand = branding_profile();
    $clinic = public_clinic_profile();
    $preserved = $_GET;
    unset($preserved['reason']);
    ?><!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Reason for printing</title><style>
    *{box-sizing:border-box}body{margin:0;min-height:100vh;display:grid;place-items:center;padding:24px;background:#f4f7f8;color:#14213d;font-family:Arial,sans-serif}.reason-card{width:min(560px,100%);background:#fff;border:1px solid #dce5e8;border-radius:20px;padding:26px;box-shadow:0 22px 65px rgba(20,33,61,.14)}.brand{display:flex;align-items:center;gap:12px;margin-bottom:20px}.mark{width:46px;height:46px;border-radius:14px;display:grid;place-items:center;background:<?=e($brand['primary'])?>;color:#fff;font-weight:900;font-size:20px}.brand strong,.brand small{display:block}.brand small{margin-top:3px;color:#667085}.eyebrow{font-size:11px;font-weight:900;letter-spacing:.1em;text-transform:uppercase;color:<?=e($brand['primary'])?>}h1{margin:7px 0 8px;font-size:25px}p{margin:0 0 18px;color:#667085;line-height:1.55}label{display:block;font-weight:800}textarea{width:100%;min-height:110px;margin-top:8px;padding:12px;border:1px solid #cfd9dd;border-radius:12px;font:inherit;resize:vertical}textarea:focus{outline:3px solid color-mix(in srgb,<?=e($brand['primary'])?> 20%,transparent);border-color:<?=e($brand['primary'])?>}.actions{display:flex;justify-content:flex-end;gap:10px;margin-top:18px}.btn{border:0;border-radius:11px;padding:11px 16px;font-weight:800;cursor:pointer}.btn.primary{background:<?=e($brand['primary'])?>;color:#fff}.btn.ghost{background:#edf2f3;color:#344054}</style></head><body><main class="reason-card"><div class="brand"><div class="mark">D</div><div><strong><?=e($brand['name'])?></strong><small><?=e((string) ($clinic['address'] ?? ''))?></small></div></div><span class="eyebrow">Confidential record control</span><h1>Enter a reason for printing</h1><p>This reason is required only for clinical/confidential record exports and is recorded in the audit log.</p><form method="get" action="print_record.php"><?php foreach ($preserved as $key => $value): if (is_scalar($value)): ?><input type="hidden" name="<?=e((string) $key)?>" value="<?=e((string) $value)?>"><?php endif; endforeach; ?><label>Reason<textarea name="reason" maxlength="255" required autofocus placeholder="Example: Patient requested a copy for referral"></textarea></label><div class="actions"><button type="button" class="btn ghost" onclick="window.close()">Cancel</button><button class="btn primary" type="submit">Open printable page</button></div></form></main></body></html><?php
    exit;
}

function pr_money($value): string { return '₱' . number_format((float) $value, 2); }
function pr_date(?string $value, bool $time = false): string { if (!$value) return '—'; return date($time ? 'F j, Y g:i A' : 'F j, Y', strtotime($value)); }
function pr_text($value): string { $value = trim((string) $value); return $value === '' ? '—' : nl2br(e($value)); }
function pr_require_role(array $roles): void { if (!in_array(active_role(), $roles, true)) { http_response_code(403); exit('This document is outside the active Task View.'); } }
function pr_log(string $type, ?int $recordId, ?int $patientId, ?int $branchId, string $reason): void {
    db()->prepare('INSERT INTO `' . table('print_logs') . '` (document_type,record_id,patient_id,branch_id,format,reason,printed_by,printed_at) VALUES (?,?,?,?,"html",?,?,NOW())')
        ->execute([$type,$recordId,$patientId,$branchId,$reason,(int) current_user()['id']]);
    // The server can prove that a printable page was opened, but the browser
    // cannot reliably report whether it was physically printed or saved as PDF.
    audit('record_opened_for_print','print',$recordId,[
        'document_type'=>$type,
        'patient_id'=>$patientId,
        'branch_id'=>$branchId,
        'reason'=>$reason,
        'event_status'=>'opened_for_print',
    ]);
}
function pr_header(string $title, ?array $patient = null, string $reference = ''): void {
    global $reason;
    $clinic = public_clinic_profile(); $brand = branding_profile();
    ?><!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title><?=e($title)?></title><style>
    @page{size:A4;margin:15mm 14mm 18mm}*{box-sizing:border-box}body{font-family:Arial,sans-serif;color:#14213d;margin:0;font-size:12px;line-height:1.45}.print-toolbar{position:sticky;top:0;background:#eef4f5;padding:10px;display:flex;gap:8px;justify-content:flex-end;border-bottom:1px solid #d8e1e5}.print-toolbar button{padding:8px 14px;border:0;border-radius:8px;background:#0f766e;color:white;font-weight:bold;cursor:pointer}.document{max-width:900px;margin:0 auto;padding:18px}.letterhead{display:flex;justify-content:space-between;gap:20px;border-bottom:3px solid <?=e($brand['primary'])?>;padding-bottom:12px;margin-bottom:18px}.clinic h1{margin:0;font-size:22px}.clinic p,.meta p{margin:2px 0;color:#536273}.meta{text-align:right}.print-reason{margin:0 0 14px;padding:10px 12px;border-left:4px solid <?=e($brand['primary'])?>;background:#f3f8f8;color:#344054}.print-reason strong{display:block;font-size:10px;text-transform:uppercase;color:#667085}.print-scope{margin:0 0 14px;padding:10px 12px;border:1px solid #cddfe1;border-radius:8px;background:#f7fbfb;color:#344054}.print-scope strong{display:block;font-size:10px;text-transform:uppercase;color:#667085}.print-timeline{display:grid;gap:8px}.print-timeline-item{border-left:3px solid <?=e($brand['primary'])?>;padding:7px 10px;background:#f8fbfb;break-inside:avoid}.print-timeline-item strong,.print-timeline-item small{display:block}.print-timeline-meta{color:#667085;font-size:10px;margin-top:3px}.patient-banner{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;padding:12px;background:#f4f8f8;border:1px solid #dce7e7;border-radius:10px;margin-bottom:16px}.section{margin:16px 0;break-inside:avoid}.section h2{font-size:14px;margin:0 0 8px;padding-bottom:5px;border-bottom:1px solid #ccd8dc;color:#0f5e59}.grid{display:grid;grid-template-columns:1fr 1fr;gap:8px 18px}.field strong{display:block;font-size:10px;text-transform:uppercase;color:#667085}.alert{padding:10px;border:1px solid #f0b4ae;background:#fff1f0;color:#8f2018;border-radius:8px}table{width:100%;border-collapse:collapse}th,td{border-bottom:1px solid #dce3e7;padding:7px;text-align:left;vertical-align:top}th{font-size:10px;text-transform:uppercase;color:#667085}.total{font-size:15px;font-weight:bold}.signature{margin-top:36px;display:grid;grid-template-columns:1fr 1fr;gap:60px}.signature div{border-top:1px solid #344054;padding-top:5px;text-align:center}.record-head{display:flex;justify-content:space-between;gap:15px;align-items:flex-start;margin-bottom:8px}.record-head strong,.record-head small{display:block}.record-head small,.muted{color:#667085}.encounter-card,.prescription-card,.plan-card{border:1px solid #dce3e7;border-radius:9px;padding:10px;margin:10px 0;break-inside:avoid}.image-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:9px}.image-card{border:1px solid #dce3e7;border-radius:9px;padding:7px;break-inside:avoid}.image-card img{display:block;width:100%;height:120px;object-fit:contain;background:#f2f4f5;border-radius:6px;margin-bottom:6px}.image-card strong,.image-card small{display:block}.footer{margin-top:30px;padding-top:10px;border-top:1px solid #dce3e7;color:#667085;font-size:10px;display:flex;justify-content:space-between}.page-number:after{content:"Page " counter(page)}@media print{.print-toolbar{display:none}.document{padding:0}a{color:inherit;text-decoration:none}}@media(max-width:650px){.patient-banner,.grid,.image-grid{grid-template-columns:1fr}.meta{text-align:left}.letterhead{flex-direction:column}}
    </style></head><body><div class="print-toolbar"><button onclick="window.print()">Print / Save PDF</button></div><main class="document"><header class="letterhead"><div class="clinic"><h1><?=e($brand['name'])?></h1><p><?=e($clinic['address']??'')?></p><p><?=e($clinic['phone']??'')?> · <?=e($clinic['email']??'')?></p></div><div class="meta"><strong><?=e($title)?></strong><?php if($reference):?><p>Reference: <?=e($reference)?></p><?php endif;?><p>Generated <?=e(date('F j, Y g:i A'))?></p><p>By <?=e((string)(current_user()['name']??''))?></p></div></header><?php if($reason!==''):?><section class="print-reason"><strong>Reason for printing</strong><?=e($reason)?></section><?php endif;?><?php if($patient):?><section class="patient-banner"><div><strong>Patient</strong><br><?=e(patient_full_name($patient))?></div><div><strong>Patient No.</strong><br><?=e($patient['patient_no'])?></div><div><strong>Birth Date</strong><br><?=pr_date($patient['birth_date'])?></div></section><?php endif;?><?php
}
function pr_footer(): void { ?><footer class="footer"><span>Confidential dental record. Handle according to clinic privacy policy.</span><span class="page-number"></span></footer></main></body></html><?php }
function pr_patient(int $id): array { $p=require_patient($id); return $p; }
function pr_fetch(PDO $pdo,string $sql,array $args=[]): ?array { try{$stmt=$pdo->prepare($sql);$stmt->execute($args);$row=$stmt->fetch();return $row?:null;}catch(Throwable $e){error_log('DentalCare print query failed: '.$e->getMessage());return null;} }
function pr_fetch_all(PDO $pdo,string $sql,array $args=[]): array { try{$stmt=$pdo->prepare($sql);$stmt->execute($args);return $stmt->fetchAll();}catch(Throwable $e){error_log('DentalCare print query failed: '.$e->getMessage());return [];} }
function pr_status(?string $value): string { $value=trim((string)$value); return $value===''?'—':ucwords(str_replace('_',' ',$value)); }
function pr_date_filter(mixed $value): string { $value=trim((string)$value); return preg_match('/^\d{4}-\d{2}-\d{2}$/',$value) && strtotime($value)!==false ? $value : ''; }
function pr_scope_clause(string $dateColumn, ?string $encounterColumn, array &$args, string $from, string $to, int $encounterId): string {
    $sql='';
    if($from!==''){$sql.=' AND DATE('.$dateColumn.')>=?';$args[]=$from;}
    if($to!==''){$sql.=' AND DATE('.$dateColumn.')<=?';$args[]=$to;}
    if($encounterId>0&&$encounterColumn!==null){$sql.=' AND '.$encounterColumn.'=?';$args[]=$encounterId;}
    return $sql;
}
function pr_scope_note(string $from,string $to,int $encounterId): void {
    if($from===''&&$to===''&&$encounterId<1)return;
    $parts=[];if($from!==''||$to!=='')$parts[]='Dates: '.($from!==''?pr_date($from):'Beginning').' to '.($to!==''?pr_date($to):'Present');if($encounterId>0)$parts[]='Encounter #'.$encounterId;
    ?><section class="print-scope"><strong>Selected record scope</strong><?=e(implode(' · ',$parts))?></section><?php
}
function pr_scope_rows(array $rows,array $dateKeys,?string $encounterKey,string $from,string $to,int $encounterId): array {
    if($from===''&&$to===''&&$encounterId<1)return $rows;$fromTs=$from!==''?strtotime($from.' 00:00:00'):false;$toTs=$to!==''?strtotime($to.' 23:59:59'):false;
    return array_values(array_filter($rows,static function(array $row) use($dateKeys,$encounterKey,$fromTs,$toTs,$encounterId): bool {
        $date='';foreach($dateKeys as $key){if(!empty($row[$key])){$date=(string)$row[$key];break;}}$ts=$date!==''?strtotime($date):false;if($fromTs!==false&&($ts===false||$ts<$fromTs))return false;if($toTs!==false&&($ts===false||$ts>$toTs))return false;if($encounterId>0&&$encounterKey!==null&&(int)($row[$encounterKey]??0)!==$encounterId)return false;return true;
    }));
}
function pr_tooth_region(?string $value): string { $value=trim((string)$value); if($value==='')return '—'; return dental_is_valid_fdi_tooth($value)?dental_tooth_display_label($value):$value; }
function pr_prescription_items(PDO $pdo,int $prescriptionId): array { return pr_fetch_all($pdo,'SELECT * FROM `' . table('prescription_items') . '` WHERE prescription_id=? ORDER BY id',[$prescriptionId]); }
function pr_render_prescription(PDO $pdo,array $rx,bool $latest=false): void {
    $items=pr_prescription_items($pdo,(int)$rx['id']);$signedName=(string)($rx['signed_by_name']??$rx['dentist_name']??'Dentist');$signedLicense=(string)($rx['signed_license_number']??$rx['license_number']??'');
    ?><article class="prescription-card"><div class="record-head"><div><strong><?= $latest?'Latest prescription':e((string)$rx['prescription_no']) ?></strong><small><?=e((string)$rx['prescription_no'])?> · <?=pr_date((string)($rx['issued_at']??$rx['created_at']??''),true)?></small></div><span><?=e(pr_status((string)($rx['status']??'')))?></span></div><p><strong>Prescriber:</strong> <?=e($signedName)?><?=$signedLicense!==''?' · License '.e($signedLicense):''?></p><?php if(!empty($rx['clinical_indication'])):?><p><strong>Clinical indication:</strong> <?=pr_text($rx['clinical_indication'])?></p><?php endif;?><?php if($items):?><table><thead><tr><th>Medicine / indication</th><th>Dose / Frequency / Route</th><th>Duration</th><th>Quantity</th><th>Instructions</th></tr></thead><tbody><?php foreach($items as $item):?><tr><td><strong><?=e(trim((string)$item['medication_name'].' '.(string)($item['strength']??'')))?></strong><?php if(!empty($item['generic_name'])):?><br><small><?=e((string)$item['generic_name'])?></small><?php endif;?><?php if(!empty($item['indication'])):?><br><small>For: <?=e((string)$item['indication'])?></small><?php endif;?></td><td><?=e(trim(implode(' · ',array_filter([(string)($item['dosage']??''),(string)($item['frequency']??''),(string)($item['route']??'')]))))?:'—'?></td><td><?=!empty($item['duration_days'])?e((string)$item['duration_days']).' days':'—'?></td><td><?=e((string)($item['quantity']??'—'))?></td><td><?=pr_text($item['instructions']??'')?></td></tr><?php endforeach;?></tbody></table><?php else:?><p>No medicine items were recorded.</p><?php endif;?><?php if(!empty($rx['notes'])):?><p><strong>Notes:</strong> <?=pr_text($rx['notes'])?></p><?php endif;?><?php if(($rx['status']??'')==='cancelled'):?><div class="alert"><strong>CANCELLED</strong><br><?=pr_text($rx['cancellation_reason']??'Cancelled by the issuing Dentist.')?><?=!empty($rx['cancelled_at'])?'<br>'.pr_date((string)$rx['cancelled_at'],true):''?></div><?php endif;?><?php if(!empty($rx['prescription_hash'])):?><p class="muted"><strong>Signed record hash:</strong> <?=e((string)$rx['prescription_hash'])?></p><?php endif;?></article><?php
}

$patientId = null; $branchId = null; $recordId = $id; $title='Record'; $reference='';
ob_start();

if ($type === 'patient_summary') {
    pr_require_role(['super_admin','clinic_admin','dentist','receptionist','staff','dental_assistant','cashier']);
    $patient=pr_patient($id);$patientId=$id;$branchId=(int)($patient['branch_id']??0);if(!record_branch_scope_allowed($branchId,$id)){audit('record_print_access_denied','patient',$id,['active_role'=>$role,'branch_id'=>$branchId,'reason'=>'branch_or_assignment_scope']);http_response_code(403);exit('This patient record is outside your authorized branch or assignment scope.');}$doc=(string)($_GET['document']??'summary');
    if($role==='cashier'&&$doc!=='ledger'){audit('record_print_access_denied','patient',$id,['active_role'=>$role,'document'=>$doc,'reason'=>'cashier_identity_minimization']);http_response_code(403);exit('Cashier printing is limited to the patient ledger and financial documents.');}
    $clinicalPrint=in_array($role,['super_admin','clinic_admin','dentist','dental_assistant'],true);
    $medicalPrint=in_array($role,['super_admin','clinic_admin','dentist','dental_assistant'],true);
    $financePrint=in_array($role,['super_admin','clinic_admin','cashier','staff'],true);
    if($doc==='complete'&&!$clinicalPrint){http_response_code(403);exit('The complete clinical record is outside this Task View.');}
    if($doc==='medical'&&!$medicalPrint){http_response_code(403);exit('Dental safety history printing is outside this Task View.');}
    if($doc==='ledger'&&!$financePrint){http_response_code(403);exit('Patient ledger printing is outside this Task View.');}
    if(!in_array($doc,['summary','complete','medical','ledger'],true))$doc='summary';
    $scopeFrom=$doc==='complete'?pr_date_filter($_GET['date_from']??''):'';$scopeTo=$doc==='complete'?pr_date_filter($_GET['date_to']??''):'';$scopeEncounterId=$doc==='complete'?max(0,(int)($_GET['encounter_id']??0)):0;
    if($scopeFrom!==''&&$scopeTo!==''&&strtotime($scopeFrom)>strtotime($scopeTo)){http_response_code(422);exit('The selected From date cannot be later than the To date.');}
    $scopeEncounter=null;$scopeAppointmentId=0;
    if($scopeEncounterId>0){$scopeEncounter=pr_fetch($pdo,'SELECT id,patient_id,appointment_id,created_at,dentist_name,assistant_name,status FROM `' . table('clinical_encounters') . '` WHERE id=? AND patient_id=? LIMIT 1',[$scopeEncounterId,$id]);if(!$scopeEncounter){http_response_code(404);exit('The selected encounter does not belong to this patient.');}$scopeAppointmentId=(int)($scopeEncounter['appointment_id']??0);}
    $titles=['summary'=>'Patient Profile Summary','complete'=>'Complete Patient Dental Record','medical'=>'Dental Treatment Safety History','ledger'=>'Patient Ledger'];$title=$titles[$doc];$reference=(string)$patient['patient_no'];pr_header($title,$patient,$reference);pr_scope_note($scopeFrom,$scopeTo,$scopeEncounterId);

    $alerts=$medicalPrint?pr_fetch_all($pdo,'SELECT a.*,u.name creator FROM `' . table('medical_alerts') . '` a LEFT JOIN `' . table('users') . '` u ON u.id=a.created_by WHERE a.patient_id=? AND a.is_active=1 ORDER BY FIELD(a.severity,"critical","caution","information"),a.created_at DESC',[$id]):[];
    if($medicalPrint&&(!empty($patient['medical_alerts'])||$alerts)):?><section class="section"><h2>Active Dental Treatment Safety Alerts</h2><?php if(!empty($patient['medical_alerts'])):?><div class="alert"><?=pr_text($patient['medical_alerts'])?></div><?php endif;?><?php foreach($alerts as $alert):?><div class="alert"><strong><?=e((string)$alert['alert_type'])?> · <?=e(pr_status((string)$alert['severity']))?></strong><br><?=pr_text($alert['description'])?><br><small>Recorded <?=pr_date((string)$alert['created_at'],true)?><?=!empty($alert['creator'])?' by '.e((string)$alert['creator']):''?></small></div><?php endforeach;?></section><?php endif;

    if(in_array($doc,['summary','complete'],true)):?><section class="section"><h2>Patient Information</h2><div class="grid"><div class="field"><strong>Full Name</strong><?=e(patient_full_name($patient))?></div><div class="field"><strong>Status</strong><?=e(pr_status((string)$patient['status']))?></div><div class="field"><strong>Sex</strong><?=e((string)($patient['sex']?:'—'))?></div><div class="field"><strong>Birth Date</strong><?=pr_date((string)$patient['birth_date'])?></div><div class="field"><strong>Mobile</strong><?=e((string)($patient['mobile']?:'—'))?></div><div class="field"><strong>Email</strong><?=e((string)($patient['email']?:'—'))?></div><div class="field"><strong>Emergency Contact</strong><?=e((string)($patient['emergency_contact']?:'—'))?></div><div class="field"><strong>Occupation</strong><?=e((string)($patient['occupation']?:'—'))?></div><div class="field"><strong>Address</strong><?=pr_text($patient['address'])?></div></div></section><?php endif;

    if($doc==='complete'&&$clinicalPrint){
        $summaryEncounter=$scopeEncounter ?: pr_fetch($pdo,'SELECT * FROM `' . table('clinical_encounters') . '` WHERE patient_id=? ORDER BY FIELD(status,"draft","pending_review","addendum","finalized"),COALESCE(updated_at,created_at) DESC,id DESC LIMIT 1',[$id]);
        $summaryProcedureArgs=[$id];$summaryProcedureSql='SELECT pr.*,du.name dentist_name,au.name assistant_name FROM `' . table('procedures') . '` pr LEFT JOIN `' . table('users') . '` du ON du.id=pr.dentist_user_id LEFT JOIN `' . table('users') . '` au ON au.id=pr.assistant_user_id WHERE pr.patient_id=?';$summaryProcedureSql.=pr_scope_clause('COALESCE(pr.ended_at,pr.started_at,pr.created_at)','pr.encounter_id',$summaryProcedureArgs,$scopeFrom,$scopeTo,$scopeEncounterId);$summaryProcedureSql.=' ORDER BY COALESCE(pr.ended_at,pr.started_at,pr.created_at) DESC,pr.id DESC LIMIT 1';$summaryProcedure=pr_fetch($pdo,$summaryProcedureSql,$summaryProcedureArgs);
        $summaryPlanArgs=[$id];$summaryPlanSql='SELECT tp.*,u.name dentist_name FROM `' . table('treatment_plans') . '` tp LEFT JOIN `' . table('users') . '` u ON u.id=tp.dentist_user_id WHERE tp.patient_id=?';$summaryPlanSql.=pr_scope_clause('COALESCE(tp.updated_at,tp.created_at)','tp.encounter_id',$summaryPlanArgs,$scopeFrom,$scopeTo,$scopeEncounterId);$summaryPlanSql.=' ORDER BY FIELD(tp.status,"in_progress","accepted","scheduled","presented","draft","completed"),COALESCE(tp.updated_at,tp.created_at) DESC,tp.id DESC LIMIT 1';$summaryPlan=pr_fetch($pdo,$summaryPlanSql,$summaryPlanArgs);
        $summaryFollowArgs=[$id];$summaryFollowSql='SELECT f.*,u.name dentist_name FROM `' . table('follow_ups') . '` f LEFT JOIN `' . table('users') . '` u ON u.id=f.dentist_user_id WHERE f.patient_id=? AND f.status IN ("pending","scheduled")';$summaryFollowSql.=pr_scope_clause('COALESCE(f.scheduled_at,f.created_at)','f.encounter_id',$summaryFollowArgs,$scopeFrom,$scopeTo,$scopeEncounterId);$summaryFollowSql.=' ORDER BY f.recommended_date,f.id LIMIT 1';$summaryFollow=pr_fetch($pdo,$summaryFollowSql,$summaryFollowArgs);
        ?><section class="section"><h2>Clinical Record Summary</h2><div class="grid"><div class="field"><strong>Responsible Dentist</strong><?=e((string)($summaryEncounter['dentist_name']??$summaryProcedure['dentist_name']??'Not assigned'))?></div><div class="field"><strong>Dental Assistant</strong><?=e((string)($summaryEncounter['assistant_name']??$summaryProcedure['assistant_name']??'Not assigned'))?></div><div class="field"><strong>Latest treatment in scope</strong><?=e((string)($summaryProcedure['procedure_name']??'None recorded'))?><?=!empty($summaryProcedure)?'<br><small>'.pr_date((string)($summaryProcedure['ended_at']?:$summaryProcedure['started_at']?:$summaryProcedure['created_at']),true).'</small>':''?></div><div class="field"><strong>Treatment plan</strong><?=e((string)($summaryPlan['title']??'None recorded'))?><?=!empty($summaryPlan['status'])?'<br><small>'.e(pr_status((string)$summaryPlan['status'])).'</small>':''?></div><div class="field"><strong>Follow-up</strong><?=e((string)($summaryFollow['purpose']??'None pending'))?><?=!empty($summaryFollow['recommended_date'])?'<br><small>'.pr_date((string)$summaryFollow['recommended_date']).'</small>':''?></div><div class="field"><strong>Encounter status</strong><?=e(pr_status((string)($summaryEncounter['status']??'not selected')))?><?=!empty($summaryEncounter['id'])?'<br><small>Encounter #'.e((string)$summaryEncounter['id']).'</small>':''?></div></div></section><?php
    }

    if(in_array($doc,['medical','complete'],true)){
        $medicalVerificationReady=integrity_medical_columns_ready();
        $currentSql='SELECT m.*,u.name creator FROM `' . table('medical_histories') . '` m LEFT JOIN `' . table('users') . '` u ON u.id=m.created_by WHERE m.patient_id=?';
        if($medicalVerificationReady)$currentSql.=' AND m.verification_status="verified"';
        $currentSql.=$medicalVerificationReady?' ORDER BY COALESCE(m.verified_at,m.created_at) DESC,m.id DESC LIMIT 1':' ORDER BY m.created_at DESC,m.id DESC LIMIT 1';
        $latest=pr_fetch($pdo,$currentSql,[$id])??[];
        $histories=[];
        if($doc==='complete'&&$clinicalPrint){
            $historyArgs=[$id];$historySql='SELECT m.*,u.name creator' . ($medicalVerificationReady?',vu.name verifier':',NULL verifier') . ' FROM `' . table('medical_histories') . '` m LEFT JOIN `' . table('users') . '` u ON u.id=m.created_by' . ($medicalVerificationReady?' LEFT JOIN `' . table('users') . '` vu ON vu.id=m.verified_by':'') . ' WHERE m.patient_id=?';$historySql.=pr_scope_clause('m.created_at',null,$historyArgs,$scopeFrom,$scopeTo,0);$historySql.=' ORDER BY m.created_at DESC,m.id DESC LIMIT 50';
            $histories=pr_fetch_all($pdo,$historySql,$historyArgs);
        }
        ?><section class="section"><h2>Current Dental Treatment Safety History</h2><div class="grid"><div class="field"><strong>Allergies</strong><?=pr_text($latest['allergies']??'')?></div><div class="field"><strong>Current medicines relevant to dental care</strong><?=pr_text($latest['medications']??'')?></div><div class="field"><strong>Health conditions relevant to dental care</strong><?=pr_text($latest['conditions']??'')?></div><div class="field"><strong>Dental History</strong><?=pr_text($latest['dental_history']??'')?></div></div><p class="muted"><?= $medicalVerificationReady?'Latest verified version':'Latest recorded version' ?>: <?=!empty($latest['created_at'])?pr_date((string)($latest['verified_at']??$latest['created_at']),true):($medicalVerificationReady?'No dentist-verified history recorded':'No structured history version recorded')?><?=!empty($latest['verifier'])?' · Verified by '.e((string)$latest['verifier']):(!empty($latest['creator'])?' · '.e((string)$latest['creator']):'')?></p></section><?php
        if($doc==='complete'&&count($histories)>0):?><section class="section"><h2>Dental Safety History Versions</h2><table><thead><tr><th>Date</th><?php if($medicalVerificationReady):?><th>Status</th><th>Source</th><?php endif;?><th>Allergies</th><th>Medications</th><th>Conditions</th><th>Dental History</th></tr></thead><tbody><?php foreach($histories as $history):?><tr><td><?=pr_date((string)$history['created_at'],true)?></td><?php if($medicalVerificationReady):?><td><?=e(pr_status((string)($history['verification_status']??'pending_review')))?><?php if(!empty($history['verifier'])):?><br><small><?=e((string)$history['verifier'])?></small><?php endif;?></td><td><?=e(pr_status((string)($history['source_type']??'legacy')))?></td><?php endif;?><td><?=pr_text($history['allergies'])?></td><td><?=pr_text($history['medications'])?></td><td><?=pr_text($history['conditions'])?></td><td><?=pr_text($history['dental_history'])?></td></tr><?php endforeach;?></tbody></table></section><?php endif;
        $vitalArgs=[$id];$vitalSql='SELECT v.*,u.name recorder FROM `' . table('vital_signs') . '` v LEFT JOIN `' . table('users') . '` u ON u.id=v.recorded_by WHERE v.patient_id=?';$vitalSql.=pr_scope_clause('v.recorded_at','v.encounter_id',$vitalArgs,$scopeFrom,$scopeTo,$scopeEncounterId);$vitalSql.=' ORDER BY v.recorded_at DESC,v.id DESC LIMIT 100';$vitals=pr_fetch_all($pdo,$vitalSql,$vitalArgs);
        ?><section class="section"><h2>Vital Signs</h2><?php if($vitals):?><table><thead><tr><th>Date</th><th>Blood pressure</th><th>Pulse / SpO₂</th><th>Temperature / respiration</th><th>Weight / height / BMI</th><th>Pain / glucose</th><th>Measurement context</th><th>Pregnancy</th></tr></thead><tbody><?php foreach($vitals as $v):[$printBpSys,$printBpDia,$printBpRepeat]=clinical_vitals_effective_bp($v);?><tr><td><?=pr_date((string)$v['recorded_at'],true)?></td><td><?=$printBpSys!==null?e((string)$printBpSys).'/'.e((string)$printBpDia).' mmHg':'—'?><?=$printBpRepeat?'<br><small>Repeat reading</small>':''?></td><td><?=e((string)($v['pulse_rate']??'—'))?> bpm<br><?=e((string)($v['oxygen_saturation']??'—'))?>% SpO₂</td><td><?=e((string)($v['temperature_c']??'—'))?> °C<br><?=e((string)($v['respiratory_rate']??'—'))?>/min</td><td><?=e((string)($v['weight_kg']??'—'))?> kg<br><?=e((string)($v['height_cm']??'—'))?> cm · BMI <?=e((string)($v['bmi']??'—'))?></td><td><?=isset($v['pain_score'])&&$v['pain_score']!==null?e((string)$v['pain_score']).'/10':'—'?><br><?=e((string)($v['blood_glucose']??'—'))?> mg/dL</td><td><?=e(pr_status((string)($v['bp_position']??'not recorded')))?><?=!empty($v['bp_arm'])?' · '.e(ucfirst((string)$v['bp_arm'])).' arm':''?><?=!empty($v['bp_cuff_size'])?'<br>Cuff: '.e((string)$v['bp_cuff_size']):''?><?=!empty($v['measurement_notes'])?'<br>'.pr_text((string)$v['measurement_notes']):''?></td><td><?=e((string)($v['pregnancy_status']??'—'))?></td></tr><?php endforeach;?></tbody></table><?php else:?><p>No vital signs recorded.</p><?php endif;?></section><?php
        if(schema_table_exists(table('inhouse_checkup_results'))){$checkupArgs=[$id];$checkupSql='SELECT c.*,u.name provider_name,rd.name referral_dentist_name FROM `' . table('inhouse_checkup_results') . '` c LEFT JOIN `' . table('users') . '` u ON u.id=c.provider_user_id LEFT JOIN `' . table('users') . '` rd ON rd.id=c.referral_dentist_user_id WHERE c.patient_id=?';$checkupSql.=pr_scope_clause('c.started_at',null,$checkupArgs,$scopeFrom,$scopeTo,0);if($scopeEncounterId>0){if($scopeAppointmentId>0){$checkupSql.=' AND c.appointment_id=?';$checkupArgs[]=$scopeAppointmentId;}else{$checkupSql.=' AND 1=0';}}$checkupSql.=' ORDER BY c.started_at DESC,c.id DESC';$checkups=pr_fetch_all($pdo,$checkupSql,$checkupArgs);?><section class="section"><h2>In-house Checkups</h2><?php if($checkups):?><table><thead><tr><th>Date</th><th>Service</th><th>Provider</th><th>Measurements</th><th>Findings / Notes</th><th>Outcome</th></tr></thead><tbody><?php foreach($checkups as $c):$m=array_filter([($c['blood_pressure_systolic']!==null&&$c['blood_pressure_diastolic']!==null)?$c['blood_pressure_systolic'].'/'.$c['blood_pressure_diastolic'].' mmHg':null,$c['pulse_rate']!==null?$c['pulse_rate'].' bpm':null,$c['temperature_c']!==null?$c['temperature_c'].' °C':null,$c['oxygen_saturation']!==null?$c['oxygen_saturation'].'% SpO2':null,$c['weight_kg']!==null?$c['weight_kg'].' kg':null,$c['bmi']!==null?'BMI '.$c['bmi']:null,$c['blood_glucose_mg_dl']!==null?$c['blood_glucose_mg_dl'].' mg/dL':null]);?><tr><td><?=pr_date((string)$c['started_at'],true)?></td><td><?=e((string)$c['service_name'])?><?=!empty($c['abnormal_flag'])?'<br><strong>Flagged finding</strong>':''?></td><td><?=e((string)($c['provider_name']?:'Clinic staff'))?></td><td><?=e($m?implode(' · ',$m):'—')?></td><td><?=pr_text($c['findings']?:$c['notes'])?></td><td><?=e(pr_status((string)$c['status']))?><?php if(!empty($c['referral_dentist_name'])):?><br><small>Referred to <?=e((string)$c['referral_dentist_name'])?></small><?php endif;?></td></tr><?php endforeach;?></tbody></table><?php else:?><p>No in-house checkups recorded.</p><?php endif;?></section><?php }
    }

    if($clinicalPrint&&in_array($doc,['medical','complete'],true)){
        $latestRxArgs=[$id];$latestRxSql='SELECT rx.*,u.name dentist_name,dp.license_number FROM `' . table('prescriptions') . '` rx LEFT JOIN `' . table('users') . '` u ON u.id=rx.dentist_user_id LEFT JOIN `' . table('dentist_profiles') . '` dp ON dp.user_id=rx.dentist_user_id WHERE rx.patient_id=? AND rx.status="issued"';$latestRxSql.=pr_scope_clause('COALESCE(rx.issued_at,rx.created_at)','rx.encounter_id',$latestRxArgs,$scopeFrom,$scopeTo,$scopeEncounterId);$latestRxSql.=' ORDER BY rx.issued_at DESC,rx.id DESC LIMIT 1';$latestRx=pr_fetch($pdo,$latestRxSql,$latestRxArgs);
        ?><section class="section"><h2>Latest Prescription</h2><?php if($latestRx): pr_render_prescription($pdo,$latestRx,true); else:?><p>No issued prescription recorded.</p><?php endif;?></section><?php
    }

    if(in_array($doc,['summary','complete'],true)){
        $appointmentArgs=[$id];$appointmentSql='SELECT * FROM `' . table('appointments') . '` WHERE patient_id=?';$appointmentSql.=pr_scope_clause('start_at',null,$appointmentArgs,$scopeFrom,$scopeTo,0);if($scopeEncounterId>0){if($scopeAppointmentId>0){$appointmentSql.=' AND id=?';$appointmentArgs[]=$scopeAppointmentId;}else{$appointmentSql.=' AND 1=0';}}$appointmentSql.=' ORDER BY start_at DESC LIMIT 100';$appointments=pr_fetch_all($pdo,$appointmentSql,$appointmentArgs);
        ?><section class="section"><h2>Appointments</h2><?php if($appointments):?><table><thead><tr><th>Date</th><th>Service</th><th>Provider</th><th>Chair</th><th>Status</th></tr></thead><tbody><?php foreach($appointments as $appointment):?><tr><td><?=pr_date((string)$appointment['start_at'],true)?></td><td><?=e((string)($appointment['service_name']?:'Dental visit'))?></td><td><?=e((string)($appointment['dentist_name']?:$appointment['inhouse_provider_name']??'—'))?></td><td><?=e((string)($appointment['chair_name']?:'—'))?></td><td><?=e(pr_status((string)$appointment['status']))?></td></tr><?php endforeach;?></tbody></table><?php else:?><p>No appointments recorded.</p><?php endif;?></section><?php
    }

    if($doc==='complete'&&$clinicalPrint){
        $encounterArgs=[$id];$encounterSql='SELECT ce.*,ca.extraoral_findings,ca.intraoral_findings,ca.soft_tissue_findings,ca.tmj_findings,ca.occlusion_findings,ca.oral_hygiene_status,ca.radiographic_findings,ca.risk_assessment,ca.prognosis FROM `' . table('clinical_encounters') . '` ce LEFT JOIN `' . table('clinical_assessments') . '` ca ON ca.encounter_id=ce.id WHERE ce.patient_id=?';$encounterSql.=pr_scope_clause('ce.created_at','ce.id',$encounterArgs,$scopeFrom,$scopeTo,$scopeEncounterId);$encounterSql.=' ORDER BY ce.created_at DESC,ce.id DESC LIMIT 100';$encounters=pr_fetch_all($pdo,$encounterSql,$encounterArgs);
        ?><section class="section"><h2>Clinical Encounters</h2><?php if($encounters):foreach($encounters as $encounter):?><article class="encounter-card"><div class="record-head"><div><strong><?=pr_date((string)$encounter['created_at'],true)?> · <?=e((string)($encounter['dentist_name']?:'Dentist'))?></strong><small>Encounter #<?=(int)$encounter['id']?> · <?=e(pr_status((string)$encounter['status']))?></small></div></div><div class="grid"><div class="field"><strong>Chief Complaint</strong><?=pr_text($encounter['chief_complaint'])?></div><div class="field"><strong>History of Present Condition</strong><?=pr_text($encounter['history_present_condition'])?></div><div class="field"><strong>Examination</strong><?=pr_text($encounter['examination'])?></div><div class="field"><strong>Diagnosis Summary</strong><?=pr_text($encounter['diagnosis'])?></div><div class="field"><strong>Treatment Plan</strong><?=pr_text($encounter['treatment_plan'])?></div><div class="field"><strong>Procedure Performed</strong><?=pr_text($encounter['procedure_done'])?></div><div class="field"><strong>SOAP Note</strong><?=pr_text($encounter['soap_note'])?></div><div class="field"><strong>Follow-Up</strong><?=pr_date((string)$encounter['follow_up_date'])?> · <?=e((string)($encounter['follow_up_purpose']?:'—'))?></div></div><?php if(array_filter([$encounter['extraoral_findings'],$encounter['intraoral_findings'],$encounter['soft_tissue_findings'],$encounter['tmj_findings'],$encounter['occlusion_findings'],$encounter['radiographic_findings'],$encounter['risk_assessment'],$encounter['prognosis']])):?><h3>Assessment</h3><div class="grid"><div class="field"><strong>Extraoral</strong><?=pr_text($encounter['extraoral_findings'])?></div><div class="field"><strong>Intraoral</strong><?=pr_text($encounter['intraoral_findings'])?></div><div class="field"><strong>Soft Tissue</strong><?=pr_text($encounter['soft_tissue_findings'])?></div><div class="field"><strong>TMJ / Occlusion</strong><?=pr_text(trim((string)$encounter['tmj_findings'].' '.(string)$encounter['occlusion_findings']))?></div><div class="field"><strong>Radiographic Findings</strong><?=pr_text($encounter['radiographic_findings'])?></div><div class="field"><strong>Risk / Prognosis</strong><?=pr_text(trim((string)$encounter['risk_assessment'].' '.(string)$encounter['prognosis']))?></div></div><?php endif;?></article><?php endforeach;else:?><p>No clinical encounters recorded.</p><?php endif;?></section><?php

        $diagnosisArgs=[$id];$diagnosisSql='SELECT d.*,ce.created_at encounter_date,u.name dentist_name FROM `' . table('diagnoses') . '` d LEFT JOIN `' . table('clinical_encounters') . '` ce ON ce.id=d.encounter_id LEFT JOIN `' . table('users') . '` u ON u.id=d.diagnosed_by WHERE d.patient_id=?';$diagnosisSql.=pr_scope_clause('d.diagnosed_at','d.encounter_id',$diagnosisArgs,$scopeFrom,$scopeTo,$scopeEncounterId);$diagnosisSql.=' ORDER BY d.diagnosed_at DESC,d.id DESC';$diagnoses=pr_fetch_all($pdo,$diagnosisSql,$diagnosisArgs);
        ?><section class="section"><h2>Diagnoses</h2><?php if($diagnoses):?><table><thead><tr><th>Date</th><th>Tooth / Region</th><th>Diagnosis</th><th>Severity</th><th>Status</th><th>Dentist</th></tr></thead><tbody><?php foreach($diagnoses as $diagnosis):?><tr><td><?=pr_date((string)$diagnosis['diagnosed_at'],true)?></td><td><?=e(pr_tooth_region($diagnosis['tooth_region']))?></td><td><strong><?=e((string)$diagnosis['diagnosis_name'])?></strong><?=!empty($diagnosis['diagnosis_code'])?'<br><small>'.e((string)$diagnosis['diagnosis_code']).'</small>':''?><?=!empty($diagnosis['notes'])?'<br>'.pr_text($diagnosis['notes']):''?></td><td><?=e(pr_status((string)$diagnosis['severity']))?></td><td><?=e(pr_status((string)$diagnosis['diagnosis_status']))?></td><td><?=e((string)($diagnosis['dentist_name']?:'—'))?></td></tr><?php endforeach;?></tbody></table><?php else:?><p>No structured diagnoses recorded.</p><?php endif;?></section><?php

        if(schema_table_exists(table('odontogram_entries'))){
            $chartSql=schema_table_exists(table('dental_condition_catalog'))?'SELECT o.*,c.name condition_name,u.name recorder FROM `' . table('odontogram_entries') . '` o LEFT JOIN `' . table('dental_condition_catalog') . '` c ON c.code=o.condition_code LEFT JOIN `' . table('users') . '` u ON u.id=o.recorded_by WHERE o.patient_id=? ORDER BY o.recorded_at DESC,o.id DESC':'SELECT o.*,NULL condition_name,u.name recorder FROM `' . table('odontogram_entries') . '` o LEFT JOIN `' . table('users') . '` u ON u.id=o.recorded_by WHERE o.patient_id=? ORDER BY o.recorded_at DESC,o.id DESC';
            $findings=pr_scope_rows(pr_fetch_all($pdo,$chartSql,[$id]),['recorded_at'],'encounter_id',$scopeFrom,$scopeTo,$scopeEncounterId);
            ?><section class="section"><h2>Odontogram and Tooth Findings</h2><?php if($findings):?><table><thead><tr><th>Date</th><th>Dentition</th><th>FDI Tooth</th><th>Surface</th><th>Finding</th><th>Severity / Layer</th><th>Status</th></tr></thead><tbody><?php foreach($findings as $finding):?><tr><td><?=pr_date((string)$finding['recorded_at'],true)?></td><td><?=e(pr_status((string)$finding['dentition']))?></td><td><?=e(dental_tooth_display_label((string)$finding['tooth_number']))?></td><td><?=e((string)($finding['surface']?:'Whole'))?></td><td><strong><?=e((string)($finding['condition_name']?:pr_status((string)$finding['condition_code'])))?></strong><?=!empty($finding['notes'])?'<br>'.pr_text($finding['notes']):''?></td><td><?=e(pr_status((string)($finding['severity']??'')))?> · <?=e(pr_status((string)$finding['chart_layer']))?></td><td><?=e(pr_status((string)$finding['status']))?></td></tr><?php endforeach;?></tbody></table><?php else:?><p>No tooth findings recorded.</p><?php endif;?></section><?php
        }

        $procedures=pr_scope_rows(pr_fetch_all($pdo,encounter_assistant_schema_ready()?'SELECT pr.*,du.name dentist_name,au.name assistant_name,eu.name entered_by_name,vu.name verified_by_name FROM `' . table('procedures') . '` pr LEFT JOIN `' . table('users') . '` du ON du.id=pr.dentist_user_id LEFT JOIN `' . table('users') . '` au ON au.id=pr.assistant_user_id LEFT JOIN `' . table('users') . '` eu ON eu.id=pr.entered_by_user_id LEFT JOIN `' . table('users') . '` vu ON vu.id=pr.verified_by_user_id WHERE pr.patient_id=? ORDER BY COALESCE(pr.ended_at,pr.started_at,pr.created_at) DESC,pr.id DESC':'SELECT pr.*,u.name dentist_name FROM `' . table('procedures') . '` pr LEFT JOIN `' . table('users') . '` u ON u.id=pr.dentist_user_id WHERE pr.patient_id=? ORDER BY COALESCE(pr.ended_at,pr.started_at,pr.created_at) DESC,pr.id DESC',[$id]),['ended_at','started_at','created_at'],'encounter_id',$scopeFrom,$scopeTo,$scopeEncounterId);
        ?><section class="section"><h2>Procedures Performed</h2><?php if($procedures):?><table><thead><tr><th>Date</th><th>Procedure</th><th>Tooth / Region</th><th>Care team and entry</th><th>Outcome</th><th>Status</th></tr></thead><tbody><?php foreach($procedures as $procedure): $entryName=(string)(($procedure['entered_by_name']??'') ?: ($procedure['assistant_name']??$procedure['dentist_name']??'—')); ?><tr><td><?=pr_date((string)($procedure['ended_at']?:$procedure['started_at']?:$procedure['created_at']),true)?></td><td><strong><?=e((string)$procedure['procedure_name'])?></strong><?=!empty($procedure['materials'])?'<br><small>Materials: '.e((string)$procedure['materials']).'</small>':''?></td><td><?=e(pr_tooth_region($procedure['tooth_region']))?></td><td><strong>Dentist:</strong> <?=e((string)($procedure['dentist_name']?:'—'))?><?php if(!empty($procedure['assistant_name'])):?><br><strong>Assistant:</strong> <?=e((string)$procedure['assistant_name'])?><?php endif;?><br><strong>Entered by:</strong> <?=e($entryName)?><?php if(!empty($procedure['entered_by_role'])):?><br><small><?=e(pr_status((string)$procedure['entered_by_role']))?></small><?php endif;?><?php if(!empty($procedure['verified_by_name'])):?><br><strong>Verified by:</strong> <?=e((string)$procedure['verified_by_name'])?><?=!empty($procedure['verified_at'])?' · '.pr_date((string)$procedure['verified_at'],true):''?><?php elseif(($procedure['entered_by_role']??'')==='dental_assistant'):?><br><small>Awaiting Dentist verification</small><?php endif;?></td><td><?=pr_text($procedure['outcome'])?><?php if(!empty($procedure['complications'])):?><br><strong>Complications:</strong> <?=pr_text($procedure['complications'])?><?php endif;?></td><td><?=e(pr_status((string)$procedure['status']))?></td></tr><?php endforeach;?></tbody></table><?php else:?><p>No procedures recorded.</p><?php endif;?></section><?php

        if(schema_table_exists(table('instrument_usage'))){
            $instrumentUses=pr_scope_rows(pr_fetch_all($pdo,'SELECT iu.*,s.set_code,s.name set_name,b.cycle_no,b.load_no,b.sterilizer_name,b.released_at,b.batch_hash,pr.procedure_name,a.name assigned_by_name,r.name returned_by_name FROM `' . table('instrument_usage') . '` iu JOIN `' . table('instrument_sets') . '` s ON s.id=iu.instrument_set_id JOIN `' . table('sterilization_batches') . '` b ON b.id=iu.batch_id LEFT JOIN `' . table('procedures') . '` pr ON pr.id=iu.procedure_id LEFT JOIN `' . table('users') . '` a ON a.id=iu.assigned_by LEFT JOIN `' . table('users') . '` r ON r.id=iu.returned_by WHERE iu.patient_id=? ORDER BY iu.assigned_at DESC,iu.id DESC',[$id]),['assigned_at'],'encounter_id',$scopeFrom,$scopeTo,$scopeEncounterId);
            ?><section class="section"><h2>Sterile Instrument Traceability</h2><?php if($instrumentUses):?><table><thead><tr><th>Patient use</th><th>Instrument set</th><th>Procedure / Encounter</th><th>Sterilization cycle</th><th>Release evidence</th><th>Return to decontamination</th></tr></thead><tbody><?php foreach($instrumentUses as $use):?><tr><td><?=pr_date((string)$use['assigned_at'],true)?><br><small><?=e((string)($use['assigned_by_name']?:'—'))?></small></td><td><strong><?=e((string)$use['set_code'])?></strong><br><?=e((string)$use['set_name'])?></td><td><?=e((string)($use['procedure_name']?:($use['encounter_id']?'Encounter #'.$use['encounter_id']:'General/appointment use')))?><?php if(!empty($use['notes'])):?><br><small><?=pr_text($use['notes'])?></small><?php endif;?></td><td><?=e((string)$use['sterilizer_name'])?><br>Cycle <?=e((string)$use['cycle_no'])?> · Load <?=e((string)$use['load_no'])?><br><small>Released <?=pr_date((string)$use['released_at'],true)?></small></td><td><?=e(!empty($use['batch_hash'])?substr((string)$use['batch_hash'],0,24).'…':'Missing release hash')?></td><td><?=!empty($use['returned_at'])?pr_date((string)$use['returned_at'],true).'<br><small>'.e((string)($use['returned_by_name']?:'—')).'</small>':'Open / not returned'?></td></tr><?php endforeach;?></tbody></table><?php else:?><p>No instrument-use records are linked to this patient.</p><?php endif;?></section><?php
        }

        $plans=pr_scope_rows(pr_fetch_all($pdo,'SELECT tp.*,u.name dentist_name FROM `' . table('treatment_plans') . '` tp LEFT JOIN `' . table('users') . '` u ON u.id=tp.dentist_user_id WHERE tp.patient_id=? ORDER BY tp.created_at DESC,tp.id DESC',[$id]),['updated_at','created_at'],'encounter_id',$scopeFrom,$scopeTo,$scopeEncounterId);
        ?><section class="section"><h2>Treatment Plans</h2><?php if($plans):foreach($plans as $plan):$items=pr_fetch_all($pdo,'SELECT * FROM `' . table('treatment_plan_items') . '` WHERE treatment_plan_id=? ORDER BY sequence_no,id',[(int)$plan['id']]);?><article class="plan-card"><div class="record-head"><div><strong><?=e((string)$plan['title'])?></strong><small><?=pr_date((string)$plan['created_at'])?> · <?=e((string)($plan['dentist_name']?:'Dentist'))?></small></div><span><?=e(pr_status((string)$plan['status']))?></span></div><?php if($items):?><table><thead><tr><th>#</th><th>Tooth / Region</th><th>Diagnosis</th><th>Procedure</th><th>Priority</th><th>Sessions</th><th>Estimate</th><th>Status</th></tr></thead><tbody><?php foreach($items as $item):?><tr><td><?=e((string)$item['sequence_no'])?></td><td><?=e(pr_tooth_region($item['tooth_region']))?></td><td><?=e((string)($item['diagnosis']?:'—'))?></td><td><?=e((string)$item['procedure_name'])?></td><td><?=e(pr_status((string)$item['priority']))?></td><td><?=e((string)$item['sessions'])?></td><td><?=pr_money($item['estimated_fee'])?></td><td><?=e(pr_status((string)$item['status']))?></td></tr><?php endforeach;?></tbody></table><?php endif;?><?php if(!empty($plan['notes'])):?><p><strong>Notes:</strong> <?=pr_text($plan['notes'])?></p><?php endif;?></article><?php endforeach;else:?><p>No treatment plans recorded.</p><?php endif;?></section><?php

        $prescriptions=pr_scope_rows(pr_fetch_all($pdo,'SELECT rx.*,u.name dentist_name,dp.license_number FROM `' . table('prescriptions') . '` rx LEFT JOIN `' . table('users') . '` u ON u.id=rx.dentist_user_id LEFT JOIN `' . table('dentist_profiles') . '` dp ON dp.user_id=rx.dentist_user_id WHERE rx.patient_id=? ORDER BY rx.issued_at DESC,rx.id DESC',[$id]),['issued_at','created_at'],'encounter_id',$scopeFrom,$scopeTo,$scopeEncounterId);
        ?><section class="section"><h2>Prescription History</h2><?php if($prescriptions):foreach($prescriptions as $rx)pr_render_prescription($pdo,$rx,false);else:?><p>No prescriptions recorded.</p><?php endif;?></section><?php

        $documents=pr_scope_rows(pr_fetch_all($pdo,'SELECT d.*,u.name uploader FROM `' . table('documents') . '` d LEFT JOIN `' . table('users') . '` u ON u.id=d.uploaded_by WHERE d.patient_id=? ORDER BY d.created_at DESC,d.id DESC LIMIT 100',[$id]),['created_at'],'encounter_id',$scopeFrom,$scopeTo,$scopeEncounterId);
        ?><section class="section"><h2>X-rays, Clinical Images, and Attachments</h2><?php if($documents):?><div class="image-grid"><?php foreach($documents as $document):$isImage=str_starts_with((string)$document['mime_type'],'image/');?><article class="image-card"><?php if($isImage):?><img src="download_document.php?id=<?=(int)$document['id']?>&amp;preview=1" alt="<?=e((string)$document['category'])?>"><?php endif;?><strong><?=e((string)$document['category'])?></strong><small><?=e(pr_tooth_region($document['tooth_region']))?> · <?=pr_date((string)$document['created_at'],true)?></small><small><?=e((string)$document['file_name'])?> · <?=e((string)($document['uploader']?:'Clinical team'))?></small><?php if(!empty($document['description'])):?><p><?=pr_text($document['description'])?></p><?php endif;?></article><?php endforeach;?></div><?php else:?><p>No X-rays or clinical attachments recorded.</p><?php endif;?></section><?php

        $referrals=pr_scope_rows(pr_fetch_all($pdo,'SELECT r.*,u.name dentist_name FROM `' . table('referrals') . '` r LEFT JOIN `' . table('users') . '` u ON u.id=r.referring_dentist_id WHERE r.patient_id=? ORDER BY r.created_at DESC',[$id]),['created_at'],'encounter_id',$scopeFrom,$scopeTo,$scopeEncounterId);
        ?><section class="section"><h2>Referrals</h2><?php if($referrals):?><table><thead><tr><th>Date</th><th>Provider</th><th>Reason</th><th>Urgency</th><th>Status</th><th>Outcome</th></tr></thead><tbody><?php foreach($referrals as $referral):?><tr><td><?=pr_date((string)$referral['created_at'])?></td><td><?=e((string)$referral['provider_name'])?><?=!empty($referral['provider_type'])?'<br><small>'.e((string)$referral['provider_type']).'</small>':''?></td><td><?=pr_text($referral['reason'])?></td><td><?=e(pr_status((string)$referral['urgency']))?></td><td><?=e(pr_status((string)$referral['status']))?></td><td><?=pr_text($referral['outcome'])?></td></tr><?php endforeach;?></tbody></table><?php else:?><p>No referrals recorded.</p><?php endif;?></section><?php

        $labs=pr_scope_rows(pr_fetch_all($pdo,'SELECT lc.*,tp.encounter_id FROM `' . table('laboratory_cases') . '` lc LEFT JOIN `' . table('treatment_plans') . '` tp ON tp.id=lc.treatment_plan_id WHERE lc.patient_id=? ORDER BY lc.created_at DESC,lc.id DESC',[$id]),['created_at'],'encounter_id',$scopeFrom,$scopeTo,$scopeEncounterId);
        ?><section class="section"><h2>Laboratory Cases</h2><?php if($labs):?><table><thead><tr><th>Date</th><th>Laboratory</th><th>Case</th><th>Tooth / Arch</th><th>Material / Shade</th><th>Due</th><th>Status</th></tr></thead><tbody><?php foreach($labs as $lab):?><tr><td><?=pr_date((string)$lab['created_at'])?></td><td><?=e((string)$lab['laboratory_name'])?></td><td><?=e((string)$lab['case_type'])?></td><td><?=e((string)($lab['tooth_arch']?:'—'))?></td><td><?=e(trim((string)($lab['material']??'').' / '.(string)($lab['shade']??''),' /')?:'—')?></td><td><?=pr_date((string)$lab['due_date'])?></td><td><?=e(pr_status((string)$lab['status']))?></td></tr><?php endforeach;?></tbody></table><?php else:?><p>No laboratory cases recorded.</p><?php endif;?></section><?php

        $followups=pr_scope_rows(pr_fetch_all($pdo,'SELECT f.*,u.name dentist_name FROM `' . table('follow_ups') . '` f LEFT JOIN `' . table('users') . '` u ON u.id=f.dentist_user_id WHERE f.patient_id=? ORDER BY f.recommended_date DESC,f.id DESC',[$id]),['scheduled_at','created_at','recommended_date'],'encounter_id',$scopeFrom,$scopeTo,$scopeEncounterId);
        $recalls=pr_scope_rows(pr_fetch_all($pdo,'SELECT * FROM `' . table('recalls') . '` WHERE patient_id=? ORDER BY due_date DESC,id DESC',[$id]),['created_at','due_date'],null,$scopeFrom,$scopeTo,0);if($scopeEncounterId>0)$recalls=[];
        ?><section class="section"><h2>Follow-Ups and Recalls</h2><?php if($followups):?><table><thead><tr><th>Recommended Date</th><th>Purpose</th><th>Urgency</th><th>Status</th><th>Instructions</th></tr></thead><tbody><?php foreach($followups as $follow):?><tr><td><?=pr_date((string)$follow['recommended_date'])?></td><td><?=e((string)$follow['purpose'])?></td><td><?=e(pr_status((string)$follow['urgency']))?></td><td><?=e(pr_status((string)$follow['status']))?></td><td><?=pr_text($follow['instructions'])?></td></tr><?php endforeach;?></tbody></table><?php endif;?><?php if($recalls):?><h3>Recall schedule</h3><table><thead><tr><th>Due Date</th><th>Recall Type</th><th>Status</th><th>Notes</th></tr></thead><tbody><?php foreach($recalls as $recall):?><tr><td><?=pr_date((string)$recall['due_date'])?></td><td><?=e((string)$recall['recall_type'])?></td><td><?=e(pr_status((string)$recall['status']))?></td><td><?=pr_text($recall['notes'])?></td></tr><?php endforeach;?></tbody></table><?php endif;?><?php if(!$followups&&!$recalls):?><p>No follow-up or recall records found.</p><?php endif;?></section><?php
    }

    if($doc==='complete'&&$clinicalPrint){
        $printTimeline=patient_timeline_fetch($pdo,$id,$role,['from'=>$scopeFrom,'to'=>$scopeTo,'encounter_id'=>$scopeEncounterId]);
        ?><section class="section"><h2>Unified Patient Timeline</h2><?php if($printTimeline):?><div class="print-timeline"><?php foreach($printTimeline as $timelineEvent):?><article class="print-timeline-item"><strong><?=e(pr_date((string)$timelineEvent['at'],true).' — '.(string)$timelineEvent['title'])?></strong><?php if(!empty($timelineEvent['summary'])):?><span><?=e((string)$timelineEvent['summary'])?></span><?php endif;?><small class="print-timeline-meta"><?=e(patient_timeline_category_map($role)[$timelineEvent['category']]??pr_status((string)$timelineEvent['category']))?><?php if(!empty($timelineEvent['status'])):?> · <?=e(pr_status((string)$timelineEvent['status']))?><?php endif;?><?php if(!empty($timelineEvent['dentist'])):?> · Dentist: <?=e((string)$timelineEvent['dentist'])?><?php endif;?><?php if(!empty($timelineEvent['assistant'])):?> · Assistant: <?=e((string)$timelineEvent['assistant'])?><?php endif;?><?php if(!empty($timelineEvent['actor'])):?> · Recorded by: <?=e((string)$timelineEvent['actor'])?><?php endif;?><?php if((int)$timelineEvent['encounter_id']>0):?> · Encounter #<?=(int)$timelineEvent['encounter_id']?><?php endif;?></small></article><?php endforeach;?></div><?php else:?><p>No authorized timeline entries match the selected record scope.</p><?php endif;?></section><?php
    }

    if($doc==='ledger'||($doc==='complete'&&$financePrint)){
        $invoices=pr_scope_rows(pr_fetch_all($pdo,'SELECT * FROM `' . table('invoices') . '` WHERE patient_id=? ORDER BY created_at DESC,id DESC',[$id]),['created_at'],'encounter_id',$scopeFrom,$scopeTo,$scopeEncounterId);
        $invoiceIds=array_map(static fn(array $row): int => (int)$row['id'],$invoices);
        $invoiceItemMap=[];$paymentMap=[];$returnMap=[];
        if($invoiceIds){
            $marks=implode(',',array_fill(0,count($invoiceIds),'?'));
            if(schema_table_exists(table('invoice_items'))){
                foreach(pr_fetch_all($pdo,'SELECT * FROM `' . table('invoice_items') . '` WHERE invoice_id IN ('.$marks.') ORDER BY invoice_id,id',$invoiceIds) as $item){
                    $invoiceItemMap[(int)$item['invoice_id']][]=$item;
                }
            }
            if(schema_table_exists(table('payments'))){
                foreach(pr_fetch_all($pdo,'SELECT py.*,u.name receiver FROM `' . table('payments') . '` py LEFT JOIN `' . table('users') . '` u ON u.id=py.received_by WHERE py.invoice_id IN ('.$marks.') ORDER BY py.invoice_id,py.created_at,py.id',$invoiceIds) as $paymentRow){
                    $paymentMap[(int)$paymentRow['invoice_id']][]=$paymentRow;
                }
            }
            if(schema_table_exists(table('payment_adjustments'))){
                foreach(pr_fetch_all($pdo,'SELECT pa.*,rq.name requester,ap.name approver,pr.name processor FROM `' . table('payment_adjustments') . '` pa LEFT JOIN `' . table('users') . '` rq ON rq.id=pa.requested_by LEFT JOIN `' . table('users') . '` ap ON ap.id=pa.approved_by LEFT JOIN `' . table('users') . '` pr ON pr.id=pa.processed_by WHERE pa.invoice_id IN ('.$marks.') ORDER BY pa.invoice_id,COALESCE(pa.processed_at,pa.approved_at,pa.requested_at),pa.id',$invoiceIds) as $returnRow){
                    $returnMap[(int)$returnRow['invoice_id']][]=$returnRow;
                }
            }
        }
        $ledgerChargeTotal=0.0;$ledgerPaidTotal=0.0;$ledgerOpenBalance=0.0;$ledgerReturnedTotal=0.0;
        foreach($invoices as $invoice){
            $ledgerChargeTotal+=(float)$invoice['amount'];
            $ledgerPaidTotal+=(float)$invoice['paid_amount'];
            $ledgerOpenBalance+=max(0,(float)$invoice['amount']-(float)$invoice['paid_amount']);
            foreach(($returnMap[(int)$invoice['id']]??[]) as $returnRow){ if(($returnRow['status']??'')==='processed')$ledgerReturnedTotal+=(float)$returnRow['amount']; }
        }
        ?><section class="section"><h2>Patient Account Statement</h2><div class="grid"><div class="field"><strong>Total charges</strong><?=pr_money($ledgerChargeTotal)?></div><div class="field"><strong>Total paid to date</strong><?=pr_money($ledgerPaidTotal)?></div><div class="field"><strong>Processed refunds / reversals</strong><?=pr_money($ledgerReturnedTotal)?></div><div class="field"><strong>Outstanding balance</strong><?=pr_money($ledgerOpenBalance)?></div></div><p class="muted">This statement is financial only. It does not include diagnosis, clinical notes, prescriptions, or treatment details outside invoice descriptions.</p><?php if($invoices):?><table><thead><tr><th>Invoice</th><th>Date</th><th>Description</th><th>Charge</th><th>Paid</th><th>Balance</th><th>Status</th></tr></thead><tbody><?php foreach($invoices as $invoice):$invoiceId=(int)$invoice['id'];$outstanding=max(0,(float)$invoice['amount']-(float)$invoice['paid_amount']);?><tr><td><strong><?=e((string)$invoice['invoice_no'])?></strong></td><td><?=pr_date((string)$invoice['created_at'])?></td><td><?=e((string)$invoice['description'])?></td><td><?=pr_money($invoice['amount'])?></td><td><?=pr_money($invoice['paid_amount'])?></td><td><?=pr_money($outstanding)?></td><td><?=e(pr_status((string)$invoice['status']))?></td></tr><?php if(!empty($invoiceItemMap[$invoiceId])):?><tr><td></td><td colspan="6"><strong>Charge breakdown</strong><table><thead><tr><th>Service / procedure</th><th>Qty</th><th>Gross</th><th>Discount</th><th>Net</th></tr></thead><tbody><?php foreach($invoiceItemMap[$invoiceId] as $item):?><tr><td><?=e((string)$item['description'])?><?=!empty($item['item_code'])?'<br><small>'.e((string)$item['item_code']).'</small>':''?></td><td><?=e(number_format((float)($item['quantity']??1),2))?></td><td><?=pr_money($item['gross_amount']??$item['unit_price']??0)?></td><td><?=pr_money($item['discount_amount']??0)?></td><td><?=pr_money($item['net_amount']??$item['gross_amount']??0)?></td></tr><?php endforeach;?></tbody></table></td></tr><?php endif;?><?php if(!empty($paymentMap[$invoiceId])||!empty($returnMap[$invoiceId])):?><tr><td></td><td colspan="6"><strong>Payments and returns</strong><table><thead><tr><th>Date</th><th>Type</th><th>Method</th><th>Reference</th><th>Amount</th><th>Status / Staff</th></tr></thead><tbody><?php foreach(($paymentMap[$invoiceId]??[]) as $pay):?><tr><td><?=pr_date((string)$pay['created_at'],true)?></td><td>Payment</td><td><?=e(pr_status((string)$pay['method']))?></td><td><?=e((string)($pay['reference_no']?:'—'))?></td><td><?=pr_money($pay['amount'])?></td><td><?=e(pr_status((string)($pay['status']??'posted')))?><br><small><?=e((string)($pay['receiver']?:'—'))?></small></td></tr><?php endforeach;?><?php foreach(($returnMap[$invoiceId]??[]) as $ret):?><tr><td><?=pr_date((string)($ret['processed_at']??$ret['approved_at']??$ret['requested_at']),true)?></td><td><?=e(pr_status((string)$ret['adjustment_type']))?></td><td><?=e(pr_status((string)$ret['method']))?></td><td><?=e((string)($ret['reference_no']?:'—'))?></td><td>-<?=pr_money($ret['amount'])?></td><td><?=e(pr_status((string)$ret['status']))?><br><small><?=e((string)($ret['processor']?:$ret['approver']?:$ret['requester']?:'—'))?></small></td></tr><?php endforeach;?></tbody></table></td></tr><?php endif;?><?php endforeach;?><tr><td colspan="5" class="total">Outstanding Balance</td><td colspan="2" class="total"><?=pr_money($ledgerOpenBalance)?></td></tr></tbody></table><?php else:?><p>No invoices recorded.</p><?php endif;?></section><?php
    }
    pr_footer();
} elseif ($type === 'queue_ticket') {
    pr_require_role(['super_admin','clinic_admin','receptionist','staff','dentist','dental_assistant','cashier']);
    $stmt=$pdo->prepare('SELECT q.*,p.patient_no,p.first_name,p.middle_name,p.last_name,p.mobile,p.email,p.medical_alerts,a.start_at appointment_start,a.service_name appointment_service,a.status appointment_status,b.name branch_name FROM `' . table('queue_entries') . '` q JOIN `' . table('patients') . '` p ON p.id=q.patient_id LEFT JOIN `' . table('appointments') . '` a ON a.id=q.appointment_id LEFT JOIN `' . table('branches') . '` b ON b.id=q.branch_id WHERE q.id=? LIMIT 1');
    $stmt->execute([$id]);
    $r=$stmt->fetch();
    if(!$r)exit('Queue ticket not found.');
    $patientId=(int)$r['patient_id'];$branchId=(int)$r['branch_id'];
    if(!record_branch_scope_allowed($branchId,$patientId)){http_response_code(403);exit('This queue ticket is outside your authorized branch or assignment scope.');}
    $patientName=trim((string)$r['last_name'].', '.(string)$r['first_name'].(!empty($r['middle_name'])?' '.(string)$r['middle_name']:''));
    $title='Patient Queue Ticket';$reference=(string)$r['queue_no'];
    pr_header($title,$r,$reference);
    pr_log('queue_ticket',(int)$r['id'],$patientId,$branchId,'Operational queue ticket');
    ?><section class="section"><div style="text-align:center;border:2px dashed #9fb3bd;border-radius:18px;padding:22px 12px;margin:6px auto 18px;max-width:420px"><small style="display:block;text-transform:uppercase;letter-spacing:.16em;color:#667085;font-weight:800">Queue ticket</small><strong style="display:block;font-size:64px;line-height:1;margin:8px 0;color:#0f766e"><?=e((string)$r['queue_no'])?></strong><span style="display:block;color:#667085"><?=e($r['source_type']==='appointment'?'Appointment check-in':'Walk-in')?></span></div><div class="grid"><div class="field"><strong>Patient</strong><?=e($patientName)?><br><small><?=e((string)$r['patient_no'])?></small></div><div class="field"><strong>Checked in</strong><?=pr_date((string)$r['checked_in_at'],true)?></div><div class="field"><strong>Service</strong><?=e((string)($r['service_name']?:$r['appointment_service']?:'Dental visit'))?></div><div class="field"><strong>Provider</strong><?=e((($r['provider_type']??'dentist')==='inhouse')?((string)($r['inhouse_provider_name']?:'In-house clinic team')):((string)($r['dentist_name']?:'Dentist unassigned')))?></div><div class="field"><strong>Chair</strong><?=e((string)($r['chair_name']?:'To be called'))?></div><div class="field"><strong>Status</strong><?=e(ucwords(str_replace('_',' ',(string)$r['status'])))?></div></div><p class="print-scope"><strong>Patient instruction</strong>Please wait until this ticket number appears on the patient queue screen or is called by the staff. Appointment patients receive an <b>A-series</b> ticket after check-in; walk-ins receive a <b>W-series</b> ticket.</p></section><?php pr_footer();
} elseif ($type === 'appointment_slip') {
    pr_require_role(['super_admin','clinic_admin','dentist','receptionist','staff','dental_assistant']);
    $stmt=$pdo->prepare('SELECT a.*,p.* ,a.id appointment_id,a.branch_id appointment_branch FROM `' . table('appointments') . '` a JOIN `' . table('patients') . '` p ON p.id=a.patient_id WHERE a.id=?');$stmt->execute([$id]);$r=$stmt->fetch();if(!$r)exit('Appointment not found.');$patientId=(int)$r['patient_id'];$branchId=(int)$r['appointment_branch'];if(!record_branch_scope_allowed($branchId,$patientId)){http_response_code(403);exit('This appointment is outside your authorized branch or assignment scope.');}$title='Dental Appointment Slip';$reference='APT-'.str_pad((string)$id,6,'0',STR_PAD_LEFT);pr_header($title,$r,$reference);?><section class="section"><h2>Appointment Details</h2><div class="grid"><div class="field"><strong>Date and Time</strong><?=pr_date($r['start_at'],true)?></div><div class="field"><strong>Service</strong><?=e($r['service_name'])?></div><div class="field"><strong>Dentist</strong><?=e($r['dentist_name'])?></div><div class="field"><strong>Chair</strong><?=e($r['chair_name']?:'To be assigned')?></div><div class="field"><strong>Status</strong><?=e($r['status'])?></div><div class="field"><strong>Notes</strong><?=pr_text($r['notes'])?></div></div></section><?php pr_footer();
} elseif ($type === 'appointment_schedule') {
    pr_require_role(['super_admin','clinic_admin','dentist','receptionist','staff','dental_assistant']);$title='Daily Appointment Schedule';$reference=$date;pr_header($title,null,$reference);$sql='SELECT a.*,p.patient_no,p.first_name,p.last_name FROM `' . table('appointments') . '` a JOIN `' . table('patients') . '` p ON p.id=a.patient_id WHERE DATE(a.start_at)=?';$params=[$date];if($role==='dentist'){$ids=task_dentist_scope_ids();if($ids){$marks=implode(',',array_fill(0,count($ids),'?'));$sql.=' AND a.dentist_user_id IN ('.$marks.')';$params=array_merge($params,$ids);}else{$sql.=' AND 1=0';}}elseif(!superuser_primary_workspace()){$scheduleBranchId=signed_user_branch_id();if($scheduleBranchId>0){$sql.=' AND a.branch_id=?';$params[]=$scheduleBranchId;}else{$sql.=' AND 1=0';}}$sql.=' ORDER BY a.start_at';$stmt=$pdo->prepare($sql);$stmt->execute($params);?><section class="section"><h2><?=e(pr_date($date))?></h2><table><thead><tr><th>Time</th><th>Patient</th><th>Service</th><th>Dentist</th><th>Chair</th><th>Status</th></tr></thead><tbody><?php foreach($stmt as $r):?><tr><td><?=e(date('g:i A',strtotime($r['start_at'])))?></td><td><?=e($r['last_name'].', '.$r['first_name'])?><br><small><?=e($r['patient_no'])?></small></td><td><?=e($r['service_name'])?></td><td><?=e($r['dentist_name'])?></td><td><?=e($r['chair_name'])?></td><td><?=e($r['status'])?></td></tr><?php endforeach;?></tbody></table></section><?php pr_footer();
} elseif ($type === 'encounter') {
    pr_require_role(['super_admin','clinic_admin','dentist','dental_assistant']);$stmt=$pdo->prepare('SELECT ce.*,p.*,ce.id encounter_id,ce.branch_id encounter_branch FROM `' . table('clinical_encounters') . '` ce JOIN `' . table('patients') . '` p ON p.id=ce.patient_id WHERE ce.id=?');$stmt->execute([$id]);$r=$stmt->fetch();if(!$r)exit('Encounter not found.');$patientId=(int)$r['patient_id'];$branchId=(int)$r['encounter_branch'];if(active_role_is('dental_assistant')&&(int)($r['assistant_user_id']??0)!==(int)(current_user()['id']??0)){http_response_code(403);exit('This encounter is not assigned to your Dental Assistant account.');}if(!record_branch_scope_allowed($branchId,$patientId)){http_response_code(403);exit('This encounter is outside your authorized branch or assignment scope.');}$title='Clinical Encounter Summary';$reference='ENC-'.str_pad((string)$id,6,'0',STR_PAD_LEFT);pr_header($title,$r,$reference);foreach(['Chief Complaint'=>'chief_complaint','Examination'=>'examination','Diagnosis'=>'diagnosis','Treatment Plan'=>'treatment_plan','Procedure Performed'=>'procedure_done','SOAP Note'=>'soap_note','Prescription'=>'prescription'] as $label=>$field):?><section class="section"><h2><?=e($label)?></h2><p><?=pr_text($r[$field])?></p></section><?php endforeach;?><section class="section"><h2>Encounter Status</h2><div class="grid"><div class="field"><strong>Treating Dentist</strong><?=e($r['dentist_name'])?></div><div class="field"><strong>Dental Assistant</strong><?=e((string)(($r['assistant_name']??'')?:'Not assigned'))?></div><div class="field"><strong>Date</strong><?=pr_date($r['created_at'],true)?></div><div class="field"><strong>Status</strong><?=e($r['status'])?></div><div class="field"><strong>Signed record hash</strong><?=e((string)($r['finalized_hash']??'—'))?></div><div class="field"><strong>Follow-Up</strong><?=pr_date($r['follow_up_date'])?></div></div></section><?php
if(function_exists('clinical_record_completion_latest')&&clinical_record_completion_schema_ready($pdo)):
    $completionReview=clinical_record_completion_latest($pdo,$id);
    if($completionReview):
        $missingRows=$completionReview['missing']??[];
?>
<section class="section"><h2>Signed Record Completion Review</h2><div class="grid"><div class="field"><strong>Status</strong><?=e(pr_status((string)$completionReview['review_status']))?></div><div class="field"><strong>Reviewed</strong><?=pr_date((string)$completionReview['reviewed_at'],true)?></div><div class="field"><strong>Missing / needs review</strong><?=e((string)($completionReview['missing_count']??0))?></div><div class="field"><strong>Review hash</strong><?=e((string)($completionReview['review_hash']??'—'))?></div></div><?php if($missingRows):?><table><thead><tr><th>Item</th><th>Message</th></tr></thead><tbody><?php foreach($missingRows as $missing):?><tr><td><?=e((string)($missing['label']??$missing['key']??'Requirement'))?></td><td><?=e((string)($missing['message']??''))?></td></tr><?php endforeach;?></tbody></table><?php else:?><p>This encounter has a complete clinical-record review snapshot.</p><?php endif;?></section>
<?php endif; endif;
$discharge=treatment_completion_schema_ready()?json_decode((string)($r['discharge_summary_json']??''),true):[];
if(!is_array($discharge))$discharge=[];
if($discharge||!empty($r['completion_destination'])):
?>
<section class="section"><h2>Discharge and Handoff Summary</h2>
<div class="grid">
  <div class="field"><strong>Completion destination</strong><?=e(pr_status((string)($r['completion_destination']??'cashier')))?></div>
  <div class="field"><strong>Verified billing handoff</strong><?=pr_money((float)($r['billing_handoff_amount']??0))?></div>
  <div class="field"><strong>Chair released</strong><?=pr_date($r['chair_released_at']??null,true)?></div>
  <div class="field"><strong>Discharged</strong><?=pr_date($r['discharged_at']??null,true)?></div>
</div>
<?php if(!empty($discharge['care_team'])):?><p><strong>Care team:</strong> Treating Dentist — <?=e((string)($discharge['care_team']['dentist']['name']??$r['dentist_name']))?><?php if(!empty($discharge['care_team']['dental_assistant']['name'])):?> · Dental Assistant — <?=e((string)$discharge['care_team']['dental_assistant']['name'])?><?php endif;?></p><?php endif;?>
<?php if(!empty($r['no_payment_reason'])):?><p><strong>Authorized no-payment reason:</strong> <?=pr_text($r['no_payment_reason'])?></p><?php endif;?>
<?php if(!empty($discharge['procedures'])):?><h3>Completed procedures</h3><table><thead><tr><th>Procedure</th><th>Tooth / region</th><th>Clinical details</th><th>Entry attribution</th><th>Approved amount</th></tr></thead><tbody><?php foreach($discharge['procedures'] as $procedure):?><tr><td><?=e((string)($procedure['procedure_name']??''))?></td><td><?=e(pr_tooth_region((string)($procedure['tooth_region']??'')))?></td><td><?php $procedureDetails=[];foreach(['anesthetic'=>'Anesthetic','materials'=>'Materials','complications'=>'Complications','outcome'=>'Outcome'] as $field=>$label){$value=trim((string)($procedure[$field]??''));if($value!=='')$procedureDetails[]='<strong>'.e($label).':</strong> '.pr_text($value);}echo $procedureDetails?implode('<br>',$procedureDetails):'—';?></td><td><strong>Dentist:</strong> <?=e((string)($procedure['responsible_dentist']??$r['dentist_name']))?><br><strong>Entered by:</strong> <?=e((string)($procedure['entered_by']??$procedure['dental_assistant']??$procedure['responsible_dentist']??'—'))?><?php if(!empty($procedure['entered_by_role'])):?><br><small><?=e(pr_status((string)$procedure['entered_by_role']))?></small><?php endif;?><?php if(!empty($procedure['verified_by'])):?><br><strong>Verified by:</strong> <?=e((string)$procedure['verified_by'])?><?=!empty($procedure['verified_at'])?' · '.pr_date($procedure['verified_at'],true):''?><?php endif;?></td><td><?=($procedure['fee_status']??'')==='no_charge'?'Authorized no-charge':pr_money((float)($procedure['approved_fee_snapshot']??0))?></td></tr><?php endforeach;?></tbody></table><?php endif;?>
<?php if(!empty($discharge['medications'])):?><h3>Prescription</h3><table><thead><tr><th>Medicine</th><th>Directions</th><th>Duration / quantity</th><th>Instructions</th></tr></thead><tbody><?php foreach($discharge['medications'] as $medicine):?><tr><td><?=e(trim((string)($medicine['medication_name']??'').' '.(string)($medicine['strength']??'')))?><?=!empty($medicine['generic_name'])?'<br><small>'.e((string)$medicine['generic_name']).'</small>':''?></td><td><?=e(trim((string)($medicine['dosage']??'').' '.(string)($medicine['route']??'').' '.(string)($medicine['frequency']??'')))?></td><td><?=!empty($medicine['duration_days'])?e((string)$medicine['duration_days']).' day(s)':'—'?> · Qty <?=e((string)($medicine['quantity']??'—'))?></td><td><?=pr_text((string)($medicine['instructions']??''))?></td></tr><?php endforeach;?></tbody></table><?php endif;?>
<?php if(!empty($discharge['clinical_usage'])):?><h3>Clinical materials and services</h3><table><thead><tr><th>Item</th><th>Quantity</th><th>Billing</th><th>Note</th></tr></thead><tbody><?php foreach($discharge['clinical_usage'] as $usage):?><tr><td><?=e((string)($usage['description']??''))?><br><small><?=e(pr_status((string)($usage['usage_type']??'')))?></small></td><td><?=e((string)($usage['quantity']??'—'))?> <?=e((string)($usage['unit']??''))?></td><td><?=e(pr_status((string)($usage['billing_mode']??'')))?><?php if(($usage['billing_mode']??'')==='bill_separately'):?><br><small><?=pr_money((float)($usage['quantity']??0)*(float)($usage['unit_price']??0))?></small><?php endif;?></td><td><?=pr_text((string)($usage['notes']??''))?></td></tr><?php endforeach;?></tbody></table><?php endif;?>
<?php if(!empty($r['patient_advice'])):?><p><strong>Patient instructions:</strong><br><?=pr_text($r['patient_advice'])?></p><?php endif;?>
<?php if(!empty($discharge['follow_up'])):?><h3>Follow-up recommendation</h3><table><thead><tr><th>Purpose</th><th>Recommended date</th><th>Urgency</th><th>Instructions</th></tr></thead><tbody><?php foreach($discharge['follow_up'] as $follow):?><tr><td><?=e((string)($follow['purpose']??''))?></td><td><?=pr_date($follow['recommended_date']??null)?></td><td><?=e(pr_status((string)($follow['urgency']??'routine')))?></td><td><?=pr_text((string)($follow['instructions']??''))?></td></tr><?php endforeach;?></tbody></table><?php elseif(!empty($r['follow_up_purpose'])||!empty($r['follow_up_date'])):?><p><strong>Follow-up:</strong> <?=e((string)($r['follow_up_purpose']??'Follow-up'))?> · <?=pr_date($r['follow_up_date']??null)?></p><?php endif;?>
</section>
<?php endif;?>
<div class="signature"><div>Treating Dentist</div><div>Patient / Guardian</div></div><?php pr_footer();
} elseif ($type === 'treatment_plan') {
    pr_require_role(['super_admin','clinic_admin','dentist','dental_assistant']);$planBranchExpr=schema_column_exists(table('treatment_plans'),'branch_id')?'COALESCE(tp.branch_id,ce.branch_id,p.branch_id)':'COALESCE(ce.branch_id,p.branch_id)';$stmt=$pdo->prepare('SELECT tp.*,p.*,tp.id plan_id,tp.patient_id plan_patient,'.$planBranchExpr.' plan_branch,u.name dentist_name FROM `' . table('treatment_plans') . '` tp LEFT JOIN `' . table('clinical_encounters') . '` ce ON ce.id=tp.encounter_id JOIN `' . table('patients') . '` p ON p.id=tp.patient_id LEFT JOIN `' . table('users') . '` u ON u.id=tp.dentist_user_id WHERE tp.id=?');$stmt->execute([$id]);$r=$stmt->fetch();if(!$r)exit('Treatment plan not found.');$patientId=(int)$r['plan_patient'];$branchId=(int)($r['plan_branch']??0);if(!record_branch_scope_allowed($branchId,$patientId)){http_response_code(403);exit('This treatment plan is outside your authorized branch or assignment scope.');}$title='Treatment Plan and Estimate';$reference='TP-'.str_pad((string)$id,6,'0',STR_PAD_LEFT);pr_header($title,$r,$reference);?><section class="section"><h2><?=e($r['title'])?></h2><div class="grid"><div class="field"><strong>Phase</strong><?=e($r['phase']?:'—')?></div><div class="field"><strong>Status</strong><?=e($r['status'])?></div><div class="field"><strong>Dentist</strong><?=e($r['dentist_name']?:'—')?></div><div class="field"><strong>Version</strong><?=e((string)$r['version_no'])?></div></div></section><?php $items=$pdo->prepare('SELECT * FROM `' . table('treatment_plan_items') . '` WHERE treatment_plan_id=? ORDER BY sequence_no,id');$items->execute([$id]);?><section class="section"><h2>Recommended Treatment</h2><table><thead><tr><th>#</th><th>Tooth/Area</th><th>Diagnosis</th><th>Procedure</th><th>Sessions</th><th>Fee</th><th>Status</th></tr></thead><tbody><?php foreach($items as $x):?><tr><td><?=e((string)$x['sequence_no'])?></td><td><?=e($x['tooth_region'])?></td><td><?=e($x['diagnosis'])?></td><td><?=e($x['procedure_name'])?></td><td><?=e((string)$x['sessions'])?></td><td><?=pr_money($x['estimated_fee'])?></td><td><?=e($x['status'])?></td></tr><?php endforeach;?><tr><td colspan="5" class="total">Estimated Total</td><td colspan="2" class="total"><?=pr_money($r['estimate_total'])?></td></tr></tbody></table><p><strong>Notes:</strong> <?=pr_text($r['notes'])?></p></section><div class="signature"><div>Dentist</div><div>Patient / Guardian Acceptance</div></div><?php pr_footer();
} elseif ($type === 'prescription') {
    pr_require_role(['super_admin','clinic_admin','dentist']);$stmt=$pdo->prepare('SELECT rx.*,p.*,rx.id rx_id,rx.patient_id rx_patient,u.name dentist_name,dp.license_number FROM `' . table('prescriptions') . '` rx JOIN `' . table('patients') . '` p ON p.id=rx.patient_id LEFT JOIN `' . table('users') . '` u ON u.id=rx.dentist_user_id LEFT JOIN `' . table('dentist_profiles') . '` dp ON dp.user_id=rx.dentist_user_id WHERE rx.id=?');$stmt->execute([$id]);$r=$stmt->fetch();if(!$r)exit('Prescription not found.');$patientId=(int)$r['rx_patient'];$branchId=(int)($r['branch_id']??0);if(!record_branch_scope_allowed($branchId,$patientId)){http_response_code(403);exit('This prescription is outside your authorized branch or assignment scope.');}$title='Dental Prescription';$reference=$r['prescription_no'];pr_header($title,$r,$reference);?><section class="section"><h2>Prescription record</h2><?php pr_render_prescription($pdo,$r,false);?></section><section class="section"><div class="grid"><div class="field"><strong>Issued</strong><?=pr_date($r['issued_at'],true)?></div><div class="field"><strong>Status</strong><?=e(pr_status((string)$r['status']))?></div><div class="field"><strong>Prescribing Dentist</strong><?=e((string)($r['signed_by_name']??$r['dentist_name']?:'—'))?></div><div class="field"><strong>License No.</strong><?=e((string)($r['signed_license_number']??$r['license_number']?:'—'))?></div></div></section><?php if(($r['status']??'')!=='cancelled'):?><div class="signature"><div>Prescribing Dentist Signature</div><div></div></div><?php endif;?><?php pr_footer();
} elseif (in_array($type,['invoice','receipt'],true)) {
    pr_require_role(['super_admin','clinic_admin','cashier','staff']);
    $stmt=$pdo->prepare('SELECT i.*,p.*,i.id invoice_id,i.patient_id invoice_patient,i.branch_id invoice_branch FROM `' . table('invoices') . '` i JOIN `' . table('patients') . '` p ON p.id=i.patient_id WHERE i.id=?');
    $stmt->execute([$id]);$r=$stmt->fetch();if(!$r)exit('Invoice not found.');
    $patientId=(int)$r['invoice_patient'];$branchId=(int)$r['invoice_branch'];
    if(!record_branch_scope_allowed($branchId,$patientId)){http_response_code(403);exit('This financial record is outside your authorized branch scope.');}

    $itemized=schema_table_exists(table('invoice_items'));
    $items=[];
    if($itemized){$itemStmt=$pdo->prepare('SELECT * FROM `' . table('invoice_items') . '` WHERE invoice_id=? ORDER BY id');$itemStmt->execute([$id]);$items=$itemStmt->fetchAll();}
    if(!$items)$items=[['description'=>$r['description'],'quantity'=>1,'unit_price'=>$r['amount'],'gross_amount'=>$r['amount'],'discount_amount'=>0,'net_amount'=>$r['amount']]];

    if($type==='invoice'){
        $title='Patient Invoice';$reference=(string)$r['invoice_no'];pr_header($title,$r,$reference);
        ?><?php if(function_exists('app_orientation_mode_active')&&app_orientation_mode_active()):?><section class="section"><div style="border:2px dashed #a35f00;padding:10px 12px;background:#fff8e8;text-align:center;font-weight:900;letter-spacing:.08em">DEMO COPY — CLIENT ORIENTATION ONLY</div></section><?php endif;?><section class="section"><h2>Itemized Charges</h2><table><thead><tr><th>Description</th><th>Qty</th><th>Unit Price</th><th>Gross</th><th>Discount</th><th>Net</th></tr></thead><tbody><?php foreach($items as $item):?><tr><td><?=e((string)$item['description'])?><?=!empty($item['item_code'])?'<br><small>'.e((string)$item['item_code']).'</small>':''?></td><td><?=e(number_format((float)($item['quantity']??1),2))?></td><td><?=pr_money($item['unit_price']??$item['gross_amount']??0)?></td><td><?=pr_money($item['gross_amount']??0)?></td><td><?=pr_money($item['discount_amount']??0)?></td><td><?=pr_money($item['net_amount']??$item['gross_amount']??0)?></td></tr><?php endforeach;?></tbody></table></section>
        <section class="section"><div class="grid"><div class="field"><strong>Subtotal</strong><?=pr_money($r['subtotal']??$r['amount'])?></div><div class="field"><strong>Discount</strong><?=pr_money($r['discount_amount']??0)?><?=!empty($r['discount_reason'])?'<br><small>'.e((string)$r['discount_reason']).'</small>':''?></div><div class="field"><strong>Total Charge</strong><?=pr_money($r['amount'])?></div><div class="field"><strong>Paid</strong><?=pr_money($r['paid_amount'])?></div><div class="field"><strong>Balance</strong><?=pr_money(max(0,(float)$r['amount']-(float)$r['paid_amount']))?></div><div class="field"><strong>Status</strong><?=e(pr_status((string)$r['status']))?></div></div></section>
        <div class="signature"><div>Authorized Cashier</div><div>Patient / Payor</div></div><?php
        pr_footer();
    } else {
        $paymentId=(int)($_GET['payment_id']??0);
        if($paymentId<1){
            $latestPayment=$pdo->prepare('SELECT id FROM `' . table('payments') . '` WHERE invoice_id=? ORDER BY created_at DESC,id DESC LIMIT 1');
            $latestPayment->execute([$id]);$paymentId=(int)($latestPayment->fetchColumn()?:0);
        }
        if($paymentId<1)exit('No payment has been recorded for this invoice.');
        $paymentTable=table('payments');
        $paymentColumns=(schema_column_exists($paymentTable,'tendered_amount')?',py.tendered_amount':',NULL tendered_amount')
            .(schema_column_exists($paymentTable,'change_amount')?',py.change_amount':',0 change_amount')
            .(schema_column_exists($paymentTable,'notes')?',py.notes':',NULL notes');
        $payerColumns=(schema_column_exists($paymentTable,'payer_name')?',py.payer_name':',NULL payer_name')
            .(schema_column_exists($paymentTable,'payer_relationship')?',py.payer_relationship':',NULL payer_relationship');
        $hasWindowLink=schema_table_exists(table('cashier_windows')) && schema_column_exists(table('payments'),'cashier_window_id');
        $windowJoin=$hasWindowLink?' LEFT JOIN `' . table('cashier_windows') . '` cw ON cw.id=py.cashier_window_id':'';
        $windowSelect=$hasWindowLink?',cw.window_name,cw.window_code':',NULL window_name,NULL window_code';
        $paymentStmt=$pdo->prepare('SELECT py.*,u.name receiver'.$paymentColumns.$payerColumns.$windowSelect.' FROM `' . table('payments') . '` py LEFT JOIN `' . table('users') . '` u ON u.id=py.received_by'.$windowJoin.' WHERE py.id=? AND py.invoice_id=? LIMIT 1');
        $paymentStmt->execute([$paymentId,$id]);$payment=$paymentStmt->fetch();if(!$payment)exit('Payment receipt not found for this invoice.');
        $recordId=$paymentId;
        $reference=(string)$r['invoice_no'].'-P'.str_pad((string)$paymentId,4,'0',STR_PAD_LEFT);
        $title='Official Payment Receipt';pr_header($title,$r,$reference);
        ?><?php if(function_exists('app_orientation_mode_active')&&app_orientation_mode_active()):?><section class="section"><div style="border:2px dashed #a35f00;padding:10px 12px;background:#fff8e8;text-align:center;font-weight:900;letter-spacing:.08em">DEMO COPY — CLIENT ORIENTATION ONLY</div></section><?php endif;?><?php
        $paidItems=revenue_payment_receipt_items($pdo,$paymentId);
        $hasGenericBreakdown=revenue_payment_receipt_rows_are_generic($paidItems);
        $allocatedTotal=0.0;foreach($paidItems as $paidItem)$allocatedTotal+=(float)($paidItem['amount_applied']??0);
        $returnRows=[];$returnedAmount=0.0;
        if(schema_table_exists(table('payment_adjustments'))){
            $returnStmt=$pdo->prepare('SELECT pa.*,rq.name requester,ap.name approver,pr.name processor FROM `' . table('payment_adjustments') . '` pa LEFT JOIN `' . table('users') . '` rq ON rq.id=pa.requested_by LEFT JOIN `' . table('users') . '` ap ON ap.id=pa.approved_by LEFT JOIN `' . table('users') . '` pr ON pr.id=pa.processed_by WHERE pa.payment_id=? AND pa.status="processed" ORDER BY pa.processed_at,pa.id');
            $returnStmt->execute([$paymentId]);$returnRows=$returnStmt->fetchAll();foreach($returnRows as $returnRow)$returnedAmount+=(float)$returnRow['amount'];
        }
        $invoiceBalance=max(0,(float)$r['amount']-(float)$r['paid_amount']);
        ?><?php if($hasGenericBreakdown):?><section class="section"><div style="border-left:4px solid #a35f00;padding:10px 12px;background:#fff8e8"><strong>Historical balance is not yet itemized.</strong><br><small>The imported source contained only an opening balance, not the procedures or services that created it. An Administrator must reconstruct the breakdown from the old chart, receipt, or ledger before this can be represented as an itemized clinical receipt.</small></div></section><?php endif;?>
        <section class="section"><h2>What This Payment Covered</h2><table><thead><tr><th>Service / Procedure</th><th>Qty</th><th>Charge</th><th>Paid Today</th><th>Balance After</th></tr></thead><tbody><?php foreach($paidItems as $item):?><tr><td><strong><?=e($hasGenericBreakdown?'Historical account balance — breakdown pending':(string)$item['description'])?></strong><?=!empty($item['item_code'])?'<br><small>'.e((string)$item['item_code']).'</small>':''?></td><td><?=e(number_format((float)($item['quantity']??1),2))?></td><td><?=pr_money($item['payable_amount']??$item['line_net']??0)?></td><td><strong><?=pr_money($item['amount_applied']??0)?></strong></td><td><?=pr_money($item['remaining_after']??0)?></td></tr><?php endforeach;if(!$paidItems):?><tr><td colspan="5">No payment allocation is available.</td></tr><?php endif;?><tr><td colspan="3" class="total">Amount paid today</td><td colspan="2" class="total"><?=pr_money($allocatedTotal)?></td></tr></tbody></table></section>
        <section class="section"><h2>Payment Information</h2><div class="grid"><div class="field"><strong>Date and time</strong><?=pr_date((string)$payment['created_at'],true)?></div><div class="field"><strong>Paid by</strong><?=e((string)($payment['payer_name']?:($r['first_name'].' '.$r['last_name'])))?> · <?=e((string)($payment['payer_relationship']?:'Self'))?></div><div class="field"><strong>Method</strong><?=e(pr_status((string)$payment['method']))?></div><div class="field"><strong>Reference</strong><?=e((string)($payment['reference_no']?:'—'))?></div><div class="field"><strong>Cashier</strong><?=e((string)($payment['receiver']?:'—'))?></div><div class="field"><strong>Window</strong><?=e(trim((string)($payment['window_code']??'').' '.(string)($payment['window_name']??''))?:'—')?></div></div><?php if(!empty($payment['notes'])):?><p><strong>Note:</strong> <?=e((string)$payment['notes'])?></p><?php endif;?></section>
        <section class="section"><h2>Payment Summary</h2><div class="grid"><div class="field"><strong>Paid today</strong><?=pr_money($payment['amount'])?></div><div class="field"><strong>Amount tendered</strong><?=pr_money($payment['tendered_amount']??$payment['amount'])?></div><div class="field"><strong>Change</strong><?=pr_money($payment['change_amount']??0)?></div><div class="field"><strong>Remaining invoice balance</strong><?=pr_money($invoiceBalance)?></div><?php if($invoiceBalance>0.001):?><div class="field"><strong>Original invoice total</strong><?=pr_money($r['amount'])?></div><div class="field"><strong>Total paid to date</strong><?=pr_money($r['paid_amount'])?></div><?php endif;?></div></section>
        <?php if($returnRows):?><section class="section"><h2>Refunds or Reversals</h2><table><thead><tr><th>Processed</th><th>Type</th><th>Method</th><th>Reference</th><th>Amount</th><th>Reason</th></tr></thead><tbody><?php foreach($returnRows as $x):?><tr><td><?=pr_date($x['processed_at'],true)?></td><td><?=e(pr_status((string)$x['adjustment_type']))?></td><td><?=e(pr_status((string)$x['method']))?></td><td><?=e((string)($x['reference_no']?:'—'))?></td><td><?=pr_money($x['amount'])?></td><td><?=e((string)$x['reason'])?></td></tr><?php endforeach;?></tbody></table><p><strong>Net amount retained:</strong> <?=pr_money(max(0,(float)$payment['amount']-$returnedAmount))?></p></section><?php endif;?>
        <div class="signature"><div>Authorized Cashier</div><div>Patient / Payor</div></div><?php
        pr_footer();
    }
} elseif ($type === 'payment_adjustment') {
    pr_require_role(['super_admin','clinic_admin','cashier','staff']);
    if (!schema_table_exists(table('payment_adjustments'))) exit('Payment return workflow is not installed.');
    $stmt=$pdo->prepare(
        'SELECT pa.*,pay.amount original_amount,pay.method original_method,pay.reference_no original_reference,pay.created_at payment_date,'
        . 'i.invoice_no,i.patient_id,i.branch_id,p.first_name,p.last_name,p.patient_no,p.mobile,p.email,'
        . 'rq.name requester,ap.name approver,pr.name processor,cs.id cashier_session_no '
        . 'FROM `' . table('payment_adjustments') . '` pa '
        . 'JOIN `' . table('payments') . '` pay ON pay.id=pa.payment_id '
        . 'JOIN `' . table('invoices') . '` i ON i.id=pa.invoice_id '
        . 'JOIN `' . table('patients') . '` p ON p.id=i.patient_id '
        . 'LEFT JOIN `' . table('users') . '` rq ON rq.id=pa.requested_by '
        . 'LEFT JOIN `' . table('users') . '` ap ON ap.id=pa.approved_by '
        . 'LEFT JOIN `' . table('users') . '` pr ON pr.id=pa.processed_by '
        . 'LEFT JOIN `' . table('cashier_sessions') . '` cs ON cs.id=pa.cashier_session_id '
        . 'WHERE pa.id=? AND pa.status="processed" LIMIT 1'
    );
    $stmt->execute([$id]);$r=$stmt->fetch();if(!$r)exit('Processed refund or reversal not found.');
    $patientId=(int)$r['patient_id'];$branchId=(int)$r['branch_id'];
    if(!record_branch_scope_allowed($branchId,$patientId)){http_response_code(403);exit('This financial record is outside your authorized branch scope.');}
    $title=(string)$r['adjustment_type']==='reversal'?'Payment Reversal Record':'Refund Receipt';
    $reference='RET-'.str_pad((string)$id,6,'0',STR_PAD_LEFT);
    pr_header($title,$r,$reference);?>
    <section class="section"><h2>Return transaction</h2><div class="grid"><div class="field"><strong>Invoice</strong><?=e((string)$r['invoice_no'])?></div><div class="field"><strong>Return type</strong><?=e(pr_status((string)$r['adjustment_type']))?></div><div class="field"><strong>Amount returned</strong><?=pr_money($r['amount'])?></div><div class="field"><strong>Return method</strong><?=e(pr_status((string)$r['method']))?></div><div class="field"><strong>Return reference</strong><?=e((string)($r['reference_no']?:'—'))?></div><div class="field"><strong>Processed</strong><?=pr_date($r['processed_at'],true)?></div><div class="field"><strong>Cashier session</strong><?=!empty($r['cashier_session_no'])?'#'.e((string)$r['cashier_session_no']):'—'?></div><div class="field"><strong>Status</strong><?=e(pr_status((string)$r['status']))?></div></div></section>
    <section class="section"><h2>Original payment</h2><div class="grid"><div class="field"><strong>Received</strong><?=pr_date($r['payment_date'],true)?></div><div class="field"><strong>Original amount</strong><?=pr_money($r['original_amount'])?></div><div class="field"><strong>Original method</strong><?=e(pr_status((string)$r['original_method']))?></div><div class="field"><strong>Original reference</strong><?=e((string)($r['original_reference']?:'—'))?></div></div></section>
    <section class="section"><h2>Reason and control trail</h2><p><strong>Reason:</strong> <?=pr_text($r['reason'])?></p><?php if(!empty($r['review_note'])):?><p><strong>Approval note:</strong> <?=pr_text($r['review_note'])?></p><?php endif;?><div class="grid"><div class="field"><strong>Requested by</strong><?=e((string)($r['requester']?:'—'))?><br><small><?=pr_date($r['requested_at'],true)?></small></div><div class="field"><strong>Approved by</strong><?=e((string)($r['approver']?:'—'))?><br><small><?=pr_date($r['approved_at'],true)?></small></div><div class="field"><strong>Processed by</strong><?=e((string)($r['processor']?:'—'))?><br><small><?=pr_date($r['processed_at'],true)?></small></div></div></section>
    <div class="signature"><div>Authorized Cashier</div><div>Patient / Payor Acknowledgment</div></div><?php pr_footer();
} elseif (in_array($type,['inventory_stock','inventory_expiry','sterilization_log'],true)) {
    pr_require_role(['super_admin','clinic_admin','inventory_officer']);
    $title=['inventory_stock'=>'Current Inventory Stock by Branch and Lot','inventory_expiry'=>'Inventory Lot and Expiration Report','sterilization_log'=>'Controlled Sterilization Log'][$type];
    if(!inventory_schema_ready()){http_response_code(409);exit('Apply Version 0.5.9.8 before printing controlled inventory or sterilization records.');}
    $reference=$date;$reportBranchId=superuser_primary_workspace()?(int)($_GET['branch_id']??0):signed_user_branch_id();pr_header($title,null,$reference);
    if($type==='inventory_stock'){
        if(schema_table_exists(table('inventory_branch_stocks'))){
            $sql='SELECT bs.*,i.sku,i.name,i.category,i.unit,b.name branch FROM `' . table('inventory_branch_stocks') . '` bs JOIN `' . table('inventory_items') . '` i ON i.id=bs.item_id JOIN `' . table('branches') . '` b ON b.id=bs.branch_id WHERE i.status="active"'.($reportBranchId>0?' AND bs.branch_id=?':'').' ORDER BY b.name,i.category,i.name';
            $stmt=$pdo->prepare($sql);$stmt->execute($reportBranchId>0?[$reportBranchId]:[]);$rows=$stmt->fetchAll();
        }else{$rows=$pdo->query('SELECT i.*,"Legacy aggregate" branch FROM `' . table('inventory_items') . '` i WHERE status="active" ORDER BY category,name')->fetchAll();}
        ?><table><thead><tr><th>Branch</th><th>SKU</th><th>Item</th><th>Category</th><th>Unit</th><th>Reconciled stock</th><th>Reorder</th><th>Last reconciliation</th></tr></thead><tbody><?php foreach($rows as $r):?><tr><td><?=e($r['branch'])?></td><td><?=e($r['sku'])?></td><td><?=e($r['name'])?></td><td><?=e($r['category'])?></td><td><?=e($r['unit'])?></td><td><?=e((string)$r['current_stock'])?></td><td><?=e((string)$r['reorder_level'])?></td><td><?=pr_date($r['last_reconciled_at']??null,true)?></td></tr><?php endforeach;?></tbody></table><?php
    }elseif($type==='inventory_expiry'){
        $sql='SELECT l.*,i.sku,i.name,i.unit,b.name branch FROM `' . table('inventory_lots') . '` l JOIN `' . table('inventory_items') . '` i ON i.id=l.item_id LEFT JOIN `' . table('branches') . '` b ON b.id=l.branch_id WHERE 1=1'.($reportBranchId>0?' AND l.branch_id=?':'').' ORDER BY b.name,l.expiry_date IS NULL,l.expiry_date,i.name';
        $stmt=$pdo->prepare($sql);$stmt->execute($reportBranchId>0?[$reportBranchId]:[]);$rows=$stmt->fetchAll();
        ?><table><thead><tr><th>Branch</th><th>Item</th><th>Lot</th><th>Expiry</th><th>Received</th><th>Remaining</th><th>Status</th><th>Source document</th></tr></thead><tbody><?php foreach($rows as $r):?><tr><td><?=e($r['branch']?:'—')?></td><td><?=e($r['sku'].' — '.$r['name'])?></td><td><?=e($r['lot_number'])?></td><td><?=pr_date($r['expiry_date'])?></td><td><?=e((string)$r['quantity_received'])?></td><td><?=e((string)$r['quantity_remaining']).' '.e($r['unit'])?></td><td><?=e(pr_status((string)$r['status']))?></td><td><?=e((string)($r['received_document_id']?:'Legacy'))?></td></tr><?php endforeach;?></tbody></table><?php
    }else{
        $sql='SELECT s.*,u.name operator_name,c.name completed_name,r.name released_name,b.name branch,e.serial_number,(SELECT GROUP_CONCAT(CONCAT(ix.set_code," — ",ix.name) ORDER BY ix.set_code SEPARATOR "; ") FROM `' . table('sterilization_batch_sets') . '` bs JOIN `' . table('instrument_sets') . '` ix ON ix.id=bs.instrument_set_id WHERE bs.batch_id=s.id) instrument_sets FROM `' . table('sterilization_batches') . '` s LEFT JOIN `' . table('users') . '` u ON u.id=s.operator_user_id LEFT JOIN `' . table('users') . '` c ON c.id=s.completed_by LEFT JOIN `' . table('users') . '` r ON r.id=s.released_by LEFT JOIN `' . table('branches') . '` b ON b.id=s.branch_id LEFT JOIN `' . table('sterilization_equipment') . '` e ON e.id=s.equipment_id WHERE DATE(s.cycle_started_at)=?'.($reportBranchId>0?' AND s.branch_id=?':'').' ORDER BY s.cycle_started_at';
        $args=[$date];if($reportBranchId>0)$args[]=$reportBranchId;$stmt=$pdo->prepare($sql);$stmt->execute($args);
        ?><table><thead><tr><th>Branch / Start</th><th>Sterilizer</th><th>Cycle / Load</th><th>Instrument sets</th><th>Operator / Reviewer</th><th>Physical parameters</th><th>Indicators</th><th>Status / Review</th><th>Evidence hash</th></tr></thead><tbody><?php foreach($stmt as $r):?><tr><td><?=e($r['branch']?:'—')?><br><?=pr_date($r['cycle_started_at'],true)?></td><td><?=e($r['sterilizer_name'])?><?php if(!empty($r['serial_number'])):?><br><small>S/N <?=e($r['serial_number'])?></small><?php endif;?></td><td><?=e($r['cycle_no'].' / '.$r['load_no'])?></td><td><?=e($r['instrument_sets']?:'No linked sets')?></td><td>Operator: <?=e($r['operator_name']?:'—')?><br>Completed: <?=e($r['completed_name']?:'—')?><br>Released: <?=e($r['released_name']?:'—')?></td><td><?=e((string)($r['temperature_c']?:'—'))?> °C<br><?=e((string)($r['pressure_kpa']?:'—'))?> kPa<br><?=e((string)($r['exposure_minutes']?:'—'))?> min</td><td>Chemical: <?=e(pr_status((string)($r['chemical_indicator_result']??$r['indicator_result'])))?><br>Biological: <?=e(pr_status((string)($r['biological_indicator_result']??$r['biological_result'])))?></td><td><?=e(pr_status((string)($r['cycle_status']??$r['release_status'])))?><?php if(!empty($r['release_note'])):?><br><small>Release: <?=e($r['release_note'])?></small><?php endif;?><?php if(!empty($r['failure_reason'])):?><br><small>Failure: <?=e($r['failure_reason'])?></small><?php endif;?></td><td><?=e(!empty($r['batch_hash'])?substr((string)$r['batch_hash'],0,20).'…':'Not released')?></td></tr><?php endforeach;?></tbody></table><?php
    }
    pr_footer();
} elseif (in_array($type,['audit_log','collection_report'],true)) {
    pr_require_role(['super_admin','clinic_admin']);$title=$type==='audit_log'?'Daily Audit Log':'Daily Collection Report';$reference=$date;pr_header($title,null,$reference);if($type==='audit_log'){$auditBranchId=superuser_primary_workspace()?0:signed_user_branch_id();$auditSql='SELECT a.*,u.name user_name FROM `' . table('audit_logs') . '` a LEFT JOIN `' . table('users') . '` u ON u.id=a.user_id WHERE DATE(a.created_at)=?';$auditArgs=[$date];if(!superuser_primary_workspace()){if(schema_column_exists(table('audit_logs'),'branch_id')&&$auditBranchId>0){$auditSql.=' AND a.branch_id=?';$auditArgs[]=$auditBranchId;}else{$auditSql.=' AND 1=0';}}$auditSql.=' ORDER BY a.created_at';$stmt=$pdo->prepare($auditSql);$stmt->execute($auditArgs);?><table><thead><tr><th>Time</th><th>User</th><th>Action</th><th>Entity</th><th>Record</th></tr></thead><tbody><?php foreach($stmt as $r):?><tr><td><?=e(date('g:i:s A',strtotime($r['created_at'])))?></td><td><?=e($r['user_name']?:'System')?></td><td><?=e($r['action'])?></td><td><?=e($r['entity_type'])?></td><td><?=e((string)$r['entity_id'])?></td></tr><?php endforeach;?></tbody></table><?php }else{
        $reportBranchId=superuser_primary_workspace()?0:signed_user_branch_id();
        $branchSql=$reportBranchId>0?' AND i.branch_id=?':(superuser_primary_workspace()?'':' AND 1=0');
        $paymentSql='SELECT py.*,i.invoice_no,p.first_name,p.last_name,u.name cashier FROM `' . table('payments') . '` py JOIN `' . table('invoices') . '` i ON i.id=py.invoice_id JOIN `' . table('patients') . '` p ON p.id=i.patient_id LEFT JOIN `' . table('users') . '` u ON u.id=py.received_by WHERE DATE(py.created_at)=?'.$branchSql.' ORDER BY py.created_at';
        $paymentArgs=[$date];if($reportBranchId>0)$paymentArgs[]=$reportBranchId;
        $stmt=$pdo->prepare($paymentSql);$stmt->execute($paymentArgs);$paymentRows=$stmt->fetchAll();
        $returnRows=[];
        if(schema_table_exists(table('payment_adjustments'))){
            $returnSql='SELECT pa.*,i.invoice_no,p.first_name,p.last_name,rq.name requester,ap.name approver,pr.name processor FROM `' . table('payment_adjustments') . '` pa JOIN `' . table('invoices') . '` i ON i.id=pa.invoice_id JOIN `' . table('patients') . '` p ON p.id=i.patient_id LEFT JOIN `' . table('users') . '` rq ON rq.id=pa.requested_by LEFT JOIN `' . table('users') . '` ap ON ap.id=pa.approved_by LEFT JOIN `' . table('users') . '` pr ON pr.id=pa.processed_by WHERE pa.status="processed" AND DATE(pa.processed_at)=?'.$branchSql.' ORDER BY pa.processed_at';
            $returnArgs=[$date];if($reportBranchId>0)$returnArgs[]=$reportBranchId;
            $returnStmt=$pdo->prepare($returnSql);$returnStmt->execute($returnArgs);$returnRows=$returnStmt->fetchAll();
        }
        $gross=0.0;$returned=0.0;$methodTotals=[];$cashierTotals=[];$returnMethodTotals=[];
        foreach($paymentRows as $x){
            $amount=(float)$x['amount'];$gross+=$amount;
            $method=(string)($x['method']?:'unknown');$cashier=(string)($x['cashier']?:'Unassigned cashier');
            if(!isset($methodTotals[$method]))$methodTotals[$method]=['count'=>0,'amount'=>0.0];
            if(!isset($cashierTotals[$cashier]))$cashierTotals[$cashier]=['count'=>0,'amount'=>0.0];
            $methodTotals[$method]['count']++;$methodTotals[$method]['amount']+=$amount;
            $cashierTotals[$cashier]['count']++;$cashierTotals[$cashier]['amount']+=$amount;
        }
        foreach($returnRows as $x){
            $amount=(float)$x['amount'];$returned+=$amount;$method=(string)($x['method']?:'unknown');
            if(!isset($returnMethodTotals[$method]))$returnMethodTotals[$method]=['count'=>0,'amount'=>0.0];
            $returnMethodTotals[$method]['count']++;$returnMethodTotals[$method]['amount']+=$amount;
        }
        ksort($methodTotals);ksort($cashierTotals);ksort($returnMethodTotals);
        ?><section class="section"><h2>Collection Summary</h2><div class="grid"><div class="field"><strong>Gross payments received</strong><?=pr_money($gross)?></div><div class="field"><strong>Refunds and reversals</strong><?=pr_money($returned)?></div><div class="field"><strong>Net collections</strong><?=pr_money($gross-$returned)?></div><div class="field"><strong>Accounting basis</strong>Cash movements processed on <?=e(pr_date($date))?></div></div></section>
        <section class="section"><h2>By Payment Method</h2><table><thead><tr><th>Method</th><th>Payment count</th><th>Gross received</th><th>Returned</th><th>Net</th></tr></thead><tbody><?php foreach($methodTotals as $method=>$total):$ret=$returnMethodTotals[$method]['amount']??0.0;?><tr><td><?=e(pr_status($method))?></td><td><?=e((string)$total['count'])?></td><td><?=pr_money($total['amount'])?></td><td><?=pr_money($ret)?></td><td><?=pr_money($total['amount']-$ret)?></td></tr><?php endforeach;if(!$methodTotals):?><tr><td colspan="5">No payment methods recorded on this date.</td></tr><?php endif;?></tbody></table></section>
        <section class="section"><h2>By Cashier</h2><table><thead><tr><th>Cashier</th><th>Payment count</th><th>Gross received</th></tr></thead><tbody><?php foreach($cashierTotals as $cashier=>$total):?><tr><td><?=e($cashier)?></td><td><?=e((string)$total['count'])?></td><td><?=pr_money($total['amount'])?></td></tr><?php endforeach;if(!$cashierTotals):?><tr><td colspan="3">No cashier payments recorded on this date.</td></tr><?php endif;?></tbody></table></section>
        <section class="section"><h2>Payments Received</h2><table><thead><tr><th>Time</th><th>Invoice</th><th>Patient</th><th>Source / Method</th><th>Reference</th><th>Cashier</th><th>Gross</th></tr></thead><tbody><?php foreach($paymentRows as $x):?><tr><td><?=e(date('g:i A',strtotime($x['created_at'])))?></td><td><?=e($x['invoice_no'])?></td><td><?=e($x['last_name'].', '.$x['first_name'])?></td><td><?=e(pr_status((string)($x['source_type']??'patient')))?> · <?=e(pr_status((string)$x['method']))?></td><td><?=e((string)($x['reference_no']?:'—'))?></td><td><?=e($x['cashier']?:'—')?></td><td><?=pr_money($x['amount'])?></td></tr><?php endforeach;if(!$paymentRows):?><tr><td colspan="7">No payments received on this date.</td></tr><?php endif;?></tbody></table></section>
        <section class="section"><h2>Refunds and Reversals Processed</h2><table><thead><tr><th>Time</th><th>Invoice</th><th>Patient</th><th>Type / Method</th><th>Reference</th><th>Control Trail</th><th>Amount Returned</th></tr></thead><tbody><?php foreach($returnRows as $x):?><tr><td><?=e(date('g:i A',strtotime($x['processed_at'])))?></td><td><?=e($x['invoice_no'])?></td><td><?=e($x['last_name'].', '.$x['first_name'])?></td><td><?=e(pr_status((string)$x['adjustment_type']))?> · <?=e(pr_status((string)$x['method']))?></td><td><?=e((string)($x['reference_no']?:'—'))?></td><td><small><?=e($x['requester']?:'—')?> / <?=e($x['approver']?:'—')?> / <?=e($x['processor']?:'—')?></small></td><td><?=pr_money($x['amount'])?></td></tr><?php endforeach;if(!$returnRows):?><tr><td colspan="7">No refunds or reversals processed on this date.</td></tr><?php endif;?></tbody></table></section><?php
    }pr_footer();
} else { http_response_code(404); exit('Unsupported printable record.'); }

$html = ob_get_clean();
pr_log($type, $recordId ?: null, $patientId, $branchId ?: null, $reason);
echo $html;
