<?php

declare(strict_types=1);

require DENTAL_ROOT . '/app/bootstrap.php';
require_login();
require DENTAL_ROOT . '/app/layout.php';
require DENTAL_ROOT . '/app/module_helpers.php';
require_once DENTAL_ROOT . '/app/record_release.php';
require_documentation_schema();

$pdo = db();
$role = active_role();
if (!in_array($role, ['super_admin','clinic_admin','receptionist','staff','dentist','cashier'], true)) {
    access_denied('Patient record-copy requests are outside this Task View.');
}
if (!patient_record_release_schema_ready()) {
    render_header('Patient Record Requests');
    render_module_intro('Patient record requests','Controlled release of patient-safe dental records through the secure portal.');
    echo '<section class="card"><h2>Update required</h2><p>Apply DentalCare v0.9.1.2 before using controlled record release.</p></section>';
    render_footer();
    exit;
}

function rr_request(PDO $pdo, int $id, bool $lock = false): array
{
    $stmt = $pdo->prepare(
        'SELECT rel.*,req.reason,req.staff_note,req.payload_json,req.created_at requested_at,req.status request_status,'
        . 'p.patient_no,p.first_name,p.middle_name,p.last_name,p.branch_id patient_branch_id '
        . 'FROM `' . table('patient_record_releases') . '` rel '
        . 'JOIN `' . table('patient_portal_requests') . '` req ON req.id=rel.request_id '
        . 'JOIN `' . table('patients') . '` p ON p.id=rel.patient_id '
        . 'WHERE rel.id=? LIMIT 1' . ($lock ? ' FOR UPDATE' : '')
    );
    $stmt->execute([$id]);
    $row = $stmt->fetch();
    if (!$row) throw new RuntimeException('Patient record 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 patient is outside the active Task View.');
    return $row;
}

