<?php

declare(strict_types=1);

require DENTAL_ROOT . '/app/bootstrap.php';
require_login();
require_roles(['super_admin','clinic_admin','receptionist','staff']);
require DENTAL_ROOT . '/app/layout.php';
require DENTAL_ROOT . '/app/module_helpers.php';

$pdo=db();
if(!schema_table_exists(table('appointment_waitlist'))){
    render_header('Appointment Waitlist');
    echo '<div class="alert error"><strong>Waitlist update required.</strong><p>Apply Version 0.5.8.2 in System Setup before using this page.</p></div>';
    render_footer();exit;
}
$user=current_user()??[];
$branchId=(int)($user['branch_id']??0);
if($branchId<1)$branchId=(int)($pdo->query('SELECT id FROM `' . table('branches') . '` WHERE is_active=1 ORDER BY id LIMIT 1')->fetchColumn()?:0);
$canManage=task_context_action_allowed('appointments.manage')&&has_role(['super_admin','clinic_admin','receptionist','staff']);
$services=clinic_services_catalog($branchId?:null);
$dentists=active_dentists($branchId?:null);
$error='';

if($_SERVER['REQUEST_METHOD']==='POST'){
    try{
        verify_csrf();require_task_action('appointments.manage');require_roles(['super_admin','clinic_admin','receptionist','staff']);
        $action=(string)($_POST['action']??'');
        if($action==='create'){
            $patientId=(int)($_POST['patient_id']??0);$serviceId=(int)($_POST['service_id']??0);
            $earliest=trim((string)($_POST['earliest_date']??''));$latest=trim((string)($_POST['latest_date']??''));
            $from=trim((string)($_POST['preferred_time_from']??''))?:null;$to=trim((string)($_POST['preferred_time_to']??''))?:null;
            $priority=(string)($_POST['priority']??'routine');if(!in_array($priority,['routine','soon','urgent'],true))$priority='routine';
            if($patientId<1||$serviceId<1||!preg_match('/^\d{4}-\d{2}-\d{2}$/',$earliest)||!preg_match('/^\d{4}-\d{2}-\d{2}$/',$latest))throw new RuntimeException('Select the patient, service, and acceptable date range.');
            require_patient($patientId);if($latest<$earliest)throw new RuntimeException('The latest acceptable date cannot be before the earliest date.');
            $service=null;foreach($services as $candidate)if((int)$candidate['id']===$serviceId){$service=$candidate;break;}if(!$service)throw new RuntimeException('The selected service is unavailable.');
            $doctorId=null;
            if(service_provider_type($service)==='dentist'){
                $continuity=patient_primary_dentist($patientId);$requested=(int)($_POST['dentist_user_id']??0);
                $doctorId=(int)($continuity['id']??$requested?:0);if($doctorId<1)throw new RuntimeException('Select a dentist because this patient does not yet have a continuity dentist.');
                $activeIds=array_map(static fn(array $row):int=>(int)$row['id'],$dentists);if(!in_array($doctorId,$activeIds,true))throw new RuntimeException('The selected continuity dentist is not active at this branch.');
            }
            $duplicate=$pdo->prepare('SELECT id FROM `' . table('appointment_waitlist') . '` WHERE branch_id=? AND patient_id=? AND service_id=? AND status IN ("waiting","offered") LIMIT 1');
            $duplicate->execute([$branchId,$patientId,$serviceId]);if($duplicate->fetchColumn())throw new RuntimeException('This patient already has an active waitlist request for the selected service.');
            $pdo->prepare('INSERT INTO `' . table('appointment_waitlist') . '` (branch_id,patient_id,service_id,dentist_user_id,earliest_date,latest_date,preferred_time_from,preferred_time_to,priority,status,notes,created_by,created_at) VALUES (?,?,?,?,?,?,?,?,?,"waiting",?,?,NOW())')->execute([$branchId,$patientId,$serviceId,$doctorId?:null,$earliest,$latest,$from,$to,$priority,trim((string)($_POST['notes']??''))?:null,(int)($user['id']??0)]);
            $id=(int)$pdo->lastInsertId();audit('appointment_waitlist_created','appointment_waitlist',$id,['patient_id'=>$patientId,'service_id'=>$serviceId]);
            flash('success','Patient added to the appointment waitlist.');header('Location: waitlist.php');exit;
        }
        if($action==='status'){
            $id=(int)($_POST['id']??0);$status=(string)($_POST['status']??'');
            if(!in_array($status,['waiting','offered','declined','cancelled','expired'],true))throw new RuntimeException('Invalid waitlist status.');
            $stmt=$pdo->prepare('SELECT * FROM `' . table('appointment_waitlist') . '` WHERE id=? AND branch_id=? LIMIT 1');$stmt->execute([$id,$branchId]);$row=$stmt->fetch();if(!$row)throw new RuntimeException('Waitlist entry not found.');
            $expires=$status==='offered'?date('Y-m-d H:i:s',strtotime('+24 hours')):null;
            $pdo->prepare('UPDATE `' . table('appointment_waitlist') . '` SET status=?,offer_expires_at=?,notes=CONCAT_WS("\n",NULLIF(notes,""),NULLIF(?,"")),updated_at=NOW() WHERE id=?')->execute([$status,$expires,trim((string)($_POST['note']??'')),$id]);
            audit('appointment_waitlist_status_changed','appointment_waitlist',$id,['status'=>$status],['status'=>$row['status']]);
            flash('success','Waitlist status updated.');header('Location: '.module_query_url(['page'=>null]));exit;
        }
        throw new RuntimeException('Unsupported waitlist action.');
    }catch(Throwable $exception){$error=$exception->getMessage();}
}

