<?php

declare(strict_types=1);

require DENTAL_ROOT . '/app/bootstrap.php';
require_login();
require_permission('appointments.manage',['super_admin','clinic_admin','receptionist','staff','dentist']);
require DENTAL_ROOT . '/app/layout.php';
require DENTAL_ROOT . '/app/module_helpers.php';
require_once DENTAL_ROOT . '/app/transaction_integrity.php';

$pdo = db();
$canManage = task_context_action_allowed('appointments.manage') && has_role(['super_admin','clinic_admin','receptionist','staff']);
$canVerifyMedical = active_role()==='dentist' && has_role('dentist');
if (!patient_portal_request_schema_ready()) {
    render_header('Patient Portal Requests');
    render_module_intro('Patient portal requests','Review patient-submitted reschedule and dental-safety information requests.');
    echo '<section class="card"><h2>Update required</h2><p>Version 0.5.8.6 must be applied before this workspace can be used.</p>';
    if(actual_role()==='super_admin')echo '<a class="btn primary" href="system_setup.php?tab=updates">Open System Control updates</a>';
    else echo '<p class="muted">Ask the Superuser to apply the pending database update.</p>';
    echo '</section>';
    render_footer();
    exit;
}

function portal_staff_request(PDO $pdo, int $id, bool $lock = false): array
{
    $stmt = $pdo->prepare(
        'SELECT r.*,CONCAT(p.first_name," ",p.last_name) patient,p.patient_no,p.branch_id patient_branch_id,p.medical_alerts,'
        . 'a.start_at appointment_start,a.service_name,a.status appointment_status '
        . 'FROM `' . table('patient_portal_requests') . '` r '
        . 'JOIN `' . table('patients') . '` p ON p.id=r.patient_id '
        . 'LEFT JOIN `' . table('appointments') . '` a ON a.id=r.appointment_id '
        . 'WHERE r.id=? LIMIT 1' . ($lock ? ' FOR UPDATE' : '')
    );
    $stmt->execute([$id]);
    $row = $stmt->fetch();
    if (!$row) throw new RuntimeException('Patient portal request not found.');
    if (!integrity_branch_scope_allowed(null,(int)$row['patient_branch_id'])) throw new RuntimeException('This request belongs to another clinic branch.');
    if (!task_patient_scope_allowed((int)$row['patient_id'])) throw new RuntimeException('This request is outside the active task workspace.');
    return $row;
}

function portal_staff_payload(array $request): array
{
    $payload = json_decode((string)($request['payload_json'] ?? ''), true);
    return is_array($payload) ? $payload : [];
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    try {
        verify_csrf();
        require_task_action('appointments.manage');
        $requestId=(int)($_POST['request_id'] ?? 0);
        $pdo->beginTransaction();
        $request = portal_staff_request($pdo,$requestId,true);
        $action = (string)($_POST['action'] ?? '');
        $note = trim((string)($_POST['staff_note'] ?? ''));
        if ((string)$request['status'] !== 'pending') throw new RuntimeException('This request has already been resolved.');

        if ($action === 'approve_medical') {
            if (!$canVerifyMedical) throw new RuntimeException('Only a signed-in dentist can clinically verify a patient-reported medical update.');
            if ((string)$request['request_type'] !== 'medical_history_update') throw new RuntimeException('This action is only available for dental-safety information updates.');
            if ($note === '') throw new RuntimeException('Record how the dentist verified this dental-safety information update.');
            $payload = portal_staff_payload($request);
            $values = [
                'allergies'=>trim((string)($payload['allergies'] ?? '')),
                'medications'=>trim((string)($payload['medications'] ?? '')),
                'conditions'=>trim((string)($payload['conditions'] ?? '')),
                'dental_history'=>trim((string)($payload['dental_history'] ?? '')),
            ];
            integrity_insert_verified_medical_history($pdo,(int)$request['patient_id'],$values,(int)current_user()['id'],$note);
            $summary = integrity_medical_alert_summary($values);
            $pdo->prepare('UPDATE `' . table('patients') . '` SET medical_alerts=?,updated_at=NOW() WHERE id=?')->execute([$summary,(int)$request['patient_id']]);
            $update=$pdo->prepare('UPDATE `' . table('patient_portal_requests') . '` SET status="completed",staff_note=?,resolved_by=?,resolved_at=NOW(),updated_at=NOW() WHERE id=? AND status="pending"');
            $update->execute([$note !== '' ? $note : 'Verified by the treating dentist and saved as a new dental-safety history version.',(int)current_user()['id'],(int)$request['id']]);
            if($update->rowCount()!==1)throw new RuntimeException('This request was resolved by another user.');
            workflow_event((int)$request['patient_id'],'medical_update_verified','Portal medical update verified',['portal_request_id'=>(int)$request['id']],$note ?: 'Verified by dentist.');
            audit('patient_portal_medical_update_approved','patient_portal_request',(int)$request['id'],['patient_id'=>(int)$request['patient_id'],'verified_by'=>(int)current_user()['id']]);
            $pdo->commit();
            module_return('portal_requests.php','success','The dentist verified the dental-safety information and saved a new version.');
        }

        if ($action === 'decline') {
            $isMedicalUpdate=(string)$request['request_type']==='medical_history_update';
            if ($isMedicalUpdate && !$canVerifyMedical) throw new RuntimeException('Only a signed-in dentist can clinically decline a patient-reported medical update.');
            if (!$isMedicalUpdate && !$canManage) throw new RuntimeException('The active role cannot decline this portal request.');
            if ($note === '') throw new RuntimeException('Enter the reason or guidance that will be retained with the request.');
            $pdo->prepare('UPDATE `' . table('patient_portal_requests') . '` SET status="declined",staff_note=?,resolved_by=?,resolved_at=NOW(),updated_at=NOW() WHERE id=?')
                ->execute([$note,(int)current_user()['id'],(int)$request['id']]);
            workflow_event((int)$request['patient_id'],'portal_request_declined','Patient portal request declined',['portal_request_id'=>(int)$request['id']],$note);
            audit('patient_portal_request_declined','patient_portal_request',(int)$request['id'],['request_type'=>$request['request_type'],'patient_id'=>(int)$request['patient_id'],'note'=>$note]);
            $pdo->commit();
            module_return('portal_requests.php','success','The request was declined and the clinic note was recorded.');
        }


        throw new RuntimeException('Unsupported request action.');
    } catch (Throwable $exception) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        module_return('portal_requests.php','error',$exception->getMessage());
    }
}