$operationRequest = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    try {
        verify_csrf();
        $releaseId = (int)($_POST['release_id'] ?? 0);
        $action = (string)($_POST['action'] ?? '');
        $note = mb_substr(trim((string)($_POST['note'] ?? '')), 0, 500);
        $operationRequest = operation_integrity_begin($pdo,'record_release',$action,$_POST,'patient_record_release',$releaseId ?: null);
        $pdo->beginTransaction();
        $row = rr_request($pdo, $releaseId, true);
        $scope = (string)$row['release_scope'];
        $status = (string)$row['status'];
        $userId = (int)(current_user()['id'] ?? 0);

        if ($action === 'identity_verify') {
            if (!patient_record_release_can_receive()) throw new RuntimeException('This Task View cannot verify record-request identity.');
            if ($status !== 'pending_identity') throw new RuntimeException('Identity verification is no longer pending.');
            if ($note === '') throw new RuntimeException('Record how identity and authority were verified.');
            $next = $scope === 'financial' ? 'approved' : 'pending_clinical';
            $pdo->prepare('UPDATE `' . table('patient_record_releases') . '` SET status=?,identity_verified_by=?,identity_verified_at=NOW(),updated_at=NOW() WHERE id=? AND status="pending_identity"')
                ->execute([$next,$userId,$releaseId]);
            $pdo->prepare('UPDATE `' . table('patient_portal_requests') . '` SET status=?,staff_note=?,updated_at=NOW() WHERE id=?')
                ->execute([$next,$note,(int)$row['request_id']]);
            audit_required('patient_record_identity_verified','patient_record_release',$releaseId,['patient_id'=>(int)$row['patient_id'],'scope'=>$scope,'next_status'=>$next,'note'=>$note]);
            $pdo->commit();
            operation_integrity_complete($pdo,$operationRequest,['entity_type'=>'patient_record_release','entity_id'=>$releaseId,'redirect'=>'record_requests.php']);
            module_return('record_requests.php','success',$scope === 'financial' ? 'Identity verified. The financial copy is ready for authorized release.' : 'Identity verified. The request is waiting for Dentist approval.');
        }

        if ($action === 'clinical_approve') {
            if (!patient_record_release_can_clinically_approve()) throw new RuntimeException('Only a Dentist Task View can approve clinical content for release.');
            if ($scope === 'financial') throw new RuntimeException('Financial-only copies do not require clinical approval.');
            if ($status !== 'pending_clinical') throw new RuntimeException('This request is not waiting for Dentist approval.');
            if ($note === '') throw new RuntimeException('Record the Dentist release review.');
            $pdo->prepare('UPDATE `' . table('patient_record_releases') . '` SET status="approved",clinical_approved_by=?,clinical_approved_at=NOW(),updated_at=NOW() WHERE id=? AND status="pending_clinical"')
                ->execute([$userId,$releaseId]);
            $pdo->prepare('UPDATE `' . table('patient_portal_requests') . '` SET status="approved",staff_note=?,updated_at=NOW() WHERE id=?')
                ->execute([$note,(int)$row['request_id']]);
            audit_required('patient_record_clinical_release_approved','patient_record_release',$releaseId,['patient_id'=>(int)$row['patient_id'],'scope'=>$scope,'note'=>$note]);
            $pdo->commit();
            operation_integrity_complete($pdo,$operationRequest,['entity_type'=>'patient_record_release','entity_id'=>$releaseId,'redirect'=>'record_requests.php']);
            module_return('record_requests.php','success','The Dentist approved the finalized dental content. An Administrator can now release it to the patient portal.');
        }

        if ($action === 'release') {
            if (!patient_record_release_can_release($scope)) throw new RuntimeException('This Task View cannot release this type of record.');
            if ($status !== 'approved') throw new RuntimeException('This request has not completed the required approval steps.');
            $expiresAt = date('Y-m-d H:i:s', strtotime('+30 days'));
            $pdo->prepare('UPDATE `' . table('patient_record_releases') . '` SET status="released",released_by=?,released_at=NOW(),expires_at=?,updated_at=NOW() WHERE id=? AND status="approved"')
                ->execute([$userId,$expiresAt,$releaseId]);
            $pdo->prepare('UPDATE `' . table('patient_portal_requests') . '` SET status="completed",staff_note=?,resolved_by=?,resolved_at=NOW(),updated_at=NOW() WHERE id=?')
                ->execute([$note !== '' ? $note : 'Approved dental-record copy released through the secure patient portal.',$userId,(int)$row['request_id']]);
            audit_required('patient_record_released_to_portal','patient_record_release',$releaseId,['patient_id'=>(int)$row['patient_id'],'scope'=>$scope,'expires_at'=>$expiresAt]);
            $pdo->commit();
            operation_integrity_complete($pdo,$operationRequest,['entity_type'=>'patient_record_release','entity_id'=>$releaseId,'redirect'=>'record_requests.php']);
            module_return('record_requests.php','success','The approved record copy is now available in the patient portal for 30 days.');
        }

        if ($action === 'decline') {
            $allowed = ($status === 'pending_identity' && patient_record_release_can_receive())
                || ($status === 'pending_clinical' && patient_record_release_can_clinically_approve())
                || ($status === 'approved' && patient_record_release_can_release($scope));
            if (!$allowed) throw new RuntimeException('This Task View cannot decline the request at its current stage.');
            if ($note === '') throw new RuntimeException('Enter the reason and patient guidance.');
            $pdo->prepare('UPDATE `' . table('patient_record_releases') . '` SET status="declined",updated_at=NOW() WHERE id=?')->execute([$releaseId]);
            $pdo->prepare('UPDATE `' . table('patient_portal_requests') . '` SET status="declined",staff_note=?,resolved_by=?,resolved_at=NOW(),updated_at=NOW() WHERE id=?')
                ->execute([$note,$userId,(int)$row['request_id']]);
            audit_required('patient_record_release_declined','patient_record_release',$releaseId,['patient_id'=>(int)$row['patient_id'],'scope'=>$scope,'note'=>$note]);
            $pdo->commit();
            operation_integrity_complete($pdo,$operationRequest,['entity_type'=>'patient_record_release','entity_id'=>$releaseId,'redirect'=>'record_requests.php']);
            module_return('record_requests.php','success','The request was declined and the reason is visible to the patient.');
        }

        if ($action === 'revoke') {
            if (!in_array($role, ['super_admin','clinic_admin'], true) || !task_context_action_allowed('records.release.manage') || !can('records.release.manage')) throw new RuntimeException('Only an Administrator can revoke a released clinical record copy.');
            if ($status !== 'released') throw new RuntimeException('Only an active released copy can be revoked.');
            if ($note === '') throw new RuntimeException('Enter the revocation reason.');
            $pdo->prepare('UPDATE `' . table('patient_record_releases') . '` SET status="revoked",revoked_by=?,revoked_at=NOW(),revocation_reason=?,updated_at=NOW() WHERE id=? AND status="released"')
                ->execute([$userId,$note,$releaseId]);
            audit_required('patient_record_release_revoked','patient_record_release',$releaseId,['patient_id'=>(int)$row['patient_id'],'scope'=>$scope,'reason'=>$note]);
            $pdo->commit();
            operation_integrity_complete($pdo,$operationRequest,['entity_type'=>'patient_record_release','entity_id'=>$releaseId,'redirect'=>'record_requests.php']);
            module_return('record_requests.php','success','Portal access to this released copy has been revoked.');
        }

        throw new RuntimeException('Unsupported record-release action.');
    } catch (Throwable $exception) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        operation_integrity_fail($pdo,$operationRequest,$exception);
        module_return('record_requests.php','error',$exception->getMessage());
    }
}