$status=trim((string)($_GET['status']??'waiting'));$allowed=['waiting','offered','booked','declined','cancelled','expired'];if(!in_array($status,$allowed,true))$status='';
$q=trim((string)($_GET['q']??''));$matchCancelled=isset($_GET['match_cancelled']);
$page=module_page_number();$perPage=module_page_size('per_page',25);
$where=' WHERE w.branch_id=?';$args=[$branchId];
if($status!==''){$where.=' AND w.status=?';$args[]=$status;}
if($q!==''){$like='%'.$q.'%';$where.=' AND (p.patient_no LIKE ? OR p.first_name LIKE ? OR p.last_name LIKE ? OR p.mobile LIKE ? OR s.name LIKE ? OR u.name LIKE ?)';array_push($args,$like,$like,$like,$like,$like,$like);}
if($matchCancelled){$where.=' AND EXISTS (SELECT 1 FROM `' . table('appointments') . '` a WHERE a.branch_id=w.branch_id AND a.status="cancelled" AND a.start_at>=NOW() AND a.start_at<DATE_ADD(NOW(),INTERVAL 60 DAY) AND a.service_id=w.service_id AND DATE(a.start_at) BETWEEN w.earliest_date AND w.latest_date AND (w.dentist_user_id IS NULL OR w.dentist_user_id=a.dentist_user_id))';}
$from=' FROM `' . table('appointment_waitlist') . '` w JOIN `' . table('patients') . '` p ON p.id=w.patient_id JOIN `' . table('service_catalog') . '` s ON s.id=w.service_id LEFT JOIN `' . table('users') . '` u ON u.id=w.dentist_user_id';
$countStmt=$pdo->prepare('SELECT COUNT(*)'.$from.$where);$countStmt->execute($args);$total=(int)$countStmt->fetchColumn();$pages=max(1,(int)ceil($total/$perPage));$page=min($page,$pages);$offset=($page-1)*$perPage;
$stmt=$pdo->prepare('SELECT w.*,p.patient_no,p.first_name,p.last_name,p.mobile,s.name service_name,s.provider_type,u.name dentist_name'.$from.$where.' ORDER BY FIELD(w.priority,"urgent","soon","routine"),w.earliest_date,w.created_at LIMIT '.$perPage.' OFFSET '.$offset);$stmt->execute($args);$rows=$stmt->fetchAll();
$manageId=max(0,(int)($_GET['manage_id']??0));$managedRow=null;if($manageId>0){$manageStmt=$pdo->prepare('SELECT w.*,p.patient_no,p.first_name,p.last_name,p.mobile,s.name service_name,s.provider_type,u.name dentist_name'.$from.' WHERE w.branch_id=? AND w.id=? LIMIT 1');$manageStmt->execute([$branchId,$manageId]);$managedRow=$manageStmt->fetch()?:null;}
$counts=[];
$countByStatus=$pdo->prepare('SELECT status,COUNT(*) total FROM `' . table('appointment_waitlist') . '` WHERE branch_id=? GROUP BY status');$countByStatus->execute([$branchId]);foreach($countByStatus as $row)$counts[(string)$row['status']]=(int)$row['total'];

