<?php
require DENTAL_ROOT . '/app/bootstrap.php';require_login();require_documentation_schema();require_permission('clinical.view',['super_admin','clinic_admin','dentist','dental_assistant']);require DENTAL_ROOT . '/app/layout.php';require DENTAL_ROOT . '/app/module_helpers.php';
$pdo=db();$canCreate=clinical_record_edit_allowed(['dentist']);$canUpdate=clinical_record_edit_allowed(['dentist','dental_assistant']);$patients=patient_options();$dentists=dentist_options();$patientId=(int)($_GET['patient_id']??0);if($patientId)require_patient($patientId);
if($_SERVER['REQUEST_METHOD']==='POST'){
 verify_csrf();$action=$_POST['action']??'create';if($action==='create')require_clinical_record_editor(['dentist']);else require_clinical_record_editor(['dentist','dental_assistant']);
 if($action==='create'){$patientId=(int)$_POST['patient_id'];require_patient($patientId);$stmt=$pdo->prepare('INSERT INTO `' . table('laboratory_cases') . '` (patient_id,treatment_plan_id,dentist_user_id,laboratory_name,case_type,tooth_arch,shade,material,due_date,status,cost,instructions,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,NOW())');$stmt->execute([$patientId,$_POST['treatment_plan_id']?:null,has_role('dentist')?(int)current_user()['id']:($_POST['dentist_user_id']?:null),trim((string)$_POST['laboratory_name']),trim((string)$_POST['case_type']),trim((string)$_POST['tooth_arch']),trim((string)$_POST['shade']),trim((string)$_POST['material']),$_POST['due_date']?:null,$_POST['status'],(float)$_POST['cost'],trim((string)$_POST['instructions'])]);$id=(int)$pdo->lastInsertId();audit('laboratory_case_created','laboratory_case',$id,['patient_id'=>$patientId]);module_return('laboratory.php?patient_id='.$patientId,'success','Laboratory case created.');}
 if($action==='status'){$id=(int)$_POST['id'];module_require_record_scope($pdo,'laboratory_cases',$id,'patient_id','dentist_user_id',true);$status=(string)$_POST['status'];if(!in_array($status,['draft','sent','received_by_lab','in_production','quality_check','ready','received_by_clinic','patient_fitting','adjustment_required','completed','cancelled'],true))throw new RuntimeException('Select a valid laboratory status.');$stmt=$pdo->prepare('UPDATE `' . table('laboratory_cases') . '` SET status=?,received_at=IF(?="received_by_clinic",NOW(),received_at),completed_at=IF(?="completed",NOW(),completed_at) WHERE id=?');$stmt->execute([$status,$status,$status,$id]);$stmt=$pdo->prepare('SELECT patient_id FROM `' . table('laboratory_cases') . '` WHERE id=?');$stmt->execute([$id]);$patientId=(int)$stmt->fetchColumn();audit('laboratory_case_status_updated','laboratory_case',$id,['status'=>$status]);module_return('laboratory.php?patient_id='.$patientId,'success','Laboratory case updated.');}
}
$state=module_management_state();$q=$state['query'];$statusFilter=module_safe_status_filter('status',['','draft','sent','received_by_lab','in_production','quality_check','ready','received_by_clinic','patient_fitting','adjustment_required','completed','cancelled']);
$where=['1=1'];$args=[];if($patientId){$where[]='l.patient_id=?';$args[]=$patientId;}[$scopeSql,$scopeArgs]=task_patient_scope_condition('l.patient_id');if($scopeSql!==''){$where[]=substr(trim($scopeSql),4);$args=array_merge($args,$scopeArgs);}if($q!==''){$term=module_like_term($q);$where[]='(l.case_type LIKE ? ESCAPE "\\" OR l.laboratory_name LIKE ? ESCAPE "\\" OR l.tooth_arch LIKE ? ESCAPE "\\" OR CONCAT(p.first_name," ",p.last_name) LIKE ? ESCAPE "\\")';array_push($args,$term,$term,$term,$term);}if($statusFilter!==''){$where[]='l.status=?';$args[]=$statusFilter;}$whereSql=implode(' AND ',$where);
$count=$pdo->prepare('SELECT COUNT(*) FROM `' . table('laboratory_cases') . '` l JOIN `' . table('patients') . '` p ON p.id=l.patient_id WHERE '.$whereSql);$count->execute($args);$total=(int)$count->fetchColumn();$pages=max(1,(int)ceil($total/$state['per_page']));$state['page']=min($state['page'],$pages);$state['offset']=($state['page']-1)*$state['per_page'];
$stmt=$pdo->prepare('SELECT l.*,CONCAT(p.first_name," ",p.last_name) patient,p.patient_no,u.name dentist FROM `' . table('laboratory_cases') . '` l JOIN `' . table('patients') . '` p ON p.id=l.patient_id LEFT JOIN `' . table('users') . '` u ON u.id=l.dentist_user_id WHERE '.$whereSql.' ORDER BY (l.due_date IS NULL),l.due_date,l.created_at DESC LIMIT '.$state['per_page'].' OFFSET '.$state['offset']);$stmt->execute($args);$rows=$stmt->fetchAll();
$selected=null;if($state['manage_id']>0){$stmt=$pdo->prepare('SELECT l.*,CONCAT(p.first_name," ",p.last_name) patient,p.patient_no,u.name dentist FROM `' . table('laboratory_cases') . '` l JOIN `' . table('patients') . '` p ON p.id=l.patient_id LEFT JOIN `' . table('users') . '` u ON u.id=l.dentist_user_id WHERE l.id=? LIMIT 1');$stmt->execute([$state['manage_id']]);$candidate=$stmt->fetch();if($candidate){require_patient((int)$candidate['patient_id']);$selected=$candidate;}}
render_header('Laboratory Cases');render_module_intro('Dental laboratory workflow','Track crowns, bridges, dentures, appliances, retainers, and implant prostheses through delivery.',$canCreate?'New laboratory case':null,$canCreate?'lab-form':null);
?>
<div class="management-workspace"><form method="get" class="card management-filters"><label>Search cases<input type="search" name="q" value="<?=e($q)?>" placeholder="Patient, laboratory, case type, or tooth"></label><label>Patient<select name="patient_id"><option value="">All patients</option><?php foreach($patients as $patient):?><option value="<?=(int)$patient['id']?>" <?=$patientId===(int)$patient['id']?'selected':''?>><?=e($patient['patient_no'].' — '.$patient['last_name'].', '.$patient['first_name'])?></option><?php endforeach;?></select></label><label>Status<select name="status"><option value="">All statuses</option><?php foreach(['draft','sent','received_by_lab','in_production','quality_check','ready','received_by_clinic','patient_fitting','adjustment_required','completed','cancelled'] as $status):?><option value="<?=$status?>" <?=$statusFilter===$status?'selected':''?>><?=e(module_status($status))?></option><?php endforeach;?></select></label><div class="filter-actions"><button class="btn primary">Filter</button><a class="btn ghost" href="laboratory.php">Reset</a></div></form>
<section class="card management-table-card"><div class="card-head"><div><h2>Laboratory cases</h2><p>Status controls open only for the selected case.</p></div><?php module_render_list_count($total,'cases');?></div><?php module_render_server_pagination($total,$state['page'],$state['per_page'],'page','per_page','cases');?><div class="table-wrap"><table><thead><tr><th>Due</th><th>Patient</th><th>Case</th><th>Laboratory</th><th>Tooth / material</th><th>Cost</th><th>Status</th><th></th></tr></thead><tbody><?php foreach($rows as $row):$overdue=$row['due_date']&&$row['due_date']<date('Y-m-d')&&!in_array($row['status'],['completed','cancelled'],true);?><tr><td class="<?=$overdue?'danger-text':''?>"><?=$row['due_date']?e(date('M j, Y',strtotime((string)$row['due_date']))):'—'?></td><td><strong><?=e($row['patient'])?></strong><small><?=e((string)$row['patient_no'])?></small></td><td><strong><?=e($row['case_type'])?></strong><small><?=e((string)($row['dentist']?:'Dentist not recorded'))?></small></td><td><?=e($row['laboratory_name'])?></td><td><?=e((string)($row['tooth_arch']?:'—'))?><small><?=e(trim((string)($row['material']?:'').' '.(string)($row['shade']?:'')))?></small></td><td>₱<?=number_format((float)$row['cost'],2)?></td><td><span class="badge"><?=e(module_status((string)$row['status']))?></span></td><td><?php if($canUpdate):?><a class="btn ghost compact" href="<?=e(module_management_url(['manage_id'=>(int)$row['id']]))?>">Manage</a><?php endif;?></td></tr><?php endforeach;?><?php if(!$rows):?><tr><td colspan="8" class="management-empty">No laboratory cases match this view.</td></tr><?php endif;?></tbody></table></div><?php module_render_server_pagination($total,$state['page'],$state['per_page'],'page','per_page','cases');?></section>
<?php if($selected&&$canUpdate):?><dialog id="manage-lab" class="management-dialog" data-auto-open-dialog="manage-lab"><form method="post" class="form-grid"><button type="button" class="dialog-close" data-close>×</button><h2 class="wide"><?=e((string)$selected['case_type'])?></h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="status"><input type="hidden" name="id" value="<?=(int)$selected['id']?>"><div class="wide management-summary"><div><span>Patient</span><strong><?=e((string)$selected['patient'])?></strong></div><div><span>Laboratory</span><strong><?=e((string)$selected['laboratory_name'])?></strong></div><div><span>Due</span><strong><?=$selected['due_date']?e(date('M j, Y',strtotime((string)$selected['due_date']))):'Not set'?></strong></div></div><label>Status<select name="status"><?php foreach(['draft','sent','received_by_lab','in_production','quality_check','ready','received_by_clinic','patient_fitting','adjustment_required','completed','cancelled'] as $status):?><option value="<?=$status?>" <?=$selected['status']===$status?'selected':''?>><?=e(module_status($status))?></option><?php endforeach;?></select></label><button class="btn primary">Update case</button><a class="btn ghost" href="<?=e(module_management_url(['manage_id'=>null]))?>">Close</a></form></dialog><?php endif;?>
<?php if($canCreate):?><dialog id="lab-form" class="wide-dialog"><form method="post" class="form-grid"><button type="button" class="dialog-close" data-close>×</button><h2 class="wide">New laboratory case</h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="create"><label>Patient<?php module_patient_select($patients,'patient_id',$patientId);?></label><label>Dentist<?php module_dentist_select($dentists);?></label><label>Laboratory<input name="laboratory_name" required></label><label>Case type<select name="case_type"><option>Crown</option><option>Bridge</option><option>Denture</option><option>Orthodontic Appliance</option><option>Night Guard</option><option>Retainer</option><option>Implant Prosthesis</option></select></label><label>Tooth or arch<input name="tooth_arch"></label><label>Shade<input name="shade"></label><label>Material<input name="material"></label><label>Due date<input type="date" name="due_date"></label><label>Cost<input type="number" step="0.01" min="0" name="cost" value="0"></label><label>Status<select name="status"><option value="draft">Draft</option><option value="sent">Sent to laboratory</option></select></label><label>Treatment plan ID<input type="number" name="treatment_plan_id"></label><label class="wide">Instructions<textarea name="instructions"></textarea></label><button class="btn primary">Create case</button></form></dialog><?php endif;?></div>
<?php render_footer();