$status = trim((string)($_GET['status'] ?? 'active'));
$validStatuses = ['active','pending_identity','pending_clinical','approved','released','declined','revoked','all'];
if (!in_array($status,$validStatuses,true)) $status='active';
$scopeFilter = trim((string)($_GET['scope'] ?? ''));
if ($scopeFilter !== '' && !array_key_exists($scopeFilter,patient_record_scope_options())) $scopeFilter='';
$q = trim((string)($_GET['q'] ?? ''));
$page = module_page_number();
$perPage = module_page_size('per_page',25);
$where = ['1=1'];
$args = [];
if ($status === 'active') $where[] = 'rel.status IN ("pending_identity","pending_clinical","approved")';
elseif ($status !== 'all') { $where[]='rel.status=?'; $args[]=$status; }
if ($scopeFilter !== '') { $where[]='rel.release_scope=?'; $args[]=$scopeFilter; }
if ($q !== '') { $like='%'.$q.'%'; $where[]='(p.patient_no LIKE ? OR p.first_name LIKE ? OR p.last_name LIKE ? OR req.reason LIKE ?)'; array_push($args,$like,$like,$like,$like); }
if (!superuser_primary_workspace()) {
    $branchId = integrity_user_branch_id();
    if ($branchId > 0) { $where[]='p.branch_id=?'; $args[]=$branchId; } else $where[]='1=0';
}
[$scopeSql,$scopeArgs] = task_patient_scope_condition('rel.patient_id');
if ($scopeSql !== '') { $where[] = ltrim(preg_replace('/^\s*AND\s+/i','',$scopeSql) ?? $scopeSql); $args=array_merge($args,$scopeArgs); }
$whereSql = implode(' AND ',$where);
$from = ' FROM `' . table('patient_record_releases') . '` rel JOIN `' . table('patient_portal_requests') . '` req ON req.id=rel.request_id JOIN `' . table('patients') . '` p ON p.id=rel.patient_id LEFT JOIN `' . table('users') . '` iu ON iu.id=rel.identity_verified_by LEFT JOIN `' . table('users') . '` cu ON cu.id=rel.clinical_approved_by LEFT JOIN `' . table('users') . '` ru ON ru.id=rel.released_by';
$countStmt=$pdo->prepare('SELECT COUNT(*)'.$from.' WHERE '.$whereSql);$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 rel.*,req.reason,req.staff_note,req.created_at requested_at,p.patient_no,p.first_name,p.middle_name,p.last_name,p.branch_id patient_branch_id,iu.name identity_user,cu.name clinical_user,ru.name release_user'.$from.' WHERE '.$whereSql.' ORDER BY CASE rel.status WHEN "pending_identity" THEN 0 WHEN "pending_clinical" THEN 1 WHEN "approved" THEN 2 ELSE 3 END,rel.created_at DESC LIMIT '.$perPage.' OFFSET '.$offset);
$stmt->execute($args);$rows=$stmt->fetchAll();