render_header('Appointment Waitlist');
?>
<?php if($error!==''):?><div class="flash error"><?=e($error)?></div><?php endif;?>
<div class="toolbar"><div><strong>Fill cancelled or newly opened slots</strong><span class="muted">Keep patient preferences and continuity dentist together until a valid slot becomes available.</span></div><?php if($canManage):?><button class="btn primary" type="button" data-open="waitlist-form">Add patient</button><?php endif;?></div>
<div class="request-filter-row"><a class="<?=$status===''?'active':''?>" href="<?=e(module_query_url(['status'=>null,'page'=>null]))?>">All</a><?php foreach($allowed as $filter):?><a class="<?=$status===$filter?'active':''?>" href="<?=e(module_query_url(['status'=>$filter,'page'=>null]))?>"><?=e(module_status($filter))?> <span><?=e((string)($counts[$filter]??0))?></span></a><?php endforeach;?><a class="<?=$matchCancelled?'active':''?>" href="<?=e(module_query_url(['match_cancelled'=>$matchCancelled?null:1,'page'=>null]))?>">Matches cancelled slots</a></div>
<form method="get" class="card compact-filter" data-auto-submit><?php if($status!==''):?><input type="hidden" name="status" value="<?=e($status)?>"><?php endif;?><label>Search<input type="search" name="q" value="<?=e($q)?>" placeholder="Patient, mobile, service, or dentist" data-auto-search data-min-length="2"></label><?php if($matchCancelled):?><input type="hidden" name="match_cancelled" value="1"><?php endif;?></form>
<div class="card server-list-card"><?php module_render_server_pagination($total,$page,$perPage,'page','per_page','waitlist entries');?><div class="table-wrap" data-no-pagination><table data-no-pagination="true"><thead><tr><th>Priority</th><th>Patient</th><th>Service / dentist</th><th>Acceptable schedule</th><th>Status</th><th></th></tr></thead><tbody><?php foreach($rows as $row):?><tr><td><span class="badge"><?=e(module_status((string)$row['priority']))?></span></td><td><strong><?=e($row['last_name'].', '.$row['first_name'])?></strong><small><?=e((string)$row['patient_no'])?><?=!empty($row['mobile'])?' · '.e((string)$row['mobile']):''?></small></td><td><?=e((string)$row['service_name'])?><small><?=($row['provider_type']??'dentist')==='inhouse'?'In-house clinic team':e((string)($row['dentist_name']?:'Dentist not assigned'))?></small></td><td><?=e(date('M j',strtotime((string)$row['earliest_date'])).'–'.date('M j, Y',strtotime((string)$row['latest_date'])))?><?php if($row['preferred_time_from']||$row['preferred_time_to']):?><small><?=e((string)($row['preferred_time_from']?:'Any time'))?>–<?=e((string)($row['preferred_time_to']?:'Any time'))?></small><?php endif;?></td><td><span class="badge"><?=e(module_status((string)$row['status']))?></span><?php if($row['offer_expires_at']):?><small>Offer expires <?=e(date('M j g:i A',strtotime((string)$row['offer_expires_at'])))?></small><?php endif;?></td><td><div class="inline-actions"><?php if(in_array($row['status'],['waiting','offered'],true)):?><a href="appointments.php?new=1&amp;waitlist_id=<?=(int)$row['id']?>">Book appointment</a><?php endif;?><?php if($canManage):?><a class="btn ghost" href="<?=e(module_management_url(['manage_id'=>(int)$row['id'],'page'=>$page,'per_page'=>$perPage]))?>">Manage</a><?php endif;?></div></td></tr><?php endforeach;?><?php if(!$rows):?><tr><td colspan="6" class="muted">No waitlist entries match this view.</td></tr><?php endif;?></tbody></table></div><?php module_render_server_pagination($total,$page,$perPage,'page','per_page','waitlist entries');?></div>
<?php if($managedRow&&$canManage):?><dialog id="waitlist-manage" class="wide-dialog" data-auto-open-dialog="waitlist-manage"><form method="dialog"><button type="submit" class="dialog-close">×</button></form><div class="dialog-scroll"><h2><?=e((string)$managedRow['last_name'].', '.(string)$managedRow['first_name'])?></h2><p><?=e((string)$managedRow['service_name'])?> · <?=e(module_status((string)$managedRow['status']))?></p><form method="post" class="form-grid"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="status"><input type="hidden" name="id" value="<?=(int)$managedRow['id']?>"><label>Status<select name="status"><?php foreach(['waiting','offered','declined','cancelled','expired'] as $option):?><option value="<?=e($option)?>" <?=$managedRow['status']===$option?'selected':''?>><?=e(module_status($option))?></option><?php endforeach;?></select></label><label class="wide">Contact note<textarea name="note"></textarea></label><button class="btn primary">Save status</button><?php if(in_array($managedRow['status'],['waiting','offered'],true)):?><a class="btn ghost" href="appointments.php?new=1&amp;waitlist_id=<?=(int)$managedRow['id']?>">Book appointment</a><?php endif;?></form></div></dialog><?php endif;?>
<?php if($canManage):?><dialog id="waitlist-form" class="wide-dialog"><form method="post" class="form-grid"><button type="button" class="dialog-close" data-close>×</button><h2 class="wide">Add patient to waitlist</h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="create"><label class="wide">Patient<div class="remote-patient-picker" data-patient-picker data-endpoint="api/patient_search.php"><input type="search" data-patient-query placeholder="Search patient number, name, mobile, or email" autocomplete="off" required><input type="hidden" name="patient_id" data-patient-id><div class="remote-patient-selection" data-patient-selection hidden></div><div class="remote-patient-results" data-patient-results hidden></div></div></label><label>Service<select name="service_id" required><option value="">Choose service</option><?php foreach($services as $service):?><option value="<?=(int)$service['id']?>"><?=e((string)$service['name'])?><?=service_provider_type($service)==='inhouse'?' · In-house':''?></option><?php endforeach;?></select></label><label>Dentist when no continuity dentist<select name="dentist_user_id"><option value="">Use continuity dentist</option><?php foreach($dentists as $doctor):?><option value="<?=(int)$doctor['id']?>"><?=e((string)$doctor['name'])?></option><?php endforeach;?></select></label><label>Earliest date<input type="date" name="earliest_date" min="<?=date('Y-m-d')?>" value="<?=date('Y-m-d')?>" required></label><label>Latest date<input type="date" name="latest_date" min="<?=date('Y-m-d')?>" value="<?=date('Y-m-d',strtotime('+30 days'))?>" required></label><label>Preferred from<input type="time" name="preferred_time_from"></label><label>Preferred until<input type="time" name="preferred_time_to"></label><label>Priority<select name="priority"><option value="routine">Routine</option><option value="soon">Soon</option><option value="urgent">Urgent</option></select></label><label class="wide">Notes<textarea name="notes" placeholder="Days unavailable, contact preference, or reason for urgency"></textarea></label><button class="btn primary wide">Add to waitlist</button></form></dialog><?php endif;?>
<?php render_footer(); ?>
