<?php

declare(strict_types=1);

require DENTAL_ROOT . '/app/bootstrap.php';
require_login();
require_documentation_schema();
require_permission('clinical.view',['super_admin','clinic_admin','dentist']);
require DENTAL_ROOT . '/app/layout.php';
require DENTAL_ROOT . '/app/module_helpers.php';
require_once DENTAL_ROOT . '/app/medicine_catalog.php';
require_once DENTAL_ROOT . '/app/clinical_safety.php';

$pdo=db();
$canEdit=clinical_record_edit_allowed(['dentist']);
$schemaReady=schema_column_exists(table('prescriptions'),'prescription_hash')&&schema_column_exists(table('prescription_items'),'indication')&&clinical_safety_schema_ready();
$catalogReady=medicine_catalog_schema_ready();
$patients=patient_options();
$patientId=(int)($_GET['patient_id']??$_POST['patient_id']??0);
if($patientId)require_patient($patientId);

function prescription_safety_preview_key(int $patientId, int $userId): string
{
    return 'standalone_rx_safety_' . max(0,$userId) . '_' . max(0,$patientId);
}

function prescription_safety_store_preview(int $patientId, int $userId, array $items, array $assessment, array $fields): void
{
    $_SESSION[prescription_safety_preview_key($patientId,$userId)] = [
        'items'=>$items,'assessment'=>$assessment,'fields'=>$fields,'stored_at'=>time(),
    ];
}

function prescription_safety_get_preview(int $patientId, int $userId): ?array
{
    if($patientId<1||$userId<1)return null;
    $key=prescription_safety_preview_key($patientId,$userId);
    $preview=$_SESSION[$key]??null;
    if(!is_array($preview))return null;
    if((int)($preview['stored_at']??0)<time()-3600){unset($_SESSION[$key]);return null;}
    return $preview;
}

function prescription_safety_clear_preview(int $patientId, int $userId): void
{
    if($patientId>0&&$userId>0)unset($_SESSION[prescription_safety_preview_key($patientId,$userId)]);
}

function prescription_post_items(): array
{
    $fields=['medication_name','generic_name','indication','strength','dosage','frequency','route','duration_days','quantity','instructions'];
    $values=[];foreach($fields as $field)$values[$field]=(array)($_POST[$field]??[]);
    $rows=[];
    foreach($values['medication_name'] as $i=>$name){
        $name=trim((string)$name);if($name==='')continue;
        $duration=trim((string)($values['duration_days'][$i]??''));
        $row=['medication_name'=>$name,'generic_name'=>trim((string)($values['generic_name'][$i]??''))?:null,'indication'=>trim((string)($values['indication'][$i]??''))?:null,'strength'=>trim((string)($values['strength'][$i]??''))?:null,'dosage'=>trim((string)($values['dosage'][$i]??''))?:null,'frequency'=>trim((string)($values['frequency'][$i]??''))?:null,'route'=>trim((string)($values['route'][$i]??''))?:null,'duration_days'=>$duration!==''?max(1,(int)$duration):null,'quantity'=>trim((string)($values['quantity'][$i]??''))?:null,'instructions'=>trim((string)($values['instructions'][$i]??''))?:null];
        foreach(['indication','strength','dosage','frequency','route','duration_days','quantity','instructions'] as $required){
            if(empty($row[$required]))throw new RuntimeException('Complete '.$required.' for '.$name.'.');
        }
        $rows[]=$row;
    }
    return $rows;
}