render_header('Patient Record Requests');
render_module_intro('Patient record requests','Verify identity, obtain Dentist approval for clinical content, and release a patient-safe copy through the secure portal.');
?>
<section class="stats mini-stats"><?php stat_card('Active',$status==='active'?$total:'—','Approval workflow');stat_card('Role',role_profile()['name'],'Current Task View');?></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"></label>
<label>Status<select name="status"><?php foreach(['active'=>'Active workflow','pending_identity'=>'Identity review','pending_clinical'=>'Dentist approval','approved'=>'Ready to release','released'=>'Released','declined'=>'Declined','revoked'=>'Revoked','all'=>'All'] as $value=>$label):?><option value="<?=e($value)?>" <?=$status===$value?'selected':''?>><?=e($label)?></option><?php endforeach;?></select></label>
<label>Copy type<select name="scope"><option value="">All copy types</option><?php foreach(patient_record_scope_options() as $value=>$label):?><option value="<?=e($value)?>" <?=$scopeFilter===$value?'selected':''?>><?=e($label)?></option><?php endforeach;?></select></label>
<button class="btn primary">Apply</button><a class="btn ghost" href="record_requests.php">Reset</a></form>
<div class="card server-list-card"><?php module_render_server_pagination($total,$page,$perPage,'page','per_page','record-requests');?><div class="table-wrap"><table><thead><tr><th>Requested</th><th>Patient</th><th>Copy</th><th>Approval trail</th><th>Status</th><th>Authorized action</th></tr></thead><tbody>
<?php foreach($rows as $row):$scope=(string)$row['release_scope'];$statusValue=(string)$row['status'];$name=trim((string)$row['first_name'].' '.(string)$row['middle_name'].' '.(string)$row['last_name']);?>
<tr><td><strong><?=e(date('M j, Y',strtotime((string)$row['requested_at'])))?></strong><small><?=e(date('g:i A',strtotime((string)$row['requested_at'])))?></small></td>
<td><strong><?=e($name)?></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_record_scope_label($scope))?></strong><?php if(!empty($row['date_from'])||!empty($row['date_to'])):?><small><?=e((string)($row['date_from']?:'Beginning'))?> to <?=e((string)($row['date_to']?:'Present'))?></small><?php endif;?><small><?=e((string)($row['reason']?:'Patient requested a copy'))?></small></td>
<td><?php if($row['identity_verified_at']):?><small>Identity: <?=e((string)($row['identity_user']?:'Verified staff'))?> · <?=e(date('M j, g:i A',strtotime((string)$row['identity_verified_at'])))?></small><?php else:?><small class="muted">Identity not yet verified</small><?php endif;?><?php if($row['clinical_approved_at']):?><small>Dentist: <?=e((string)($row['clinical_user']?:'Approved Dentist'))?> · <?=e(date('M j, g:i A',strtotime((string)$row['clinical_approved_at'])))?></small><?php endif;?><?php if($row['released_at']):?><small>Released: <?=e((string)($row['release_user']?:'Authorized staff'))?> · <?=e(date('M j, g:i A',strtotime((string)$row['released_at'])))?></small><?php endif;?></td>
<td><span class="badge"><?=e(patient_record_release_status_label($statusValue))?></span><?php if($statusValue==='released'&&!empty($row['expires_at'])):?><small>Expires <?=e(date('M j, Y',strtotime((string)$row['expires_at'])))?></small><?php endif;?><?php if($statusValue==='released'):?><small>Viewed <?=(int)$row['view_count']?> time<?=((int)$row['view_count']===1?'':'s')?></small><?php endif;?></td>
<td><div class="stacked-actions">
<?php if($statusValue==='pending_identity'&&patient_record_release_can_receive()):?><form method="post" class="inline-review-form"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="release_id" value="<?=(int)$row['id']?>"><input type="hidden" name="action" value="identity_verify"><input name="note" required placeholder="Identity verification method"><button class="btn primary compact">Verify identity</button></form><?php endif;?>
<?php if($statusValue==='pending_clinical'&&patient_record_release_can_clinically_approve()):?><form method="post" class="inline-review-form"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="release_id" value="<?=(int)$row['id']?>"><input type="hidden" name="action" value="clinical_approve"><input name="note" required placeholder="Finalized-content review"><button class="btn primary compact">Approve clinical copy</button></form><?php endif;?>
<?php if($statusValue==='approved'&&patient_record_release_can_release($scope)):?><form method="post" class="inline-review-form"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="release_id" value="<?=(int)$row['id']?>"><input type="hidden" name="action" value="release"><input name="note" placeholder="Optional patient guidance"><button class="btn primary compact">Release to portal</button></form><?php endif;?>
<?php if(in_array($statusValue,['pending_identity','pending_clinical','approved'],true)): $mayDecline=($statusValue==='pending_identity'&&patient_record_release_can_receive())||($statusValue==='pending_clinical'&&patient_record_release_can_clinically_approve())||($statusValue==='approved'&&patient_record_release_can_release($scope));if($mayDecline):?><form method="post" class="inline-review-form"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="release_id" value="<?=(int)$row['id']?>"><input type="hidden" name="action" value="decline"><input name="note" required placeholder="Reason and guidance"><button class="btn danger compact">Decline</button></form><?php endif;endif;?>
<?php if($statusValue==='released'&&in_array($role,['super_admin','clinic_admin'],true)&&task_context_action_allowed('records.release.manage')&&can('records.release.manage')):?><form method="post" class="inline-review-form"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="release_id" value="<?=(int)$row['id']?>"><input type="hidden" name="action" value="revoke"><input name="note" required placeholder="Revocation reason"><button class="btn danger compact">Revoke access</button></form><?php endif;?>
<?php if(!in_array($statusValue,['pending_identity','pending_clinical','approved','released'],true)):?><span class="muted">No action available</span><?php endif;?></div></td></tr>
<?php endforeach;?><?php if(!$rows):?><tr><td colspan="6" class="muted">No record-copy requests match this view.</td></tr><?php endif;?></tbody></table></div><?php module_render_server_pagination($total,$page,$perPage,'page','per_page','record-requests');?></div>
<?php render_footer(); ?>