$status = (string)($_GET['status'] ?? 'pending');
if (!in_array($status,['pending','completed','declined','all'],true)) $status='pending';
$type = (string)($_GET['type'] ?? '');
if (!in_array($type,['appointment_reschedule','medical_history_update','appointment_confirm','appointment_cancel','followup_booking'],true)) $type='';
$q = trim((string)($_GET['q'] ?? ''));
$page = module_page_number();
$perPage = module_page_size('per_page',25);

$from = ' FROM `' . table('patient_portal_requests') . '` r JOIN `' . table('patients') . '` p ON p.id=r.patient_id LEFT JOIN `' . table('appointments') . '` a ON a.id=r.appointment_id LEFT JOIN `' . table('users') . '` u ON u.id=r.resolved_by';
$where = ' WHERE r.request_type<>"record_copy"';
$args=[];
$userBranchId=integrity_user_branch_id();
if(active_role()!=='super_admin'&&$userBranchId>0){$where.=' AND p.branch_id=?';$args[]=$userBranchId;}
if ($status !== 'all') { $where .= ' AND r.status=?'; $args[]=$status; }
if ($canVerifyMedical && !$canManage) { $where .= ' AND r.request_type="medical_history_update"'; }
if ($type !== '') { $where .= ' AND r.request_type=?'; $args[]=$type; }
if ($q !== '') { $like='%'.$q.'%'; $where .= ' AND (p.patient_no LIKE ? OR p.first_name LIKE ? OR p.last_name LIKE ? OR r.reason LIKE ?)'; array_push($args,$like,$like,$like,$like); }
[$scopeSql,$scopeArgs] = task_patient_scope_condition('r.patient_id');
$where .= $scopeSql;
$args = array_merge($args,$scopeArgs);
$count=$pdo->prepare('SELECT COUNT(*)'.$from.$where);$count->execute($args);$total=(int)$count->fetchColumn();
$pages=max(1,(int)ceil($total/$perPage));$page=min($page,$pages);$offset=($page-1)*$perPage;
$stmt=$pdo->prepare('SELECT r.*,CONCAT(p.first_name," ",p.last_name) patient,p.patient_no,p.branch_id patient_branch_id,a.start_at appointment_start,a.service_name,a.status appointment_status,u.name resolved_by_name'.$from.$where.' ORDER BY CASE WHEN r.status="pending" THEN 0 ELSE 1 END,r.created_at DESC,r.id DESC LIMIT '.$perPage.' OFFSET '.$offset);
$stmt->execute($args);$rows=$stmt->fetchAll();
$manageId=max(0,(int)($_GET['manage_id']??0));$managedRequest=null;if($manageId>0){$manageStmt=$pdo->prepare('SELECT r.*,CONCAT(p.first_name," ",p.last_name) patient,p.patient_no,p.branch_id patient_branch_id,a.start_at appointment_start,a.service_name,a.status appointment_status,u.name resolved_by_name'.$from.' WHERE r.id=? LIMIT 1');$manageStmt->execute([$manageId]);$candidate=$manageStmt->fetch();if($candidate){require_patient((int)$candidate['patient_id']);$managedRequest=$candidate;}}