$operationRequest = null;
$operationEntityId = 0;
if($_SERVER['REQUEST_METHOD']==='POST'){
    try{
        verify_csrf();
        if(!$schemaReady)throw new RuntimeException('Apply Version 0.5.9.6 before issuing or cancelling prescriptions.');
        require_clinical_record_editor(['dentist']);
        $dentistId=(int)(current_user()['id']??0);
        require_dentist_clinical_privilege($dentistId,'prescription');
        require_dentist_credentials_verified($dentistId);
        $action=(string)($_POST['action']??'issue');
        if (in_array($action, ['issue','cancel'], true)) {
            $operationRequest = operation_integrity_begin(
                $pdo,
                'prescriptions',
                $action,
                $_POST,
                'prescription',
                (int)($_POST['id'] ?? 0) ?: null
            );
        }

        if($action==='review_safety'){
            $patientId=(int)($_POST['patient_id']??0);require_patient($patientId);$encounterId=(int)($_POST['encounter_id']??0);
            if($encounterId){$encounter=module_require_encounter_scope($pdo,$encounterId,false,true);if((int)$encounter['patient_id']!==$patientId)throw new RuntimeException('The encounter does not belong to the selected patient.');}
            $items=prescription_post_items();if(!$items)throw new RuntimeException('Add at least one medicine.');
            $items=medicine_catalog_bind_posted_items($pdo,$items,$dentistId,false);
            $assessment=clinical_safety_evaluate_prescription($pdo,$patientId,$items);
            prescription_safety_store_preview($patientId,$dentistId,$items,$assessment,[
                'encounter_id'=>$encounterId,'clinical_indication'=>(string)($_POST['clinical_indication']??''),
                'notes'=>(string)($_POST['notes']??''),'allergy_review_acknowledged'=>isset($_POST['allergy_review_acknowledged']),
                'prescription_safety_acknowledged'=>isset($_POST['prescription_safety_acknowledged']),
                'prescription_safety_override_reason'=>(string)($_POST['prescription_safety_override_reason']??''),
            ]);
            $counts=(array)($assessment['counts']??[]);
            flash(($assessment['status']??'warning')==='clear'?'success':'warning',($assessment['status']??'warning')==='blocked'
                ? 'Dental prescription safety review found a hard stop. Correct the medicine order before issuing.'
                : (((int)($counts['serious_warning']??0)+(int)($counts['data_gap']??0))>0
                    ? 'Dental prescription safety review completed with warnings or missing reference data. Review and acknowledge every finding.'
                    : 'Dental prescription safety review completed with no blocking or serious local-rule finding.'));
        }elseif($action==='cancel'){
            $id=(int)($_POST['id']??0);$reason=trim((string)($_POST['cancellation_reason']??''));
            if(mb_strlen($reason)<10)throw new RuntimeException('Enter a specific cancellation reason of at least 10 characters.');
            $pdo->beginTransaction();
            $stmt=$pdo->prepare('SELECT * FROM `' . table('prescriptions') . '` WHERE id=? FOR UPDATE');$stmt->execute([$id]);$rx=$stmt->fetch();
            if(!$rx)throw new RuntimeException('Prescription not found.');
            require_patient((int)$rx['patient_id']);
            if((int)$rx['dentist_user_id']!==$dentistId)throw new RuntimeException('Only the issuing Dentist can cancel this prescription.');
            if((string)$rx['status']!=='issued')throw new RuntimeException('Only an active issued prescription can be cancelled.');
            $update=$pdo->prepare('UPDATE `' . table('prescriptions') . '` SET status="cancelled",cancelled_at=NOW(),cancelled_by=?,cancellation_reason=? WHERE id=? AND status="issued"');
            $update->execute([$dentistId,$reason,$id]);
            if($update->rowCount()!==1)throw new RuntimeException('The prescription state changed before cancellation was completed.');
            $pdo->commit();
            audit('prescription_cancelled','prescription',$id,['reason'=>$reason,'patient_id'=>(int)$rx['patient_id']]);
            flash('success','Prescription '.$rx['prescription_no'].' cancelled. The original signed record remains preserved.');
            $patientId=(int)$rx['patient_id'];
            $operationEntityId=$id;
        }else{
            $patientId=(int)($_POST['patient_id']??0);$patient=require_patient($patientId);$encounterId=(int)($_POST['encounter_id']??0);
            if($encounterId){$encounter=module_require_encounter_scope($pdo,$encounterId,false,true);if((int)$encounter['patient_id']!==$patientId)throw new RuntimeException('The encounter does not belong to the selected patient.');}
            $items=prescription_post_items();if(!$items)throw new RuntimeException('Add at least one medicine.');
            $pdo->beginTransaction();
            $items=medicine_catalog_bind_posted_items($pdo,$items,$dentistId);
            $clinicalIndication=trim((string)($_POST['clinical_indication']??''));
            if($clinicalIndication==='')throw new RuntimeException('Record the overall clinical indication for this prescription.');
            if(!isset($_POST['allergy_review_acknowledged']))throw new RuntimeException('Confirm that allergies, current medicines, bleeding risk, pregnancy/radiography considerations, and dental-treatment alerts were reviewed.');
            $safetyOverrideReason=trim((string)($_POST['prescription_safety_override_reason']??''));
            $safetyAssessment=clinical_safety_assert_prescription($pdo,$patientId,$encounterId,$items,isset($_POST['prescription_safety_acknowledged']),$safetyOverrideReason);

            $profile=dentist_profile($dentistId)?:[];
            $signedName=dentist_display_name($profile);$license=trim((string)($profile['license_number']??''));
            $signature=trim((string)($profile['prescription_signature_path']??$profile['signature_path']??''))?:null;
            $rxNo='RX'.date('ymd').str_pad((string)random_int(1,9999),4,'0',STR_PAD_LEFT);
            $reviewSnapshot=json_encode([
                'reviewed_at'=>date('c'),'reviewed_by'=>$dentistId,'patient_id'=>$patientId,
                'allergy_review_acknowledged'=>true,'medical_alert_summary'=>(string)($patient['medical_alerts']??''),
                'safety_status'=>clinical_safety_storage_status((array)$safetyAssessment),'safety_counts'=>$safetyAssessment['counts']??[],
                'safety_context_hash'=>$safetyAssessment['context_hash']??null,
            ],JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);

            $stmt=$pdo->prepare('INSERT INTO `' . table('prescriptions') . '` (patient_id,encounter_id,dentist_user_id,prescription_no,issued_at,status,clinical_indication,review_snapshot_json,signed_by_name,signed_license_number,signed_signature_path,prescription_hash,notes,created_at) VALUES (?,?,?,?,NOW(),"issued",?,?,?,?,?,NULL,?,NOW())');
            $stmt->execute([$patientId,$encounterId?:null,$dentistId,$rxNo,$clinicalIndication,$reviewSnapshot,$signedName,$license,$signature,trim((string)($_POST['notes']??''))?:null]);$id=(int)$pdo->lastInsertId();$operationEntityId=$id;
            if(schema_column_exists(table('prescription_items'),'medicine_catalog_id')){
                $insert=$pdo->prepare('INSERT INTO `' . table('prescription_items') . '` (prescription_id,medicine_catalog_id,medication_name,generic_name,indication,strength,dosage,frequency,route,duration_days,quantity,instructions) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)');
                foreach($items as $item)$insert->execute([$id,$item['medicine_catalog_id'],$item['medication_name'],$item['generic_name'],$item['indication'],$item['strength'],$item['dosage'],$item['frequency'],$item['route'],$item['duration_days'],$item['quantity'],$item['instructions']]);
            }else{
                $insert=$pdo->prepare('INSERT INTO `' . table('prescription_items') . '` (prescription_id,medication_name,generic_name,indication,strength,dosage,frequency,route,duration_days,quantity,instructions) VALUES (?,?,?,?,?,?,?,?,?,?,?)');
                foreach($items as $item)$insert->execute([$id,$item['medication_name'],$item['generic_name'],$item['indication'],$item['strength'],$item['dosage'],$item['frequency'],$item['route'],$item['duration_days'],$item['quantity'],$item['instructions']]);
            }
            $safetyAssessmentId=clinical_safety_persist_assessment($pdo,$id,$patientId,$encounterId,$dentistId,$safetyAssessment,$safetyOverrideReason);
            $payload=[
                'prescription_no'=>$rxNo,'patient_id'=>$patientId,'encounter_id'=>$encounterId?:null,
                'dentist_user_id'=>$dentistId,'clinical_indication'=>$clinicalIndication,'items'=>$items,
                'notes'=>trim((string)($_POST['notes']??''))?:null,'signed_by_name'=>$signedName,
                'signed_license_number'=>$license,'safety_assessment_id'=>$safetyAssessmentId,
                'safety_status'=>clinical_safety_storage_status((array)$safetyAssessment),'safety_context_hash'=>$safetyAssessment['context_hash']??null,
            ];
            $hash=hash('sha256',(string)json_encode($payload,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
            $pdo->prepare('UPDATE `' . table('prescriptions') . '` SET prescription_hash=? WHERE id=?')->execute([$hash,$id]);
            $pdo->commit();
            prescription_safety_clear_preview($patientId,$dentistId);
            audit('prescription_issued','prescription',$id,['patient_id'=>$patientId,'item_count'=>count($items),'prescription_hash'=>$hash,'safety_assessment_id'=>$safetyAssessmentId,'safety_status'=>clinical_safety_storage_status((array)$safetyAssessment)]);
            flash('success','Prescription '.$rxNo.' issued and digitally sealed with '.count($items).' medicine'.(count($items)===1?'':'s').' after medication-safety review.');
        }
        operation_integrity_complete($pdo,$operationRequest,['entity_type'=>'prescription','entity_id'=>$operationEntityId,'redirect'=>'prescriptions.php']);
    }catch(Throwable $e){
        if($pdo->inTransaction())$pdo->rollBack();
        operation_integrity_fail($pdo,$operationRequest,$e);
        if(!empty($GLOBALS['clinical_safety_block_event'])&&is_array($GLOBALS['clinical_safety_block_event']))clinical_safety_record_block_event($pdo,$GLOBALS['clinical_safety_block_event']);
        if($patientId>0&&!empty($GLOBALS['clinical_safety_last_assessment'])&&is_array($GLOBALS['clinical_safety_last_assessment'])){
            prescription_safety_store_preview($patientId,(int)(current_user()['id']??0),(array)($GLOBALS['clinical_safety_last_items']??[]),(array)$GLOBALS['clinical_safety_last_assessment'],[
                'encounter_id'=>(int)($_POST['encounter_id']??0),'clinical_indication'=>(string)($_POST['clinical_indication']??''),
                'notes'=>(string)($_POST['notes']??''),'allergy_review_acknowledged'=>isset($_POST['allergy_review_acknowledged']),
                'prescription_safety_acknowledged'=>isset($_POST['prescription_safety_acknowledged']),
                'prescription_safety_override_reason'=>(string)($_POST['prescription_safety_override_reason']??''),
            ]);
        }
        flash('error',$e->getMessage());
    }
    header('Location: prescriptions.php?patient_id='.$patientId);exit;
}

$safetyPreview=prescription_safety_get_preview($patientId,(int)(current_user()['id']??0));
$safetyPreviewItems=(array)($safetyPreview['items']??[]);
$safetyPreviewAssessment=(array)($safetyPreview['assessment']??[]);
$safetyPreviewFields=(array)($safetyPreview['fields']??[]);

$sql='SELECT r.*,CONCAT(p.first_name," ",p.last_name) patient,u.name dentist,COUNT(i.id) item_count,GROUP_CONCAT(CONCAT(i.medication_name,IF(i.strength IS NULL OR i.strength="","",CONCAT(" ",i.strength))) ORDER BY i.id SEPARATOR ", ") medicine_summary FROM `' . table('prescriptions') . '` r JOIN `' . table('patients') . '` p ON p.id=r.patient_id LEFT JOIN `' . table('users') . '` u ON u.id=r.dentist_user_id LEFT JOIN `' . table('prescription_items') . '` i ON i.prescription_id=r.id WHERE 1=1';
$args=[];if($patientId){$sql.=' AND r.patient_id=?';$args[]=$patientId;}[$scopeSql,$scopeArgs]=task_patient_scope_condition('r.patient_id');$sql.=$scopeSql;$args=array_merge($args,$scopeArgs);$sql.=' GROUP BY r.id ORDER BY r.issued_at DESC LIMIT 100';$stmt=$pdo->prepare($sql);$stmt->execute($args);$rows=$stmt->fetchAll();
render_header('Prescriptions');render_module_intro('Medication records','Issue complete multi-item prescriptions with credentialed Dentist identity, structured medication-safety review, immutable hash, and controlled cancellation.',$canEdit&&$schemaReady?'New prescription':null,$canEdit&&$schemaReady?'rx-form':null);render_patient_filter($patients,'prescriptions.php',$patientId);
if(!$schemaReady):?><div class="alert warning"><strong>Version 0.9.0.7 database update required.</strong> Apply the pending clinical-safety update in System Setup before issuing prescriptions.</div><?php endif;?>
<div class="module-card-grid"><?php foreach($rows as $index=>$row):?><article class="module-card"><div class="status-actions"><span class="badge"><?=e(module_status((string)$row['status']))?></span><?php if($index===0):?><span class="badge">Latest prescription</span><?php endif;?></div><h3><?=e((string)($row['medicine_summary']?:'Prescription'))?></h3><p><?=e((string)$row['patient'])?> · <?=e((string)$row['prescription_no'])?></p><dl><dt>Medicines</dt><dd><?=(int)$row['item_count']?></dd><dt>Indication</dt><dd><?=e((string)($row['clinical_indication']??'—'))?></dd><dt>Signed by</dt><dd><?=e((string)($row['signed_by_name']??$row['dentist']?:'—'))?></dd><dt>License</dt><dd><?=e((string)($row['signed_license_number']??'—'))?></dd><dt>Issued</dt><dd><?=e(date('M j, Y g:i A',strtotime((string)$row['issued_at'])))?></dd><dt>Dental prescription safety</dt><dd><?=e(clinical_safety_status_label((string)($row['safety_status']??'pending')))?></dd><dt>Record hash</dt><dd><code><?=e(!empty($row['prescription_hash'])?substr((string)$row['prescription_hash'],0,16).'…':'Legacy record')?></code></dd></dl><?php if($row['notes']):?><p><?=nl2br(e((string)$row['notes']))?></p><?php endif;?><?php if(($row['status']??'')==='cancelled'):?><p class="notice warning"><strong>Cancelled:</strong> <?=e((string)($row['cancellation_reason']??'Reason not available'))?><?=!empty($row['cancelled_at'])?' · '.e(date('M j, Y g:i A',strtotime((string)$row['cancelled_at']))):''?></p><?php endif;?><div class="status-actions"><a class="btn ghost" target="_blank" href="print_record.php?type=prescription&amp;id=<?=(int)$row['id']?>">View / print prescription</a><?php if($canEdit&&($row['status']??'')==='issued'&&(int)$row['dentist_user_id']===(int)(current_user()['id']??0)):?><form method="post" class="status-actions"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="cancel"><input type="hidden" name="id" value="<?=(int)$row['id']?>"><input name="cancellation_reason" minlength="10" required placeholder="Cancellation reason"><button class="btn ghost" data-confirm="Cancel this prescription while preserving the signed original?">Cancel prescription</button></form><?php endif;?></div></article><?php endforeach;if(!$rows):?><div class="card queue-empty">No prescriptions found.</div><?php endif;?></div>
<?php if($canEdit&&$schemaReady):?>
<dialog id="rx-form" class="wide-dialog"><form method="post" data-keyboard-entry>
  <button type="button" class="dialog-close" data-close>×</button><h2>Issue prescription</h2>
  <input type="hidden" name="csrf" value="<?=e(csrf_token())?>">
  <div class="form-grid">
    <label>Patient<?php module_patient_select($patients,'patient_id',$patientId);?></label>
    <label>Encounter ID<input type="number" name="encounter_id" value="<?=e((string)($safetyPreviewFields['encounter_id']??''))?>"></label>
    <label class="wide">Overall clinical indication<textarea name="clinical_indication" required placeholder="Diagnosis or clinical reason for prescribing"><?=e((string)($safetyPreviewFields['clinical_indication']??''))?></textarea></label>
  </div>
  <?php if(!$catalogReady):?><div class="alert warning"><strong>Medicine catalog update pending.</strong> Add medicines manually only when the catalog entry is unavailable.</div><?php endif;?>
  <?php render_medicine_builder($safetyPreviewItems,true,[],'standalone-medicine-builder');?>
  <div class="status-actions"><button class="btn ghost" name="action" value="review_safety" formnovalidate>Run dental prescription safety review</button><small class="muted">Supports dental prescribing only. It does not diagnose or manage general medical conditions and is not a complete external interaction database.</small></div>
  <?php if($safetyPreviewAssessment):
      $previewCounts=(array)($safetyPreviewAssessment['counts']??[]);
      $previewStatus=(string)($safetyPreviewAssessment['status']??'pending');
      $previewClass=$previewStatus==='blocked'?'danger':($previewStatus==='clear'?'success':'warning');
  ?><section class="alert <?=$previewClass?>" aria-live="polite"><strong><?=e(clinical_safety_status_label($previewStatus))?></strong><span>Hard stops: <?=(int)($previewCounts['hard_stop']??0)?> · Serious warnings: <?=(int)($previewCounts['serious_warning']??0)?> · Data gaps: <?=(int)($previewCounts['data_gap']??0)?> · Advisories: <?=(int)($previewCounts['advisory']??0)?></span><?php if($previewStatus==='clear'):?><p>No finding was produced by the installed local rules. This is not a universal safety declaration.</p><?php endif;?></section>
  <?php foreach((array)($safetyPreviewAssessment['findings']??[]) as $finding):?><article class="card"><div class="card-head"><strong><?=e((string)($finding['title']??'Dental prescription safety finding'))?></strong><span class="badge"><?=e(module_status((string)($finding['severity']??'advisory')))?></span></div><p><?=e((string)($finding['detail']??''))?></p></article><?php endforeach;?>
  <?php endif;?>
  <div class="form-grid">
    <label class="wide check-label"><input type="checkbox" name="allergy_review_acknowledged" value="1" <?=!empty($safetyPreviewFields['allergy_review_acknowledged'])?'checked':''?> required><span>I reviewed allergies, current medicines, bleeding risk, pregnancy/radiography considerations, and alerts relevant to this dental treatment.</span></label>
    <label class="wide check-label"><input type="checkbox" name="prescription_safety_acknowledged" value="1" <?=!empty($safetyPreviewFields['prescription_safety_acknowledged'])?'checked':''?>><span>I reviewed the medication-safety findings, limitations, and missing interaction data.</span></label>
    <label class="wide">Clinical justification for serious warning override<textarea name="prescription_safety_override_reason" minlength="20" placeholder="Required only when continuing despite a serious warning."><?=e((string)($safetyPreviewFields['prescription_safety_override_reason']??''))?></textarea></label>
    <label class="wide">Clinical notes<textarea name="notes"><?=e((string)($safetyPreviewFields['notes']??''))?></textarea></label>
    <button class="btn primary wide" name="action" value="issue">Issue and seal prescription</button>
  </div>
</form></dialog>
<?php endif;?>
<script src="public/assets/js/medicine-builder.js?v=<?=e(app_release_version())?>"></script>
<?php render_footer();