$pendingSql='SELECT COUNT(*) FROM `' . table('patient_portal_requests') . '` r JOIN `' . table('patients') . '` p ON p.id=r.patient_id WHERE r.status="pending" AND r.request_type<>"record_copy"';$pendingArgs=[];
if($canVerifyMedical&&!$canManage)$pendingSql.=' AND r.request_type="medical_history_update"';
if(active_role()!=='super_admin'&&$userBranchId>0){$pendingSql.=' AND p.branch_id=?';$pendingArgs[]=$userBranchId;}
[$pendingScopeSql,$pendingScopeArgs]=task_patient_scope_condition('r.patient_id');$pendingSql.=$pendingScopeSql;$pendingArgs=array_merge($pendingArgs,$pendingScopeArgs);
$pendingStmt=$pdo->prepare($pendingSql);$pendingStmt->execute($pendingArgs);$pendingCount=(int)$pendingStmt->fetchColumn();
render_header('Patient Portal Requests');
render_module_intro('Patient portal requests','Review patient reschedule preferences, verify health changes relevant to dental care, and retain a complete decision trail.');
?>
<section class="stats mini-stats"><?php stat_card('Pending',$pendingCount,'Needs clinic action');stat_card('This view',$total,ucfirst($status));?></section>
<form method="get" class="card compact-filter" data-auto-submit><label>Search<input type="search" name="q" value="<?=e($q)?>" placeholder="Patient, number, or reason" data-auto-search data-min-length="2"></label><label>Status<select name="status"><option value="pending" <?=$status==='pending'?'selected':''?>>Pending</option><option value="completed" <?=$status==='completed'?'selected':''?>>Completed</option><option value="declined" <?=$status==='declined'?'selected':''?>>Declined</option><option value="all" <?=$status==='all'?'selected':''?>>All</option></select></label><label>Request type<select name="type"><option value="">All request types</option><?php foreach(['appointment_reschedule','medical_history_update','appointment_confirm','appointment_cancel','followup_booking'] as $option):?><option value="<?=e($option)?>" <?=$type===$option?'selected':''?>><?=e(patient_portal_request_type_label($option))?></option><?php endforeach;?></select></label><?php if($q!==''||$status!=='pending'||$type!==''):?><a class="btn link" href="portal_requests.php">Clear</a><?php endif;?></form>
<div class="card server-list-card"><?php module_render_server_pagination($total,$page,$perPage,'page','per_page','portal_requests');?><div class="table-wrap" data-no-pagination><table data-no-pagination="true"><thead><tr><th>Submitted</th><th>Patient</th><th>Request</th><th>Preferred schedule / details</th><th>Status</th><th>Clinic action</th></tr></thead><tbody>
<?php foreach($rows as $row):$payload=portal_staff_payload($row);?>
<tr><td><?=e(date('M j, Y g:i A',strtotime((string)$row['created_at'])))?></td><td><strong><?=e((string)$row['patient'])?></strong><small><?=e((string)$row['patient_no'])?></small><a href="patients.php?action=view&amp;id=<?=(int)$row['patient_id']?>">Open patient</a></td><td><strong><?=e(patient_portal_request_type_label((string)$row['request_type']))?></strong><small><?=e((string)$row['reason'])?></small><?php if($row['appointment_id']):?><small><?=e((string)($row['service_name']?:'Appointment'))?><?php if($row['appointment_start']):?> · <?=e(date('M j, Y g:i A',strtotime((string)$row['appointment_start'])))?><?php endif;?></small><?php endif;?></td>
<td><?php if((string)$row['request_type']==='appointment_reschedule'):?><strong><?=e($row['preferred_date']?date('M j, Y',strtotime((string)$row['preferred_date'])):'No date')?></strong><small><?=e($row['preferred_time_from']?date('g:i A',strtotime((string)$row['preferred_time_from'])):'Any time')?><?=!empty($row['preferred_time_to'])?'–'.e(date('g:i A',strtotime((string)$row['preferred_time_to']))):''?></small><?php elseif((string)$row['request_type']==='medical_history_update'):?><details><summary>Review submitted health information</summary><dl class="portal-request-detail"><dt>Allergies</dt><dd><?=nl2br(e((string)($payload['allergies']??'None stated')))?></dd><dt>Medicines</dt><dd><?=nl2br(e((string)($payload['medications']??'None stated')))?></dd><dt>Conditions</dt><dd><?=nl2br(e((string)($payload['conditions']??'None stated')))?></dd><dt>Dental history</dt><dd><?=nl2br(e((string)($payload['dental_history']??'None stated')))?></dd></dl></details><?php elseif($row['requested_start_at']):?><strong><?=e(date('M j, Y g:i A',strtotime((string)$row['requested_start_at'])))?></strong><?php else:?><span class="muted">Automatically completed patient action</span><?php endif;?></td>
<td><span class="badge"><?=e(module_status((string)$row['status']))?></span><?php if($row['resolved_by_name']):?><small><?=e((string)$row['resolved_by_name'])?> · <?=e(date('M j, Y g:i A',strtotime((string)$row['resolved_at'])))?></small><?php endif;?><?php if($row['staff_note']):?><small><?=e((string)$row['staff_note'])?></small><?php endif;?></td>
<td><?php if(($canManage||$canVerifyMedical)&&(string)$row['status']==='pending'):?><div class="inline-actions"><?php if((string)$row['request_type']==='appointment_reschedule'&&!empty($row['appointment_id'])):?><a class="btn primary compact" href="appointments.php?edit_id=<?=(int)$row['appointment_id']?>&amp;portal_request_id=<?=(int)$row['id']?>">Review schedule</a><?php endif;?><?php $mayManage=((string)$row['request_type']==='medical_history_update')?$canVerifyMedical:$canManage;if($mayManage):?><a class="btn ghost" href="<?=e(module_management_url(['manage_id'=>(int)$row['id'],'page'=>$page,'per_page'=>$perPage]))?>">Manage</a><?php elseif((string)$row['request_type']==='medical_history_update'):?><small class="muted">Awaiting Dentist verification.</small><?php endif;?></div><?php else:?><span class="muted">No action required</span><?php endif;?></td></tr></tr>
<?php endforeach;?><?php if(!$rows):?><tr><td colspan="6">No patient portal requests match this view.</td></tr><?php endif;?></tbody></table></div><?php module_render_server_pagination($total,$page,$perPage,'page','per_page','portal_requests');?></div>
<?php if($managedRequest&&($canManage||$canVerifyMedical)&&(string)$managedRequest['status']==='pending'):$managedPayload=portal_staff_payload($managedRequest);$mayDecline=((string)$managedRequest['request_type']==='medical_history_update')?$canVerifyMedical:$canManage;?><dialog id="portal-request-manage" class="wide-dialog" data-auto-open-dialog="portal-request-manage"><form method="dialog"><button type="submit" class="dialog-close">×</button></form><div class="dialog-scroll"><h2><?=e(patient_portal_request_type_label((string)$managedRequest['request_type']))?></h2><p><strong><?=e((string)$managedRequest['patient'])?></strong> · <?=e((string)$managedRequest['patient_no'])?></p><div class="notice info"><?=e((string)$managedRequest['reason'])?></div><?php if((string)$managedRequest['request_type']==='medical_history_update'):?><dl class="portal-request-detail"><dt>Allergies</dt><dd><?=nl2br(e((string)($managedPayload['allergies']??'None stated')))?></dd><dt>Medicines</dt><dd><?=nl2br(e((string)($managedPayload['medications']??'None stated')))?></dd><dt>Conditions</dt><dd><?=nl2br(e((string)($managedPayload['conditions']??'None stated')))?></dd><dt>Dental history</dt><dd><?=nl2br(e((string)($managedPayload['dental_history']??'None stated')))?></dd></dl><?php endif;?><?php if((string)$managedRequest['request_type']==='medical_history_update'&&$canVerifyMedical):?><form method="post" class="form-grid"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="approve_medical"><input type="hidden" name="request_id" value="<?=(int)$managedRequest['id']?>"><label class="wide">Dental-safety verification method, findings, and note<textarea name="staff_note" required></textarea></label><button class="btn primary" data-confirm="Save this as a new verified dental-safety history version?">Approve verified update</button></form><?php endif;?><?php if($mayDecline):?><hr><form method="post" class="form-grid"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="request_id" value="<?=(int)$managedRequest['id']?>"><label class="wide">Decline reason and patient guidance<textarea name="staff_note" required></textarea></label><button class="btn danger" name="action" value="decline" data-confirm="Decline this patient request?">Decline request</button></form><?php endif;?></div></dialog><?php endif;?>
<?php render_footer(); ?>
