<?php

declare(strict_types=1);

require DENTAL_ROOT . '/app/bootstrap.php';
require_login();
require_doctor_workflow_schema();
require_clinical_sequence_schema();
require_clinical_workspace_redesign_schema();
require_clinical_vitals_schema();
require_treatment_completion_schema();
require_encounter_assistant_schema();
require DENTAL_ROOT . '/app/layout.php';
require_once DENTAL_ROOT . '/app/module_helpers.php';
require_once DENTAL_ROOT . '/app/queue_flow.php';
require_once DENTAL_ROOT . '/app/treatment_flow.php';
require_once DENTAL_ROOT . '/app/tooth_model.php';
require_once DENTAL_ROOT . '/app/clinical_media.php';
require_once DENTAL_ROOT . '/app/transaction_integrity.php';
require_once DENTAL_ROOT . '/app/medicine_catalog.php';
require_once DENTAL_ROOT . '/app/clinical_safety.php';
require_once DENTAL_ROOT . '/app/clinical_billing.php';
require_once DENTAL_ROOT . '/app/workflow_governance.php';
require_once DENTAL_ROOT . '/app/clinical_record_completion.php';
require_once DENTAL_ROOT . '/app/inventory_integrity.php';
require_once DENTAL_ROOT . '/app/treatment_path_rules.php';
require_once DENTAL_ROOT . '/app/adaptive_encounter.php';

$pdo = db();
$user = current_user() ?? [];
$userId = (int)($user['id'] ?? 0);
$actualRole = actual_role();
$activeRole = active_role();
$isDentist = active_role_is('dentist');
$isAssistant = active_role_is('dental_assistant');
if (!$isDentist && !$isAssistant && !in_array($actualRole, ['super_admin','clinic_admin'], true)) {
    http_response_code(403);
    render_header('Clinical workspace access');
    ?>
    <section class="card setup-empty-state">
        <span class="eyebrow">Clinical workspace</span>
        <h2>This treatment workspace is not available to your role</h2>
        <p>Return to your dashboard or open the clinic queue using an operational role assigned to this workflow.</p>
        <div class="status-actions"><a class="btn primary" href="dashboard.php">Return to dashboard</a><?php if(task_link_allowed('queue.php')):?><a class="btn ghost" href="queue.php">Open clinic queue</a><?php endif;?></div>
    </section>
    <?php
    render_footer();
    return;
}

function workspace_encounter(PDO $pdo,int $id): ?array
{
    $stmt=$pdo->prepare(
        'SELECT c.*,q.queue_no,q.status queue_status,q.service_name queue_service,q.reason queue_reason,q.chair_id,q.chair_name,q.provider_type,q.called_at,q.seated_at,q.treatment_started_at,q.billing_at,q.completed_at,q.source_type,q.checked_in_at,q.intake_completed_at,'
        . 'a.start_at,a.end_at,a.status appointment_status,a.appointment_origin,a.reason_for_visit,'
        . 'p.patient_no,p.first_name,p.middle_name,p.last_name,p.birth_date,p.sex,p.mobile,p.email,p.medical_alerts '
        . 'FROM `' . table('clinical_encounters') . '` c JOIN `' . table('patients') . '` p ON p.id=c.patient_id '
        . 'LEFT JOIN `' . table('queue_entries') . '` q ON q.id=c.queue_entry_id LEFT JOIN `' . table('appointments') . '` a ON a.id=c.appointment_id WHERE c.id=?'
    );
    $stmt->execute([$id]);
    return $stmt->fetch() ?: null;
}

function workspace_can_write(array $encounter): bool
{
    return active_role_is('dentist') && (int)$encounter['dentist_user_id']===(int)(current_user()['id']??0) && $encounter['status']!=='finalized';
}

function workspace_is_assigned_assistant(array $encounter): bool
{
    return active_role_is('dental_assistant')
        && (int)($encounter['assistant_user_id']??0)===(int)(current_user()['id']??0);
}

function workspace_can_screen(array $encounter): bool
{
    if (workspace_can_write($encounter)) return true;
    if ($encounter['status']==='finalized') return false;
    if (workspace_is_assigned_assistant($encounter)) return true;
    if (!active_role_is('dental_assistant')) return false;
    return in_array((int)$encounter['dentist_user_id'], task_dentist_scope_ids(), true);
}

function workspace_can_treatment_entry(array $encounter): bool
{
    return $encounter['status']!=='finalized' && (workspace_can_write($encounter) || (workspace_is_assigned_assistant($encounter) && (string)($encounter['queue_status']??'')==='in_treatment'));
}

function workspace_latest(PDO $pdo,string $tableName,string $where,array $args): ?array
{
    $stmt=$pdo->prepare('SELECT * FROM `' . table($tableName) . '` WHERE '.$where.' ORDER BY id DESC LIMIT 1');
    $stmt->execute($args);
    return $stmt->fetch() ?: null;
}

function workspace_input(string $name): ?string
{
    $value=trim((string)($_POST[$name]??''));
    return $value===''?null:$value;
}

function workspace_resolve_start_assistant(PDO $pdo, int $assistantId, int $branchId): ?array
{
    if ($assistantId <= 0) return null;
    if (!function_exists('encounter_assistant_schema_ready') || !encounter_assistant_schema_ready()) {
        throw new RuntimeException('Dental Assistant assignment is not ready. Apply pending updates first.');
    }
    $stmt = $pdo->prepare(
        'SELECT u.id,u.name,u.branch_id FROM `' . table('users') . '` u '
        . 'JOIN `' . table('roles') . '` r ON r.id=u.role_id '
        . 'WHERE u.id=? AND r.code="dental_assistant" AND u.status="active" AND (u.branch_id=? OR u.branch_id IS NULL OR ?=0) LIMIT 1'
    );
    $stmt->execute([$assistantId, $branchId, $branchId]);
    $assistant = $stmt->fetch();
    if (!$assistant) throw new RuntimeException('Select an active Dental Assistant authorized for this branch, or choose No Dental Assistant for this visit.');
    return $assistant;
}


function workspace_resolve_procedure_service_id(PDO $pdo,array $encounter,string $procedureName): ?int
{
    if($procedureName===''||!schema_column_exists(table('procedures'),'service_id'))return null;
    $branchId=(int)($encounter['branch_id']??0);
    $stmt=$pdo->prepare(
        'SELECT id FROM `' . table('service_catalog') . '` '
        . 'WHERE is_active=1 AND LOWER(TRIM(name))=LOWER(TRIM(?)) '
        . 'AND (branch_id=? OR branch_id IS NULL) '
        . 'ORDER BY CASE WHEN branch_id=? THEN 0 ELSE 1 END,id LIMIT 1'
    );
    $stmt->execute([$procedureName,$branchId,$branchId]);
    $serviceId=(int)($stmt->fetchColumn()?:0);
    return $serviceId>0?$serviceId:null;
}

function workspace_treatment_item(PDO $pdo,int $itemId,int $patientId): ?array
{
    if($itemId<1)return null;
    $stmt=$pdo->prepare(
        'SELECT i.*,p.patient_id,p.dentist_user_id plan_dentist_user_id,p.status plan_status,p.title plan_title '
        . 'FROM `' . table('treatment_plan_items') . '` i JOIN `' . table('treatment_plans') . '` p ON p.id=i.treatment_plan_id '
        . 'WHERE i.id=? AND p.patient_id=? LIMIT 1'
    );
    $stmt->execute([$itemId,$patientId]);
    return $stmt->fetch()?:null;
}

function workspace_update_plan_rollup(PDO $pdo,int $planId): void
{
    if($planId<1)return;
    $stmt=$pdo->prepare(
        'SELECT COUNT(*) total,'
        . 'SUM(status="completed") completed_count,'
        . 'SUM(status="in_progress") progress_count,'
        . 'SUM(status IN ("proposed","accepted","scheduled","in_progress","deferred")) open_count '
        . 'FROM `' . table('treatment_plan_items') . '` WHERE treatment_plan_id=? AND status NOT IN ("declined","cancelled")'
    );
    $stmt->execute([$planId]);$counts=$stmt->fetch()?:[];
    $total=(int)($counts['total']??0);$open=(int)($counts['open_count']??0);$completed=(int)($counts['completed_count']??0);$progress=(int)($counts['progress_count']??0);
    if($total>0&&$open===0){
        $pdo->prepare('UPDATE `' . table('treatment_plans') . '` SET status="completed",updated_at=NOW() WHERE id=? AND status NOT IN ("declined","cancelled","expired","revised")')->execute([$planId]);
    }elseif($completed>0||$progress>0){
        $pdo->prepare('UPDATE `' . table('treatment_plans') . '` SET status="in_progress",updated_at=NOW() WHERE id=? AND status NOT IN ("declined","cancelled","expired","revised")')->execute([$planId]);
    }
}

function workspace_sync_treatment_item(PDO $pdo,array $item,int $encounterId,bool $finalize,int $userId): void
{
    $itemId=(int)$item['id'];$newStatus=$finalize?'completed':'in_progress';$oldStatus=(string)($item['status']??'proposed');
    if(!in_array($oldStatus,['accepted','scheduled','in_progress'],true))throw new RuntimeException('The selected treatment-plan item must be accepted or scheduled before it can be performed.');
    if((string)($item['consent_status']??'not_requested')==='declined')throw new RuntimeException('The selected treatment-plan item has declined consent. Update the treatment plan before proceeding.');
    if($oldStatus!=='completed'){
        $pdo->prepare('UPDATE `' . table('treatment_plan_items') . '` SET status=?,updated_at=NOW() WHERE id=?')->execute([$newStatus,$itemId]);
    }
    if(!empty($item['odontogram_entry_id'])&&schema_column_exists(table('treatment_plan_items'),'odontogram_entry_id')){
        $findingId=(int)$item['odontogram_entry_id'];
        $stmt=$pdo->prepare('SELECT * FROM `' . table('odontogram_entries') . '` WHERE id=? AND patient_id=? LIMIT 1');
        $stmt->execute([$findingId,(int)$item['patient_id']]);$finding=$stmt->fetch();
        if($finding){
            if($finalize){
                $pdo->prepare('UPDATE `' . table('odontogram_entries') . '` SET status="resolved",resolved_by=?,resolved_at=COALESCE(resolved_at,NOW()),treatment_plan_item_id=? WHERE id=? AND status="active"')->execute([$userId,$itemId,$findingId]);
                $duplicate=$pdo->prepare('SELECT id FROM `' . table('odontogram_entries') . '` WHERE patient_id=? AND treatment_plan_item_id=? AND chart_layer="completed" LIMIT 1');
                $duplicate->execute([(int)$item['patient_id'],$itemId]);
                if(!$duplicate->fetchColumn()){
                    $pdo->prepare(
                        'INSERT INTO `' . table('odontogram_entries') . '` '
                        . '(patient_id,branch_id,service_id,encounter_id,dentition,tooth_number,surface,condition_code,finding_type,severity,chart_layer,status,diagnosis_id,treatment_plan_item_id,supersedes_entry_id,notes,recorded_by,recorded_at) '
                        . 'VALUES (?,?,?,?,?,?,?,?,?,? ,"completed","active",?,?,?,?,?,NOW())'
                    )->execute([
                        (int)$item['patient_id'],$finding['branch_id']?:null,$finding['service_id']?:null,$encounterId,
                        $finding['dentition']?:'permanent',$item['tooth_number']?:$finding['tooth_number'],$item['surfaces']?:$finding['surface'],
                        'completed_treatment','treatment','information',$finding['diagnosis_id']?:null,$itemId,$findingId,
                        trim((string)$item['procedure_name']).' completed during encounter #'.$encounterId.'. Original finding retained in history.',$userId
                    ]);
                }
            }else{
                $pdo->prepare('UPDATE `' . table('odontogram_entries') . '` SET chart_layer="in_progress",treatment_plan_item_id=? WHERE id=? AND status="active"')->execute([$itemId,$findingId]);
            }
        }
    }
    workspace_update_plan_rollup($pdo,(int)$item['treatment_plan_id']);
}

function workspace_prepare_invoice(PDO $pdo,array $encounter,string $procedureName,string $toothRegion,float $amount,int $userId,?int $treatmentItemId=null,?int $procedureId=null): int
{
    if($amount<=0)return 0;
    $stmt=$pdo->prepare('SELECT id FROM `' . table('invoices') . '` WHERE encounter_id=? AND status NOT IN ("voided","refunded") ORDER BY id DESC LIMIT 1 FOR UPDATE');
    $stmt->execute([(int)$encounter['id']]);$existing=(int)($stmt->fetchColumn()?:0);
    if($existing)return $existing;
    $invoiceNo='INV-'.date('ymd').'-'.str_pad((string)$encounter['id'],6,'0',STR_PAD_LEFT);
    $check=$pdo->prepare('SELECT COUNT(*) FROM `' . table('invoices') . '` WHERE invoice_no=?');$check->execute([$invoiceNo]);
    if((int)$check->fetchColumn()>0)$invoiceNo.='-'.random_int(10,99);
    $description=trim($procedureName.($toothRegion!==''?' · '.$toothRegion:''));
    $posReady=schema_table_exists(table('invoice_items'))&&schema_column_exists(table('invoices'),'subtotal');
    if($posReady){
        $pdo->prepare(
            'INSERT INTO `' . table('invoices') . '` '
            . '(branch_id,invoice_no,patient_id,encounter_id,queue_entry_id,description,subtotal,discount_type,discount_value,discount_amount,tax_amount,amount,status,created_by,created_at,updated_at) '
            . 'VALUES (?,?,?,?,?,?,?,"none",0,0,0,?,"unpaid",?,NOW(),NOW())'
        )->execute([
            (int)($encounter['branch_id']??0)?:null,$invoiceNo,(int)$encounter['patient_id'],(int)$encounter['id'],
            (int)($encounter['queue_entry_id']??0)?:null,$description!==''?$description:'Dental procedure',$amount,$amount,$userId
        ]);
        $invoiceId=(int)$pdo->lastInsertId();
        $lineDescription = $description !== '' ? $description : 'Dental procedure';
        $verifiedLineSchema = schema_column_exists(table('invoice_items'),'source_type')
            && schema_column_exists(table('invoice_items'),'source_hash')
            && schema_column_exists(table('invoices'),'charge_source_hash');
        if ($verifiedLineSchema) {
            $sourcePayload = [
                'source_type'=>'clinical_procedure','service_id'=>null,'procedure_id'=>$procedureId ?: null,
                'clinical_usage_item_id'=>null,'treatment_plan_item_id'=>$treatmentItemId ?: null,
                'description'=>$lineDescription,'quantity'=>1.0,'unit_price'=>round($amount,2),
            ];
            $sourceHash = hash('sha256',json_encode($sourcePayload,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
            $pdo->prepare(
                'INSERT INTO `' . table('invoice_items') . '` '
                . '(invoice_id,treatment_plan_item_id,procedure_id,source_type,item_code,description,quantity,unit_price,gross_amount,discount_amount,net_amount,source_authorized_by,source_authorized_at,source_hash,created_by,created_at) '
                . 'VALUES (?,?,?,"clinical_procedure",?,?,1,?,?,0,?,?,NOW(),?,?,NOW())'
            )->execute([$invoiceId,$treatmentItemId?:null,$procedureId?:null,$procedureId?'PROC-'.$procedureId:null,$lineDescription,$amount,$amount,$amount,$userId?:null,$sourceHash,$userId?:null]);
            $invoiceHash = hash('sha256',json_encode([[$sourceHash,0.0,round($amount,2)]],JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
            $pdo->prepare('UPDATE `' . table('invoices') . '` SET charge_source_hash=?,updated_at=NOW() WHERE id=?')->execute([$invoiceHash,$invoiceId]);
        } else {
            $pdo->prepare(
                'INSERT INTO `' . table('invoice_items') . '` '
                . '(invoice_id,treatment_plan_item_id,procedure_id,item_code,description,quantity,unit_price,gross_amount,discount_amount,net_amount,created_by,created_at) '
                . 'VALUES (?,?,?, ?,?,1,?,?,0,?,?,NOW())'
            )->execute([$invoiceId,$treatmentItemId?:null,$procedureId?:null,$procedureId?'PROC-'.$procedureId:null,$lineDescription,$amount,$amount,$amount,$userId]);
        }
        return $invoiceId;
    }
    $pdo->prepare(
        'INSERT INTO `' . table('invoices') . '` '
        . '(branch_id,invoice_no,patient_id,encounter_id,queue_entry_id,description,amount,status,created_by,created_at) '
        . 'VALUES (?,?,?,?,?,?,?,"unpaid",?,NOW())'
    )->execute([
        (int)($encounter['branch_id']??0)?:null,$invoiceNo,(int)$encounter['patient_id'],(int)$encounter['id'],
        (int)($encounter['queue_entry_id']??0)?:null,$description!==''?$description:'Dental procedure',$amount,$userId
    ]);
    return (int)$pdo->lastInsertId();
}

function workspace_collect_diagnoses(): array
{
    $ids=(array)($_POST['diagnosis_id']??[]);
    $names=(array)($_POST['diagnosis_name']??[]);
    $regions=(array)($_POST['diagnosis_region']??[]);
    $surfaceValues=(array)($_POST['diagnosis_surfaces']??[]);
    $codes=(array)($_POST['diagnosis_code']??[]);
    $severities=(array)($_POST['diagnosis_severity']??[]);
    $statuses=(array)($_POST['diagnosis_status']??[]);
    $notes=(array)($_POST['diagnosis_notes']??[]);
    $rows=[];
    foreach($names as $i=>$name){
        $name=trim((string)$name);
        if($name==='')continue;
        $rawRegion=trim((string)($regions[$i]??''));
        $tooth=dental_extract_fdi_tooth($rawRegion);
        $surfaces=$tooth?dental_surface_codes_from_text((string)($surfaceValues[$i]??$rawRegion),$tooth):[];
        $isCaries=(bool)preg_match('/\b(caries|carious|decay|cavity)\b/i',$name) || preg_match('/^K0?2/i',trim((string)($codes[$i]??'')));
        if($tooth&&$isCaries){
            $allowed=array_keys(dental_caries_surface_options($tooth));
            $surfaces=array_values(array_filter($surfaces,static fn(string $surface):bool=>in_array($surface,$allowed,true)));
        }
        $region=$rawRegion!==''?$rawRegion:null;
        if($tooth){
            $region=$tooth.($surfaces?'-'.implode(',',$surfaces):'');
        }
        $rows[]=[
            'id'=>(int)($ids[$i]??0),
            'name'=>$name,
            'region'=>$region,
            'tooth'=>$tooth,
            'surfaces'=>$surfaces,
            'code'=>trim((string)($codes[$i]??''))?:null,
            'severity'=>in_array(($severities[$i]??''),['mild','moderate','severe','critical'],true)?$severities[$i]:null,
            'status'=>in_array(($statuses[$i]??''),['provisional','confirmed','resolved','chronic','under_observation','referred'],true)?$statuses[$i]:'provisional',
            'notes'=>trim((string)($notes[$i]??''))?:null,
        ];
    }
    return $rows;
}

function workspace_sync_diagnosis_chart(PDO $pdo,array $encounter,array $diagnosis,int $diagnosisId,int $userId): void
{
    if(!schema_table_exists(table('odontogram_entries')))return;
    $patientId=(int)$encounter['patient_id'];
    $encounterId=(int)$encounter['id'];
    $tooth=(string)($diagnosis['tooth']??'');
    $existingStmt=$pdo->prepare('SELECT * FROM `' . table('odontogram_entries') . '` WHERE diagnosis_id=? ORDER BY id DESC LIMIT 1');
    $existingStmt->execute([$diagnosisId]);
    $existing=$existingStmt->fetch()?:null;

    if($tooth===''||!dental_is_valid_fdi_tooth($tooth)){
        if($existing&&($existing['finding_type']??'')==='diagnosis'&&($existing['status']??'')==='active'){
            $pdo->prepare('UPDATE `' . table('odontogram_entries') . '` SET status="superseded",resolved_by=?,resolved_at=NOW() WHERE id=?')->execute([$userId,(int)$existing['id']]);
        }
        return;
    }

    // A finding created directly from the dental chart is authoritative. Keep
    // its condition and surface anatomy, while preserving the diagnosis link.
    if($existing&&($existing['finding_type']??'')!=='diagnosis')return;

    $surfaces=(array)($diagnosis['surfaces']??[]);
    $surfaceText=$surfaces?implode(',',$surfaces):'Whole';
    $dentition=dental_tooth_dentition($tooth)??'permanent';
    $status=(string)($diagnosis['status']??'provisional')==='resolved'?'resolved':'active';
    $layer=$status==='resolved'?'historical':'existing';
    $conditionCode=trim((string)($diagnosis['code']??''))?:'diagnosis';
    $severity=in_array((string)($diagnosis['severity']??''),['mild','moderate','severe','critical'],true)?$diagnosis['severity']:null;
    $notes=trim((string)($diagnosis['notes']??''))?:null;

    if($existing){
        $pdo->prepare(
            'UPDATE `' . table('odontogram_entries') . '` SET encounter_id=?,dentition=?,tooth_number=?,surface=?,condition_code=?,severity=?,chart_layer=?,status=?,notes=?,recorded_by=?,resolved_by=IF(?="resolved",?,NULL),resolved_at=IF(?="resolved",NOW(),NULL) WHERE id=?'
        )->execute([$encounterId,$dentition,$tooth,$surfaceText,$conditionCode,$severity,$layer,$status,$notes,$userId,$status,$userId,$status,(int)$existing['id']]);
        return;
    }

    $columns=['patient_id','encounter_id','dentition','tooth_number','surface','condition_code','finding_type','severity','chart_layer','status','diagnosis_id','notes','recorded_by','recorded_at'];
    $values=[$patientId,$encounterId,$dentition,$tooth,$surfaceText,$conditionCode,'diagnosis',$severity,$layer,$status,$diagnosisId,$notes,$userId];
    if(schema_column_exists(table('odontogram_entries'),'branch_id')){
        array_splice($columns,1,0,['branch_id']);
        array_splice($values,1,0,[(int)($encounter['branch_id']??0)?:null]);
    }
    $quoted=array_map(static fn(string $column):string=>'`'.$column.'`',$columns);
    $placeholders=array_fill(0,count($values),'?');
    $sql='INSERT INTO `' . table('odontogram_entries') . '` ('.implode(',',$quoted).') VALUES ('.implode(',',$placeholders).',NOW())';
    $pdo->prepare($sql)->execute($values);
}

function workspace_collect_usage_items(): array
{
    $types=(array)($_POST['usage_type']??[]);
    $inventoryIds=(array)($_POST['usage_inventory_item_id']??[]);
    $descriptions=(array)($_POST['usage_description']??[]);
    $quantities=(array)($_POST['usage_quantity']??[]);
    $units=(array)($_POST['usage_unit']??[]);
    $billingModes=(array)($_POST['usage_billing_mode']??[]);
    $prices=(array)($_POST['usage_unit_price']??[]);
    $notes=(array)($_POST['usage_notes']??[]);
    $allowedTypes=['medication_administered','medicine_dispense','consumable','equipment','diagnostic_service'];
    $allowedBilling=['included','bill_separately','track_only'];
    $rows=[];
    foreach($types as $i=>$type){
        $type=(string)$type;
        $description=trim((string)($descriptions[$i]??''));
        if($description===''&&!in_array($type,$allowedTypes,true))continue;
        if(!in_array($type,$allowedTypes,true))throw new RuntimeException('Choose a valid medicine, material, equipment, or diagnostic usage type.');
        if($description==='')throw new RuntimeException('Every medicine, material, equipment, or diagnostic entry needs a description.');
        $quantity=round((float)($quantities[$i]??1),2);
        if($quantity<=0||$quantity>9999)throw new RuntimeException('Usage quantities must be greater than zero.');
        $billing=in_array((string)($billingModes[$i]??''),$allowedBilling,true)?(string)$billingModes[$i]:'track_only';
        $price=round((float)($prices[$i]??0),2);
        if($billing==='bill_separately'&&$price<=0)throw new RuntimeException('Separately billable medicines, materials, equipment, or diagnostics need a positive unit price.');
        $rows[]=[
            'usage_type'=>$type,
            'inventory_item_id'=>(int)($inventoryIds[$i]??0)?:null,
            'description'=>$description,
            'quantity'=>$quantity,
            'unit'=>trim((string)($units[$i]??''))?:null,
            'billing_mode'=>$billing,
            'unit_price'=>$billing==='bill_separately'?$price:0.0,
            'line_total'=>$billing==='bill_separately'?round($quantity*$price,2):0.0,
            'notes'=>trim((string)($notes[$i]??''))?:null,
        ];
    }
    return $rows;
}

function workspace_save_usage_items(PDO $pdo,array $encounter,array $items,bool $finalize,int $userId): array
{
    if(!schema_table_exists(table('clinical_usage_items')))return [];
    $encounterId=(int)$encounter['id'];
    $patientId=(int)$encounter['patient_id'];
    $branchId=(int)($encounter['branch_id']??0)?:null;
    $pdo->prepare('DELETE FROM `' . table('clinical_usage_items') . '` WHERE encounter_id=? AND fulfillment_status IN ("draft","requested")')->execute([$encounterId]);
    $insert=$pdo->prepare(
        'INSERT INTO `' . table('clinical_usage_items') . '` '
        . '(encounter_id,patient_id,branch_id,inventory_item_id,usage_type,description,quantity,unit,billing_mode,unit_price,line_total,fulfillment_status,notes,recorded_by,created_at,updated_at) '
        . 'VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW(),NOW())'
    );
    $saved=[];
    foreach($items as $item){
        $inventoryId=(int)($item['inventory_item_id']??0);
        if(in_array($item['usage_type'],['medication_administered','medicine_dispense','consumable'],true)&&$inventoryId<1){
            throw new RuntimeException('Select a clinic inventory item for medicines administered or dispensed and for consumable materials.');
        }
        if($inventoryId>0){
            $stock=$pdo->prepare(
                'SELECT i.id,i.name,i.unit,i.status,COALESCE(bs.current_stock,i.current_stock,0) branch_stock '
                . 'FROM `' . table('inventory_items') . '` i LEFT JOIN `' . table('inventory_branch_stocks') . '` bs ON bs.item_id=i.id AND bs.branch_id=? '
                . 'WHERE i.id=? AND i.status="active" AND (i.branch_id=? OR i.branch_id IS NULL) LIMIT 1'
            );
            $stock->execute([$branchId,$inventoryId,$branchId]);
            $catalog=$stock->fetch();
            if(!$catalog)throw new RuntimeException('A selected clinical inventory item is inactive or unavailable for this branch.');
            if(in_array($item['usage_type'],['medication_administered','medicine_dispense','consumable'],true)&&$finalize&&(float)$catalog['branch_stock']<(float)$item['quantity']){
                throw new RuntimeException((string)$catalog['name'].' does not have enough branch stock for the requested quantity.');
            }
            if(trim((string)$item['description'])==='')$item['description']=(string)$catalog['name'];
            if(empty($item['unit']))$item['unit']=(string)$catalog['unit'];
        }
        $status=$finalize?'requested':'draft';
        $insert->execute([
            $encounterId,$patientId,$branchId,$inventoryId?:null,$item['usage_type'],$item['description'],$item['quantity'],$item['unit'],$item['billing_mode'],$item['unit_price'],$item['line_total'],$status,$item['notes'],$userId
        ]);
        $item['id']=(int)$pdo->lastInsertId();
        $item['fulfillment_status']=$status;
        $saved[]=$item;
    }
    return $saved;
}

function workspace_collect_medications(): array
{
    $names=(array)($_POST['medication_name']??[]);
    $generics=(array)($_POST['generic_name']??[]);
    $indications=(array)($_POST['medication_indication']??[]);
    $strengths=(array)($_POST['strength']??[]);
    $dosages=(array)($_POST['dosage']??[]);
    $frequencies=(array)($_POST['frequency']??[]);
    $routes=(array)($_POST['route']??[]);
    $durations=(array)($_POST['duration_days']??[]);
    $quantities=(array)($_POST['quantity']??[]);
    $instructions=(array)($_POST['medication_instructions']??[]);
    $rows=[];
    foreach($names as $i=>$name){
        $name=trim((string)$name);
        if($name==='')continue;
        $duration=trim((string)($durations[$i]??''));
        $rows[]=[
            'medication_name'=>$name,
            'generic_name'=>trim((string)($generics[$i]??''))?:null,
            'indication'=>trim((string)($indications[$i]??''))?:null,
            'strength'=>trim((string)($strengths[$i]??''))?:null,
            'dosage'=>trim((string)($dosages[$i]??''))?:null,
            'frequency'=>trim((string)($frequencies[$i]??''))?:null,
            'route'=>trim((string)($routes[$i]??''))?:null,
            'duration_days'=>$duration!==''?max(1,(int)$duration):null,
            'quantity'=>trim((string)($quantities[$i]??''))?:null,
            'instructions'=>trim((string)($instructions[$i]??''))?:null,
        ];
    }
    return $rows;
}

function workspace_examination_summary(array $assessment): ?string
{
    $domains=[
        ['Extraoral','extraoral_status','extraoral_findings'],
        ['Intraoral / dental','intraoral_status','intraoral_findings'],
        ['Soft tissue','soft_tissue_status','soft_tissue_findings'],
        ['TMJ','tmj_status','tmj_findings'],
        ['Occlusion','occlusion_status','occlusion_findings'],
        ['Radiographic','radiographic_status','radiographic_findings'],
    ];
    $parts=[];
    foreach($domains as [$label,$statusKey,$findingKey]){
        $state=(string)($assessment[$statusKey]??'not_examined');
        if($state==='not_examined'||$state==='')continue;
        $stateLabel=ucwords(str_replace('_',' ',$state));
        $finding=trim((string)($assessment[$findingKey]??''));
        $parts[]=$label.': '.$stateLabel.($finding!==''?' — '.$finding:'').'.';
    }
    return $parts?implode(' ',$parts):null;
}

function workspace_save_clinical(PDO $pdo,array $encounter,bool $finalize,string $completionDestination='cashier'): array
{
    $encounterId=(int)$encounter['id'];$patientId=(int)$encounter['patient_id'];$userId=(int)(current_user()['id']??0);
    $carePath=dental_encounter_care_path((string)($encounter['care_path']??'comprehensive'));
    $condensedIntake=dental_encounter_condensed_intake($carePath);
    $hpiRequired=!$condensedIntake;
    $assessmentRequired=dental_encounter_requires_full_assessment($carePath);
    $vitalsSkipReason=workspace_input('vitals_skip_reason');
    $intake=active_patient_intake($patientId,(int)($encounter['queue_entry_id']??0)?:null,(int)($encounter['appointment_id']??0)?:null);
    $chiefComplaint=workspace_input('chief_complaint')?:trim((string)($intake['chief_complaint']??$encounter['chief_complaint']??''))?:null;
    $historyPresentCondition=workspace_input('history_present_condition')?:trim((string)($intake['history_present_condition']??$encounter['history_present_condition']??''))?:null;
    $examinationSummary=workspace_input('examination_summary');
    $soapNote=workspace_input('soap_note');
    $diagnoses=workspace_collect_diagnoses();
    $medications=workspace_collect_medications();
    $medications=medicine_catalog_bind_posted_items($pdo,$medications,$userId,$finalize);
    $prescriptionSafetyAssessment=null;
    $prescriptionSafetyOverrideReason=trim((string)($_POST['prescription_safety_override_reason']??''));
    if($finalize&&$medications){
        $prescriptionSafetyAssessment=clinical_safety_assert_prescription(
            $pdo,$patientId,$encounterId,$medications,
            isset($_POST['prescription_safety_acknowledged']),
            $prescriptionSafetyOverrideReason
        );
    }
    $usageItems=workspace_collect_usage_items();
    $primaryDiagnosis=$diagnoses[0]['name']??workspace_input('diagnosis_summary');
    $allowedExamStates=['normal','abnormal','not_examined','not_applicable'];
    $examState=static fn(string $name):string=>in_array((string)($_POST[$name]??''),$allowedExamStates,true)?(string)$_POST[$name]:'not_examined';
    $assessment=[
        $examState('extraoral_status'),workspace_input('extraoral_findings'),
        $examState('intraoral_status'),workspace_input('intraoral_findings'),
        $examState('soft_tissue_status'),workspace_input('soft_tissue_findings'),
        $examState('tmj_status'),workspace_input('tmj_findings'),
        $examState('occlusion_status'),workspace_input('occlusion_findings'),
        workspace_input('oral_hygiene_status'),$examState('radiographic_status'),workspace_input('radiographic_findings'),
        workspace_input('risk_assessment'),workspace_input('prognosis')
    ];
    if($examinationSummary===null){
        $examinationSummary=workspace_examination_summary([
            'extraoral_status'=>$assessment[0],'extraoral_findings'=>$assessment[1],
            'intraoral_status'=>$assessment[2],'intraoral_findings'=>$assessment[3],
            'soft_tissue_status'=>$assessment[4],'soft_tissue_findings'=>$assessment[5],
            'tmj_status'=>$assessment[6],'tmj_findings'=>$assessment[7],
            'occlusion_status'=>$assessment[8],'occlusion_findings'=>$assessment[9],
            'radiographic_status'=>$assessment[11],'radiographic_findings'=>$assessment[12],
        ]);
    }
    if(!clinical_billing_schema_ready())throw new RuntimeException('Apply Version 0.5.9.8.15 before saving clinical procedures.');
    $procedureRows=clinical_billing_procedures($pdo,$encounterId,$finalize);
    $pendingAssistantProcedureRows=array_values(array_filter($procedureRows,static fn(array $row):bool=>(string)($row['entered_by_role']??'')==='dental_assistant' && (int)($row['verified_by_user_id']??0)<1));
    $procedureNames=[];
    foreach($procedureRows as $procedureRow){
        $name=trim((string)($procedureRow['procedure_name']??''));
        if($name!=='')$procedureNames[]=$name.(!empty($procedureRow['tooth_region'])?' · '.(string)$procedureRow['tooth_region']:'');
    }
    $procedureName=$procedureNames?implode('; ',$procedureNames):null;
    $clinicalDisposition=(string)($_POST['clinical_disposition']??'');
    $allowedDispositions=['treatment_performed','medication_prescribed_only','medication_administered','diagnostic_procedure','imaging_only','examination_only','no_treatment_required','observation','treatment_advised_declined','treatment_deferred','referral','emergency_stabilization'];
    if(!in_array($clinicalDisposition,$allowedDispositions,true))$clinicalDisposition='';
    $dispositionReason=workspace_input('disposition_reason');
    $patientAdvice=workspace_input('patient_advice');
    $treatmentItemId=0;
    $treatmentItem=null;
    foreach($procedureRows as $procedureRow){
        if((int)($procedureRow['treatment_plan_item_id']??0)>0){
            $treatmentItemId=(int)$procedureRow['treatment_plan_item_id'];
            $treatmentItem=workspace_treatment_item($pdo,$treatmentItemId,$patientId);
            break;
        }
    }
    $followDate=workspace_input('follow_up_date');$followPurpose=workspace_input('follow_up_purpose');
    $followDecision=(string)($_POST['follow_up_decision']??'');
    if(!in_array($followDecision,['recommended','none'],true))$followDecision=isset($_POST['no_follow_up'])?'none':(($followDate||$followPurpose)?'recommended':'');
    $noFollow=$followDecision==='none';
    $existingCompletion=json_decode((string)($encounter['completion_check_json']??''),true);
    if(!is_array($existingCompletion))$existingCompletion=[];
    $vitalsReview=isset($_POST['vitals_review_acknowledged']);
    $chartReview=isset($_POST['chart_review_acknowledged']);
    $chartReviewMode=(string)($_POST['chart_review_mode']??'');
    if(!in_array($chartReviewMode,['no_changes','updated_findings','continued_planned_treatment','completed_treatment','not_applicable'],true))$chartReviewMode='';
    $medicalAlertReview=isset($_POST['medical_alert_review_acknowledged']);
    $instructionsReview=isset($_POST['instructions_review_acknowledged']);
    $billingReview=isset($_POST['billing_review_acknowledged']);
    $prescriptionDecision=(string)($_POST['prescription_decision']??'');
    if(!in_array($prescriptionDecision,['issued','not_required'],true))$prescriptionDecision=$medications?'issued':'';
    $alertCountStmt=$pdo->prepare('SELECT COUNT(*) FROM `' . table('medical_alerts') . '` WHERE patient_id=? AND is_active=1');
    $alertCountStmt->execute([$patientId]);
    $hasMedicalAlerts=trim((string)($encounter['medical_alerts']??''))!==''||(int)$alertCountStmt->fetchColumn()>0;
    $consent=null;$consentExceptionReason=trim((string)($_POST['consent_exception_reason']??''));
    $procedureRequired=in_array($clinicalDisposition,['treatment_performed','emergency_stabilization'],true);
    $treatmentConsentRequired=$treatmentItemId>0||$procedureRequired||$procedureName!==null||in_array($clinicalDisposition,['medication_administered','diagnostic_procedure'],true);
    $assessmentDomainComplete=count(array_filter([$assessment[0],$assessment[2],$assessment[4],$assessment[6],$assessment[8],$assessment[11]],static fn(string $state):bool=>$state!=='not_examined'))>0;
    $assessmentComplete=!$assessmentRequired||($assessmentDomainComplete&&$examinationSummary!==null);
    $intakeComplete=$intake&&(int)($intake['allergies_confirmed']??0)===1&&(int)($intake['medications_confirmed']??0)===1&&(int)($intake['consent_acknowledged']??0)===1&&$chiefComplaint!==null&&(!$hpiRequired||$historyPresentCondition!==null);
    $vitalsCountStmt=$pdo->prepare('SELECT COUNT(*) FROM `' . table('vital_signs') . '` WHERE encounter_id=? AND (blood_pressure_systolic IS NOT NULL OR blood_pressure_diastolic IS NOT NULL OR bp_repeat_systolic IS NOT NULL OR bp_repeat_diastolic IS NOT NULL OR pulse_rate IS NOT NULL OR temperature_c IS NOT NULL OR respiratory_rate IS NOT NULL OR oxygen_saturation IS NOT NULL OR weight_kg IS NOT NULL OR height_cm IS NOT NULL OR blood_glucose IS NOT NULL)');
    $vitalsCountStmt->execute([$encounterId]);
    $vitalsRecorded=(int)$vitalsCountStmt->fetchColumn()>0;
    $requiresVitals=dental_encounter_requires_vitals($carePath,$procedureRows,$clinicalDisposition,$hasMedicalAlerts,$usageItems);
    $vitalsSkipSelected=isset($_POST['vitals_not_required']);
    $vitalsSkipped=!$requiresVitals&&$vitalsSkipSelected&&mb_strlen(trim((string)$vitalsSkipReason))>=10;
    if($requiresVitals){$vitalsSkipReason=null;$vitalsSkipped=false;}
    if($finalize){
        require_dentist_credentials_verified($userId);
        if($procedureRows){
            foreach($procedureRows as $procedureRow){
                clinical_billing_assert_procedure($procedureRow);
                $rowTreatmentItemId=(int)($procedureRow['treatment_plan_item_id']??0);
                if($rowTreatmentItemId>0){
                    $rowItem=workspace_treatment_item($pdo,$rowTreatmentItemId,$patientId);
                    if(!$rowItem)throw new RuntimeException('A performed procedure is linked to a missing treatment-plan item.');
                    $taskReason=null;
                    if(!dentist_can_work_treatment_item($pdo,$userId,$rowItem,$taskReason))throw new RuntimeException($taskReason?:'You are not assigned or qualified to finalize one of the performed procedures.');
                    if(!in_array((string)$rowItem['status'],['accepted','scheduled','in_progress'],true))throw new RuntimeException((string)$rowItem['procedure_name'].' must be accepted, scheduled, or in progress before completion.');
                }
                $serviceId=(int)($procedureRow['service_id']??0);
                if($serviceId>0){
                    $service=service_definition($serviceId,(int)($encounter['branch_id']??0));
                    if($service&&($service['provider_type']??'dentist')==='dentist'){
                        require_dentist_clinical_privilege($userId,(string)(service_required_privilege_code($service)?:'consultation'));
                    }
                }
            }
        }
        if($treatmentConsentRequired){
            $missingConsent=[];
            foreach($procedureRows as $procedureRow){
                $rowTreatmentItemId=(int)($procedureRow['treatment_plan_item_id']??0);
                $rowConsent=$rowTreatmentItemId>0
                    ? clinical_valid_consent_for_item($pdo,$patientId,$rowTreatmentItemId,$userId)
                    : clinical_valid_consent_for_encounter($pdo,$patientId,$encounterId,$userId);
                if($rowConsent&&!$consent)$consent=$rowConsent;
                if(!$rowConsent)$missingConsent[]=(string)($procedureRow['procedure_name']??'Procedure');
            }
            if(!$procedureRows){
                $consent=clinical_valid_consent_for_encounter($pdo,$patientId,$encounterId,$userId);
                if(!$consent)$missingConsent[]='Encounter procedure';
            }
            if($missingConsent){
                $emergencyException=isset($_POST['emergency_consent_exception']);
                if(!$emergencyException||mb_strlen($consentExceptionReason)<20){
                    $GLOBALS['clinical_finalize_incomplete']=true;
                    $GLOBALS['clinical_finalize_focus']='consent';
                    throw new RuntimeException('Signed consent is missing for: '.implode(', ',array_unique($missingConsent)).'. Link the required consent or document a genuine emergency exception of at least 20 characters.');
                }
            }else{
                $consentExceptionReason='';
            }
        }else{
            $consentExceptionReason='';
        }
        $missing=[];$firstMissingRequirement=null;
        $requirement=static function(string $key,string $label) use (&$missing,&$firstMissingRequirement): void {
            $missing[]=$label;if($firstMissingRequirement===null)$firstMissingRequirement=$key;
        };
        if($chiefComplaint===null)$requirement('intake','Chief complaint');
        if($hpiRequired&&$historyPresentCondition===null)$requirement('intake','History of present condition');
        if($assessmentRequired&&!$assessmentDomainComplete)$requirement('assessment','Examination domain status');
        if($assessmentRequired&&$examinationSummary===null)$requirement('assessment','Examination summary');
        if(!$diagnoses&&!workspace_input('diagnosis_summary'))$requirement('diagnosis','Diagnosis');
        if($clinicalDisposition==='')$requirement('disposition','Clinical disposition');
        if($procedureRequired&&!$procedureName)$requirement('procedure','Procedure performed');
        if($pendingAssistantProcedureRows)$requirement('procedure',count($pendingAssistantProcedureRows).' delegated treatment '.(count($pendingAssistantProcedureRows)===1?'entry':'entries').' awaiting Dentist verification');
        if(in_array($clinicalDisposition,['examination_only','no_treatment_required','observation','treatment_advised_declined','treatment_deferred','referral','medication_prescribed_only','imaging_only'],true)&&!$dispositionReason)$requirement('disposition','Disposition reason');
        if($clinicalDisposition==='medication_prescribed_only'&&!$medications)$requirement('prescription','Prescription medicine');
        if($clinicalDisposition==='medication_administered'&&!array_filter($usageItems,static fn(array $item):bool=>$item['usage_type']==='medication_administered'))$requirement('disposition','Administered medicine record');
        if($clinicalDisposition==='diagnostic_procedure'&&!$procedureName&&!array_filter($usageItems,static fn(array $item):bool=>$item['usage_type']==='diagnostic_service'))$requirement('procedure','Diagnostic procedure or service');
        if(in_array($clinicalDisposition,['treatment_advised_declined','treatment_deferred'],true)&&!workspace_input('treatment_plan'))$requirement('disposition','Proposed or deferred treatment');
        if($treatmentItem&&(string)($treatmentItem['consent_status']??'not_requested')==='declined')$requirement('consent','Treatment-plan consent');
        if(!$intakeComplete)$requirement('intake',$hpiRequired?'Reviewed intake, chief complaint, HPI, allergies, medications, and evaluation acknowledgment':'Focused safety review, chief complaint, allergies, medications, and evaluation acknowledgment');
        if($requiresVitals&&!$vitalsRecorded)$requirement('intake','Vital signs required for this encounter path or clinical risk');
        if($requiresVitals&&!$vitalsReview)$requirement('intake','Vital-sign review acknowledgement');
        if(!$requiresVitals&&!$vitalsReview&&!$vitalsSkipped)$requirement('intake','Vital-sign review or documented not-clinically-required reason');
        if($hasMedicalAlerts&&!$medicalAlertReview)$requirement('alerts','Medical-alert review acknowledgement');
        if(!$chartReview)$requirement('charting','Dental-chart review acknowledgement');
        if($chartReview&&$chartReviewMode==='')$requirement('charting','Dental-chart review result: no changes, updated findings, continued planned treatment, completed treatment, or not applicable');
        if($prescriptionDecision==='')$requirement('prescription','Prescription decision');
        if($prescriptionDecision==='issued'&&!$medications)$requirement('prescription','Prescription medicine or mark prescription not required');
        if($prescriptionDecision==='not_required'&&$medications)$requirement('prescription','Prescription decision matching the entered medicine');
        if($procedureRequired&&(!$patientAdvice||!$instructionsReview))$requirement('instructions','Post-treatment instructions and confirmation');
        elseif(!$instructionsReview)$requirement('instructions','Patient advice or discharge-instruction confirmation');
        if(!$billingReview)$requirement('billing','Billing handoff review');
        if($medications&&!isset($_POST['allergy_review_acknowledged']))$requirement('prescription','Dental prescription allergy and medicine review acknowledgement');
        foreach($medications as $index=>$medicine){
            foreach(['indication'=>'indication','strength'=>'strength','dosage'=>'dosage','frequency'=>'frequency','route'=>'route','duration_days'=>'duration','quantity'=>'quantity','instructions'=>'instructions'] as $key=>$label){
                if(empty($medicine[$key]))$requirement('prescription','Medicine '.($index+1).' '.$label);
            }
        }
        if($followDecision==='')$requirement('followup','Follow-up decision');
        elseif(!$noFollow&&(!$followDate||!$followPurpose))$requirement('followup','Follow-up purpose and recommended date');
        if($missing){
            $GLOBALS['clinical_finalize_incomplete']=true;
            $GLOBALS['clinical_finalize_focus']=$firstMissingRequirement;
            throw new RuntimeException('The encounter was not finalized. Complete: '.implode(', ',array_values(array_unique($missing))).'.');
        }
    }
    $completion=[
        'intake'=>$intakeComplete,
        'assessment'=>$assessmentComplete,
        'diagnosis'=>!empty($diagnoses)||$primaryDiagnosis,
        'clinical_disposition'=>$clinicalDisposition!=='',
        'procedure'=>!$procedureRequired||(bool)$procedureName,
        'resources'=>!empty($usageItems),
        'soap'=>(bool)workspace_input('soap_note'),
        'prescription'=>!empty($medications),
        'follow_up'=>$noFollow||($followDate&&$followPurpose),
        'consent_required'=>$treatmentConsentRequired,
        'consent_form_id'=>$consent?(int)$consent['id']:null,
        'consent_exception'=>(bool)$consentExceptionReason,
        'care_path'=>$carePath,
        'hpi_required'=>$hpiRequired,
        'assessment_required'=>$assessmentRequired,
        'vitals_required'=>$requiresVitals,
        'vitals_recorded'=>$vitalsRecorded,
        'vitals_review'=>$vitalsReview,
        'vitals_skipped'=>$vitalsSkipped,
        'vitals_skip_reason'=>$vitalsSkipped?$vitalsSkipReason:null,
        'medical_alert_review'=>!$hasMedicalAlerts||$medicalAlertReview,
        'chart_review'=>$chartReview,
        'chart_review_mode'=>$chartReviewMode,
        'prescription_decision'=>$prescriptionDecision,
        'instructions_review'=>$instructionsReview,
        'billing_review'=>$billingReview,
        'completion_destination'=>$finalize?$completionDestination:null,
    ];
    $pdo->prepare('UPDATE `' . table('clinical_encounters') . '` SET consent_form_id=?,consent_exception_reason=?,care_path=?,vitals_skip_reason=?,chief_complaint=?,history_present_condition=?,examination=?,diagnosis=?,treatment_plan=?,clinical_disposition=?,disposition_reason=?,patient_advice=?,procedure_done=?,soap_note=?,prescription=?,follow_up_date=?,follow_up_purpose=?,follow_up_urgency=?,disposition=?,status=?,completion_check_json=?,updated_at=NOW(),autosaved_at=NOW(),finalized_at=IF(?="finalized",NOW(),finalized_at) WHERE id=?')->execute([
        $consent?(int)$consent['id']:null,$consentExceptionReason?:null,$carePath,$vitalsSkipped?$vitalsSkipReason:null,$chiefComplaint,$historyPresentCondition,$examinationSummary,$primaryDiagnosis,workspace_input('treatment_plan'),$clinicalDisposition?:null,$dispositionReason,$patientAdvice,$procedureName,$soapNote,workspace_input('prescription_summary'),$followDate,$followPurpose,workspace_input('follow_up_urgency'),$noFollow?'no_follow_up':($followDate?'follow_up_planned':'pending'),$finalize?'finalized':'draft',json_encode($completion,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),$finalize?'finalized':'draft',$encounterId
    ]);
    $pdo->prepare('INSERT INTO `' . table('clinical_assessments') . '` (encounter_id,patient_id,extraoral_status,extraoral_findings,intraoral_status,intraoral_findings,soft_tissue_status,soft_tissue_findings,tmj_status,tmj_findings,occlusion_status,occlusion_findings,oral_hygiene_status,radiographic_status,radiographic_findings,risk_assessment,prognosis,recorded_by,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW(),NOW()) ON DUPLICATE KEY UPDATE extraoral_status=VALUES(extraoral_status),extraoral_findings=VALUES(extraoral_findings),intraoral_status=VALUES(intraoral_status),intraoral_findings=VALUES(intraoral_findings),soft_tissue_status=VALUES(soft_tissue_status),soft_tissue_findings=VALUES(soft_tissue_findings),tmj_status=VALUES(tmj_status),tmj_findings=VALUES(tmj_findings),occlusion_status=VALUES(occlusion_status),occlusion_findings=VALUES(occlusion_findings),oral_hygiene_status=VALUES(oral_hygiene_status),radiographic_status=VALUES(radiographic_status),radiographic_findings=VALUES(radiographic_findings),risk_assessment=VALUES(risk_assessment),prognosis=VALUES(prognosis),recorded_by=VALUES(recorded_by),updated_at=NOW()')->execute(array_merge([$encounterId,$patientId],$assessment,[$userId]));
    $existingDiagnosisStmt=$pdo->prepare('SELECT id FROM `' . table('diagnoses') . '` WHERE encounter_id=?');
    $existingDiagnosisStmt->execute([$encounterId]);
    $existingDiagnosisIds=array_map('intval',$existingDiagnosisStmt->fetchAll(PDO::FETCH_COLUMN));
    $keptDiagnosisIds=[];
    $diagInsert=$pdo->prepare('INSERT INTO `' . table('diagnoses') . '` (patient_id,encounter_id,tooth_region,diagnosis_code,diagnosis_name,severity,diagnosis_status,is_primary,notes,diagnosed_by,diagnosed_at) VALUES (?,?,?,?,?,?,?,?,?,?,NOW())');
    $diagUpdate=$pdo->prepare('UPDATE `' . table('diagnoses') . '` SET tooth_region=?,diagnosis_code=?,diagnosis_name=?,severity=?,diagnosis_status=?,is_primary=?,notes=?,diagnosed_by=?,diagnosed_at=NOW() WHERE id=? AND encounter_id=?');
    foreach($diagnoses as $i=>$row){
        $diagnosisId=(int)($row['id']??0);
        if($diagnosisId>0&&in_array($diagnosisId,$existingDiagnosisIds,true)){
            $diagUpdate->execute([$row['region'],$row['code'],$row['name'],$row['severity'],$row['status'],$i===0?1:0,$row['notes'],$userId,$diagnosisId,$encounterId]);
        }else{
            $diagInsert->execute([$patientId,$encounterId,$row['region'],$row['code'],$row['name'],$row['severity'],$row['status'],$i===0?1:0,$row['notes'],$userId]);
            $diagnosisId=(int)$pdo->lastInsertId();
        }
        $keptDiagnosisIds[]=$diagnosisId;
        workspace_sync_diagnosis_chart($pdo,$encounter,$row,$diagnosisId,$userId);
    }
    $removedDiagnosisIds=array_values(array_diff($existingDiagnosisIds,$keptDiagnosisIds));
    if($removedDiagnosisIds){
        $placeholders=implode(',',array_fill(0,count($removedDiagnosisIds),'?'));
        if(schema_table_exists(table('odontogram_entries'))){
            $pdo->prepare('UPDATE `' . table('odontogram_entries') . '` SET status=IF(finding_type="diagnosis","superseded",status),resolved_by=IF(finding_type="diagnosis",?,resolved_by),resolved_at=IF(finding_type="diagnosis",NOW(),resolved_at),diagnosis_id=NULL WHERE diagnosis_id IN ('.$placeholders.')')->execute(array_merge([$userId],$removedDiagnosisIds));
        }
        $pdo->prepare('DELETE FROM `' . table('diagnoses') . '` WHERE encounter_id=? AND id IN ('.$placeholders.')')->execute(array_merge([$encounterId],$removedDiagnosisIds));
    }
    $procedureId=0;
    if($procedureRows){
        $procedureId=(int)$procedureRows[0]['id'];
        if($finalize){
            foreach($procedureRows as $procedureRow){
                $rowStatus=(string)($procedureRow['status']??'');
                if(in_array($rowStatus,['deferred','moved_follow_up','not_performed','cancelled'],true)){
                    if(schema_column_exists(table('procedures'),'billing_status')){
                        if(schema_column_exists(table('procedures'),'cashier_handoff_status')){
                            $pdo->prepare('UPDATE `' . table('procedures') . '` SET billing_status="not_billable",cashier_handoff_status=IF(COALESCE(cashier_handoff_status,"")="sent_to_cashier",cashier_handoff_status,"excluded"),ended_at=COALESCE(ended_at,NOW()) WHERE id=? AND encounter_id=?')->execute([(int)$procedureRow['id'],$encounterId]);
                        }else{
                            $pdo->prepare('UPDATE `' . table('procedures') . '` SET billing_status="not_billable",ended_at=COALESCE(ended_at,NOW()) WHERE id=? AND encounter_id=?')->execute([(int)$procedureRow['id'],$encounterId]);
                        }
                    }
                    continue;
                }
                clinical_billing_assert_procedure($procedureRow);
                $rowItemId=(int)($procedureRow['treatment_plan_item_id']??0);
                $rowConsent=$rowItemId>0
                    ? clinical_valid_consent_for_item($pdo,$patientId,$rowItemId,$userId)
                    : clinical_valid_consent_for_encounter($pdo,$patientId,$encounterId,$userId);
                $pdo->prepare('UPDATE `' . table('procedures') . '` SET consent_form_id=?,status="completed",ended_at=COALESCE(ended_at,NOW()),billing_status=IF(fee_status="no_charge","no_charge","ready") WHERE id=? AND encounter_id=?')
                    ->execute([$rowConsent?(int)$rowConsent['id']:($consent?(int)$consent['id']:null),(int)$procedureRow['id'],$encounterId]);
                if($rowItemId>0){
                    $rowItem=workspace_treatment_item($pdo,$rowItemId,$patientId);
                    if($rowItem){
                        workspace_sync_treatment_item($pdo,$rowItem,$encounterId,true,$userId);
                        if(clinical_task_assignment_schema_ready()){
                            $pdo->prepare('UPDATE `' . table('clinical_task_assignments') . '` SET status="completed",completed_by=?,completed_at=NOW(),completion_encounter_id=?,updated_at=NOW() WHERE treatment_plan_item_id=? AND assigned_dentist_user_id=? AND status IN ("accepted","in_progress")')
                                ->execute([$userId,$encounterId,$rowItemId,$userId]);
                        }
                    }
                }
            }
            $procedureRows=clinical_billing_procedures($pdo,$encounterId,true);
        }
    }
    $savedUsageItems=workspace_save_usage_items($pdo,$encounter,$usageItems,$finalize,$userId);
    if($finalize && $medications){
        $profile=dentist_profile($userId) ?: [];
        $signedName=dentist_display_name($profile);
        $signedLicense=trim((string)($profile['license_number']??''));
        $signedSignature=trim((string)($profile['prescription_signature_path']??$profile['signature_path']??'')) ?: null;
        $clinicalIndication=workspace_input('prescription_indication') ?: $primaryDiagnosis;
        if(!$clinicalIndication)throw new RuntimeException('Record the clinical indication for the prescription.');
        $reviewSnapshot=json_encode(['reviewed_at'=>date('c'),'reviewed_by'=>$userId,'allergy_acknowledged'=>true,'patient_id'=>$patientId,'safety_status'=>clinical_safety_storage_status((array)$prescriptionSafetyAssessment),'safety_counts'=>$prescriptionSafetyAssessment['counts']??[],'safety_context_hash'=>$prescriptionSafetyAssessment['context_hash']??null],JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        $existing=$pdo->prepare('SELECT id,prescription_no FROM `' . table('prescriptions') . '` WHERE encounter_id=? AND status="issued" LIMIT 1 FOR UPDATE');
        $existing->execute([$encounterId]);
        $existingRx=$existing->fetch()?:[];
        $rxId=(int)($existingRx['id']??0);
        $rxNo=(string)($existingRx['prescription_no']??'');
        if(!$rxId){
            $rxNo='RX-'.date('ymd').'-'.random_int(1000,9999);
            $pdo->prepare('INSERT INTO `' . table('prescriptions') . '` (patient_id,encounter_id,dentist_user_id,prescription_no,status,clinical_indication,review_snapshot_json,signed_by_name,signed_license_number,signed_signature_path,notes,created_at) VALUES (?,?,?,? ,"issued",?,?,?,?,?,?,NOW())')->execute([$patientId,$encounterId,$userId,$rxNo,$clinicalIndication,$reviewSnapshot,$signedName,$signedLicense,$signedSignature,workspace_input('prescription_notes')]);
            $rxId=(int)$pdo->lastInsertId();
        }else{
            $pdo->prepare('UPDATE `' . table('prescriptions') . '` SET clinical_indication=?,review_snapshot_json=?,signed_by_name=?,signed_license_number=?,signed_signature_path=?,notes=? WHERE id=?')->execute([$clinicalIndication,$reviewSnapshot,$signedName,$signedLicense,$signedSignature,workspace_input('prescription_notes'),$rxId]);
        }
        $pdo->prepare('DELETE FROM `' . table('prescription_items') . '` WHERE prescription_id=?')->execute([$rxId]);
        if(schema_column_exists(table('prescription_items'),'medicine_catalog_id')){
            $itemInsert=$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($medications as $item){
                $itemInsert->execute([$rxId,$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{
            $itemInsert=$pdo->prepare('INSERT INTO `' . table('prescription_items') . '` (prescription_id,medication_name,generic_name,indication,strength,dosage,frequency,route,duration_days,quantity,instructions) VALUES (?,?,?,?,?,?,?,?,?,?,?)');
            foreach($medications as $item){
                $itemInsert->execute([$rxId,$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,$rxId,$patientId,$encounterId,$userId,(array)$prescriptionSafetyAssessment,$prescriptionSafetyOverrideReason);
        $rxPayload=['id'=>$rxId,'prescription_no'=>$rxNo,'patient_id'=>$patientId,'encounter_id'=>$encounterId,'dentist_user_id'=>$userId,'clinical_indication'=>$clinicalIndication,'items'=>$medications,'notes'=>workspace_input('prescription_notes'),'signed_by_name'=>$signedName,'signed_license_number'=>$signedLicense,'safety_assessment_id'=>$safetyAssessmentId,'safety_status'=>clinical_safety_storage_status((array)$prescriptionSafetyAssessment),'safety_context_hash'=>$prescriptionSafetyAssessment['context_hash']??null];
        $rxHash=hash('sha256',(string)json_encode($rxPayload,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
        $pdo->prepare('UPDATE `' . table('prescriptions') . '` SET prescription_hash=? WHERE id=?')->execute([$rxHash,$rxId]);
    }
    $followId=0;
    if($finalize && !$noFollow && $followDate && $followPurpose){
        $stmt=$pdo->prepare('SELECT id FROM `' . table('follow_ups') . '` WHERE encounter_id=? AND status IN ("pending","scheduled") ORDER BY id DESC LIMIT 1');$stmt->execute([$encounterId]);$followId=(int)($stmt->fetchColumn()?:0);
        $branchId=(int)($encounter['branch_id']??0)?:null;$serviceId=(int)($_POST['follow_up_service_id']??0)?:null;$duration=max(15,(int)($_POST['follow_up_duration']??30));$preferred=workspace_input('follow_up_time');$urgency=in_array(($_POST['follow_up_urgency']??''),['routine','important','urgent'],true)?$_POST['follow_up_urgency']:'routine';
        if($followId)$pdo->prepare('UPDATE `' . table('follow_ups') . '` SET branch_id=?,service_id=?,dentist_user_id=?,purpose=?,recommended_date=?,preferred_time=?,duration_minutes=?,urgency=?,instructions=?,status="pending" WHERE id=?')->execute([$branchId,$serviceId,$userId,$followPurpose,$followDate,$preferred,$duration,$urgency,workspace_input('follow_up_instructions'),$followId]);
        else{$pdo->prepare('INSERT INTO `' . table('follow_ups') . '` (patient_id,branch_id,service_id,encounter_id,dentist_user_id,purpose,recommended_date,preferred_time,duration_minutes,urgency,status,instructions,created_at) VALUES (?,?,?,?,?,?,?,?,?,? ,"pending",?,NOW())')->execute([$patientId,$branchId,$serviceId,$encounterId,$userId,$followPurpose,$followDate,$preferred,$duration,$urgency,workspace_input('follow_up_instructions')]);$followId=(int)$pdo->lastInsertId();}
    }
    return ['diagnoses'=>$diagnoses,'follow_up_id'=>$followId,'treatment_item'=>$treatmentItem,'treatment_plan_item_id'=>$treatmentItemId,'procedure_id'=>(int)($procedureId??0),'usage_items'=>$savedUsageItems,'clinical_disposition'=>$clinicalDisposition,'consent_form_id'=>$consent?(int)$consent['id']:null,'consent_exception'=>$consentExceptionReason?:null];
}


function workspace_snapshot_rows(PDO $pdo,string $sql,array $args): array
{
    $stmt=$pdo->prepare($sql);$stmt->execute($args);return $stmt->fetchAll()?:[];
}

function workspace_billable_handoff_total(PDO $pdo,int $encounterId,array $procedures): float
{
    $total=0.0;
    foreach($procedures as $row){
        if(!clinical_billing_is_performed($row))continue;
        if(clinical_billing_procedure_fee_status($row)==='billable')$total+=round((float)($row['approved_fee_snapshot']??0),2);
    }
    $stmt=$pdo->prepare('SELECT COALESCE(SUM(quantity*unit_price),0) FROM `' . table('clinical_usage_items') . '` WHERE encounter_id=? AND fulfillment_status<>"cancelled" AND billing_mode="bill_separately"');
    $stmt->execute([$encounterId]);
    $total+=round((float)$stmt->fetchColumn(),2);
    return round($total,2);
}

function workspace_build_discharge_summary(PDO $pdo,array $encounter,string $destination,float $handoffAmount,?string $noPaymentReason): array
{
    $encounterId=(int)$encounter['id'];
    $procedures=workspace_snapshot_rows($pdo,'SELECT p.procedure_name,p.tooth_region,p.anesthetic,p.materials,p.complications,p.outcome,p.approved_fee_snapshot,p.fee_status,p.status,p.entered_by_role,p.verified_at,du.name responsible_dentist,au.name dental_assistant,eu.name entered_by,vu.name verified_by FROM `' . table('procedures') . '` p LEFT JOIN `' . table('users') . '` du ON du.id=p.dentist_user_id LEFT JOIN `' . table('users') . '` au ON au.id=p.assistant_user_id LEFT JOIN `' . table('users') . '` eu ON eu.id=p.entered_by_user_id LEFT JOIN `' . table('users') . '` vu ON vu.id=p.verified_by_user_id WHERE p.encounter_id=? ORDER BY p.id',[$encounterId]);
    $medications=workspace_snapshot_rows($pdo,'SELECT pi.medication_name,pi.generic_name,pi.strength,pi.dosage,pi.frequency,pi.route,pi.duration_days,pi.quantity,pi.instructions FROM `' . table('prescription_items') . '` pi JOIN `' . table('prescriptions') . '` p ON p.id=pi.prescription_id WHERE p.encounter_id=? AND p.status<>"cancelled" ORDER BY pi.id',[$encounterId]);
    $followups=workspace_snapshot_rows($pdo,'SELECT purpose,recommended_date,preferred_time,duration_minutes,urgency,instructions,status FROM `' . table('follow_ups') . '` WHERE encounter_id=? ORDER BY id',[$encounterId]);
    $usage=workspace_snapshot_rows($pdo,'SELECT usage_type,description,quantity,unit,billing_mode,unit_price,notes FROM `' . table('clinical_usage_items') . '` WHERE encounter_id=? AND fulfillment_status<>"cancelled" ORDER BY id',[$encounterId]);
    return [
        'version'=>'0.8.0.4',
        'generated_at'=>date('c'),
        'encounter_id'=>$encounterId,
        'patient_id'=>(int)$encounter['patient_id'],
        'destination'=>$destination,
        'diagnosis'=>(string)($encounter['diagnosis']??''),
        'care_path'=>dental_encounter_care_path((string)($encounter['care_path']??'comprehensive')),
        'care_path_label'=>dental_encounter_care_path_label((string)($encounter['care_path']??'comprehensive')),
        'vitals_skip_reason'=>trim((string)($encounter['vitals_skip_reason']??''))?:null,
        'clinical_disposition'=>(string)($encounter['clinical_disposition']??''),
        'disposition_reason'=>(string)($encounter['disposition_reason']??''),
        'patient_advice'=>(string)($encounter['patient_advice']??''),
        'procedures'=>$procedures,
        'medications'=>$medications,
        'clinical_usage'=>$usage,
        'follow_up'=>$followups,
        'billing_handoff_amount'=>$handoffAmount,
        'no_payment_reason'=>$noPaymentReason,
        'care_team'=>[
            'dentist'=>['user_id'=>(int)$encounter['dentist_user_id'],'name'=>(string)$encounter['dentist_name']],
            'dental_assistant'=>['decision'=>clinical_assistant_decision($encounter),'user_id'=>(int)($encounter['assistant_user_id']??0)?:null,'name'=>(string)($encounter['assistant_name']??''),'assigned_at'=>$encounter['assistant_assigned_at']??null,'decided_by'=>(int)($encounter['assistant_decided_by']??0)?:null,'decided_at'=>$encounter['assistant_decided_at']??null],
        ],
        'dentist'=>[
            'user_id'=>(int)$encounter['dentist_user_id'],
            'name'=>(string)$encounter['dentist_name'],
        ],
    ];
}

function workspace_apply_signer_snapshot(PDO $pdo,int $encounterId,int $dentistUserId): void
{
    require_dentist_credentials_verified($dentistUserId);
    $profile=dentist_profile($dentistUserId) ?: [];
    $user=current_user() ?? [];
    $name=$profile ? dentist_display_name($profile) : (string)($user['name']??'Dentist');
    $license=trim((string)($profile['license_number']??''));
    $signature=trim((string)($profile['signature_path']??'')) ?: null;
    if($license==='')throw new RuntimeException('A verified professional license number is required to sign the clinical record.');

    $stmt=$pdo->prepare('SELECT * FROM `' . table('clinical_encounters') . '` WHERE id=? FOR UPDATE');
    $stmt->execute([$encounterId]);
    $encounter=$stmt->fetch();
    if(!$encounter)throw new RuntimeException('Clinical encounter not found while preparing the signed record.');
    $patientId=(int)$encounter['patient_id'];
    $snapshot=[
        'snapshot_version'=>'0.9.1.0',
        'generated_at'=>date('c'),
        'encounter'=>$encounter,
        'intake'=>workspace_snapshot_rows($pdo,'SELECT * FROM `' . table('patient_intakes') . '` WHERE patient_id=? AND (queue_entry_id=? OR appointment_id=?) ORDER BY id DESC LIMIT 1',[$patientId,(int)($encounter['queue_entry_id']??0),(int)($encounter['appointment_id']??0)]),
        'dental_safety_assessment'=>dental_safety_assessment_schema_ready()?workspace_snapshot_rows($pdo,'SELECT * FROM `' . table('dental_safety_assessments') . '` WHERE id=? LIMIT 1',[(int)($encounter['dental_safety_assessment_id']??0)]):[],
        'vital_signs'=>workspace_snapshot_rows($pdo,'SELECT * FROM `' . table('vital_signs') . '` WHERE encounter_id=? ORDER BY id',[$encounterId]),
        'assessment'=>workspace_snapshot_rows($pdo,'SELECT * FROM `' . table('clinical_assessments') . '` WHERE encounter_id=? ORDER BY id',[$encounterId]),
        'diagnoses'=>workspace_snapshot_rows($pdo,'SELECT * FROM `' . table('diagnoses') . '` WHERE encounter_id=? ORDER BY is_primary DESC,id',[$encounterId]),
        'procedures'=>workspace_snapshot_rows($pdo,'SELECT * FROM `' . table('procedures') . '` WHERE encounter_id=? ORDER BY id',[$encounterId]),
        'clinical_usage'=>workspace_snapshot_rows($pdo,'SELECT * FROM `' . table('clinical_usage_items') . '` WHERE encounter_id=? ORDER BY id',[$encounterId]),
        'consent'=>workspace_snapshot_rows($pdo,'SELECT id,patient_id,encounter_id,treatment_plan_item_id,consent_type,version_no,signer_name,signer_type,signer_relationship,status,signed_at,expires_at,dentist_user_id,form_hash,signature_hash FROM `' . table('consent_forms') . '` WHERE id=?',[(int)($encounter['consent_form_id']??0)]),
        'prescriptions'=>workspace_snapshot_rows($pdo,'SELECT * FROM `' . table('prescriptions') . '` WHERE encounter_id=? ORDER BY id',[$encounterId]),
        'prescription_items'=>workspace_snapshot_rows($pdo,'SELECT pi.* FROM `' . table('prescription_items') . '` pi JOIN `' . table('prescriptions') . '` p ON p.id=pi.prescription_id WHERE p.encounter_id=? ORDER BY pi.id',[$encounterId]),
        'follow_ups'=>workspace_snapshot_rows($pdo,'SELECT * FROM `' . table('follow_ups') . '` WHERE encounter_id=? ORDER BY id',[$encounterId]),
        'treatment_items'=>workspace_snapshot_rows($pdo,'SELECT i.* FROM `' . table('treatment_plan_items') . '` i JOIN `' . table('procedures') . '` pr ON pr.treatment_plan_item_id=i.id WHERE pr.encounter_id=? ORDER BY i.id',[$encounterId]),
        'signer'=>['user_id'=>$dentistUserId,'name'=>$name,'license_number'=>$license,'signature_path'=>$signature],
    ];
    $json=(string)json_encode($snapshot,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES|JSON_PRESERVE_ZERO_FRACTION);
    if($json===''||$json==='false')throw new RuntimeException('The complete clinical record snapshot could not be generated.');
    $hash=hash('sha256',$json);
    $pdo->prepare('UPDATE `' . table('clinical_encounters') . '` SET signed_by_name=?,signed_license_number=?,signed_signature_path=?,finalized_snapshot_json=?,finalized_hash=? WHERE id=? AND status="finalized"')
        ->execute([$name,$license,$signature,$json,$hash,$encounterId]);
}

if($_SERVER['REQUEST_METHOD']==='POST'){
    try{
        verify_csrf();
        $action=(string)($_POST['action']??'');
        if($action==='start'){
            $supervisedStart = !$isDentist && has_role(['super_admin','clinic_admin']) && !empty($_POST['supervised_start']);
            if(!$isDentist && !$supervisedStart)throw new RuntimeException('Only the authenticated dentist can start a clinical encounter. Admin/Superuser may use supervised start only from the queue when an assigned dentist is selected.');
            $queueId=(int)($_POST['queue_id']??0);
            if($queueId<=0)throw new RuntimeException('Select a queue patient.');
            $previewStmt=$pdo->prepare('SELECT * FROM `' . table('queue_entries') . '` WHERE id=? LIMIT 1');
            $previewStmt->execute([$queueId]);
            $queuePreview=$previewStmt->fetch();
            if(!$queuePreview)throw new RuntimeException('Queue entry not found.');
            $chairLockName=queue_acquire_chair_lock($pdo,$queuePreview);
            $releasedTickets=[];
            try{
                $pdo->beginTransaction();
                $stmt=$pdo->prepare('SELECT q.*,p.first_name,p.last_name FROM `' . table('queue_entries') . '` q JOIN `' . table('patients') . '` p ON p.id=q.patient_id WHERE q.id=? FOR UPDATE');
                $stmt->execute([$queueId]);
                $queue=$stmt->fetch();
                if(!$queue)throw new RuntimeException('Queue entry not found.');
                if(($queue['provider_type']??'dentist')==='inhouse')throw new RuntimeException('This is an in-house service and does not require a dentist clinical encounter.');
                $responsibleDentistId=(int)($queue['dentist_user_id']??0);
                if($responsibleDentistId<1)throw new RuntimeException('Assign a responsible dentist before starting treatment.');
                if(!$supervisedStart && $responsibleDentistId!==$userId)throw new RuntimeException('This patient is assigned to another dentist.');
                require_dentist_clinical_privilege($responsibleDentistId,'consultation');
                if(!dental_adaptive_encounter_schema_ready())throw new RuntimeException('Apply Version 0.8.0.4 before starting treatment. The adaptive encounter path must be recorded first.');
                $startCarePath=dental_encounter_care_path((string)($_POST['care_path']??dental_encounter_default_care_path($queue)));
                $assistantStartPrompted = !empty($_POST['start_assistant_prompted']);
                $startAssistantId = $assistantStartPrompted ? (int)($_POST['assistant_user_id'] ?? 0) : 0;
                $startAssistantName = null;
                $startAssistantDecision = null;
                if ($assistantStartPrompted) {
                    if (!clinical_flow_stability_schema_ready()) throw new RuntimeException('Apply Version 0.7.9.2 before starting treatment. The assistant-or-none decision must be recorded explicitly.');
                    $assistant = workspace_resolve_start_assistant($pdo, $startAssistantId, (int)($queue['branch_id'] ?? 0));
                    if ($assistant) $startAssistantName = trim((string)$assistant['name']);
                    $startAssistantDecision = [
                        'assistant_user_id' => $startAssistantId > 0 ? $startAssistantId : null,
                        'assistant_name' => $startAssistantName,
                        'decision' => $startAssistantId > 0 ? 'assigned' : 'none',
                    ];
                }
                $queueStatus=(string)$queue['status'];
                if(!in_array($queueStatus,['seated','in_treatment'],true)){
                    throw new RuntimeException('Seat the patient in the assigned chair before starting treatment. Current status: '.ucwords(str_replace('_',' ',$queueStatus)).'.');
                }
                $safetyGate=dental_safety_assert_treatment_ready($pdo,$queue,$startCarePath);
                $safetyAssessmentId=(int)($safetyGate['assessment']['id']??0);
                $releasedTickets=queue_resolve_duplicate_seating_for_start($pdo,$queue,$userId);
                $active=$pdo->prepare('SELECT queue_no FROM `' . table('queue_entries') . '` WHERE branch_id=? AND dentist_user_id=? AND id<>? AND status="in_treatment" AND DATE(checked_in_at)=CURDATE() LIMIT 1 FOR UPDATE');
                $active->execute([(int)($queue['branch_id']??0),$responsibleDentistId,$queueId]);
                if($activeTicket=$active->fetchColumn())throw new RuntimeException('Complete or pause the active treatment for '.$activeTicket.' before starting another patient.');
                $stmt=$pdo->prepare('SELECT id FROM `' . table('clinical_encounters') . '` WHERE queue_entry_id=? ORDER BY id DESC LIMIT 1 FOR UPDATE');
                $stmt->execute([$queueId]);
                $encounterId=(int)($stmt->fetchColumn()?:0);
                if(!$encounterId){
                    $profile=dentist_profile($responsibleDentistId);
                    $display=$profile?dentist_display_name($profile):user_display_name_by_id($responsibleDentistId);
                    if($display==='')$display='Assigned Dentist';
                    $intake=active_patient_intake((int)$queue['patient_id'],$queueId,(int)($queue['appointment_id']??0)?:null);
                    $chief=(string)($intake['chief_complaint']??$queue['reason']??'');
                    $hpi=(string)($intake['history_present_condition']??'');
                    $pdo->prepare('INSERT INTO `' . table('clinical_encounters') . '` (branch_id,patient_id,appointment_id,queue_entry_id,dental_safety_assessment_id,dentist_user_id,dentist_name,visit_type,care_path,care_path_decided_by,care_path_decided_at,chief_complaint,history_present_condition,status,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,NOW(),?,?,"draft",NOW(),NOW())')->execute([(int)($queue['branch_id']??0)?:null,(int)$queue['patient_id'],(int)($queue['appointment_id']??0)?:null,$queueId,$safetyAssessmentId?:null,$responsibleDentistId,$display,(string)($queue['source_type']??'scheduled'),$startCarePath,$userId,$chief,$hpi]);
                    $encounterId=(int)$pdo->lastInsertId();
                }
                if($safetyAssessmentId>0){
                    $pdo->prepare('UPDATE `' . table('clinical_encounters') . '` SET dental_safety_assessment_id=COALESCE(dental_safety_assessment_id,?),updated_at=NOW() WHERE id=?')->execute([$safetyAssessmentId,$encounterId]);
                    $pdo->prepare('UPDATE `' . table('vital_signs') . '` SET encounter_id=COALESCE(encounter_id,?) WHERE dental_safety_assessment_id=?')->execute([$encounterId,$safetyAssessmentId]);
                }
                if(!clinical_flow_stability_schema_ready())throw new RuntimeException('Apply Version 0.7.9.2 before opening a treatment encounter. The assistant-or-none decision must be recorded explicitly.');
                $pdo->prepare('UPDATE `' . table('clinical_encounters') . '` SET care_path=?,care_path_decided_by=?,care_path_decided_at=COALESCE(care_path_decided_at,NOW()),updated_at=NOW() WHERE id=?')->execute([$startCarePath,$userId,$encounterId]);
                $decisionStmt=$pdo->prepare('SELECT assistant_user_id,assistant_name,assistant_decision,care_path FROM `' . table('clinical_encounters') . '` WHERE id=? FOR UPDATE');
                $decisionStmt->execute([$encounterId]);
                $decisionEncounter=$decisionStmt->fetch()?:[];
                if(!$assistantStartPrompted && !clinical_assistant_decision_complete($decisionEncounter)){
                    throw new RuntimeException('Confirm whether a Dental Assistant is participating before opening this treatment encounter.');
                }
                if($assistantStartPrompted && encounter_assistant_schema_ready()){
                    $decision=$startAssistantId>0?'assigned':'none';
                    $pdo->prepare('UPDATE `' . table('clinical_encounters') . '` SET assistant_user_id=?,assistant_name=?,assistant_assigned_by=?,assistant_assigned_at=?,assistant_decision=?,assistant_decided_by=?,assistant_decided_at=NOW(),updated_at=NOW() WHERE id=?')
                        ->execute([$startAssistantId>0?$startAssistantId:null,$startAssistantName,$startAssistantId>0?$userId:null,$startAssistantId>0?date('Y-m-d H:i:s'):null,$decision,$userId,$encounterId]);
                }
                if($queueStatus!=='in_treatment'){
                    $queueUpdate=$pdo->prepare('UPDATE `' . table('queue_entries') . '` SET status="in_treatment",treatment_started_at=COALESCE(treatment_started_at,NOW()),updated_at=NOW() WHERE id=? AND status=?');
                    $queueUpdate->execute([$queueId,$queueStatus]);
                    if($queueUpdate->rowCount()!==1)throw new RuntimeException('The queue state changed while treatment was starting.');
                    $pdo->prepare('INSERT INTO `' . table('queue_status_history') . '` (queue_entry_id,previous_status,new_status,notes,changed_by,created_at) VALUES (?,? ,"in_treatment","Clinical encounter opened",?,NOW())')->execute([$queueId,$queueStatus,$userId]);
                    if(!empty($queue['appointment_id'])){
                        $appointmentLock=$pdo->prepare('SELECT status,start_at FROM `' . table('appointments') . '` WHERE id=? FOR UPDATE');
                        $appointmentLock->execute([(int)$queue['appointment_id']]);
                        $appointmentState=$appointmentLock->fetch();
                        if(!$appointmentState)throw new RuntimeException('The linked appointment could not be verified.');
                        integrity_assert_appointment_transition((string)$appointmentState['status'],'in_treatment',(string)$appointmentState['start_at']);
                        $appointmentUpdate=$pdo->prepare('UPDATE `' . table('appointments') . '` SET status="in_treatment",updated_at=NOW() WHERE id=? AND status=?');
                        $appointmentUpdate->execute([(int)$queue['appointment_id'],(string)$appointmentState['status']]);
                        if($appointmentUpdate->rowCount()!==1)throw new RuntimeException('The linked appointment changed while treatment was starting.');
                        if(schema_table_exists(table('appointment_status_history')))$pdo->prepare('INSERT INTO `' . table('appointment_status_history') . '` (appointment_id,previous_status,new_status,reason,changed_by,created_at) VALUES (?,? ,"in_treatment","Treatment started by assigned dentist",?,NOW())')->execute([(int)$queue['appointment_id'],(string)$appointmentState['status'],$userId]);
                    }
                }
                if(workflow_governance_schema_ready())$pdo->prepare('UPDATE `' . table('clinical_encounters') . '` SET paused_at=NULL,pause_reason=NULL,paused_by=NULL,pause_releases_chair=1,updated_at=NOW() WHERE id=?')->execute([$encounterId]);
                audit_required($queueStatus==='in_treatment'?'clinical_encounter_reopened':'clinical_encounter_started','clinical_encounter',$encounterId,['queue_entry_id'=>$queueId,'released_duplicate_seating'=>$releasedTickets,'supervised_start'=>!empty($supervisedStart),'responsible_dentist_user_id'=>$responsibleDentistId??null,'start_assistant_decision'=>$startAssistantDecision??null,'care_path'=>$startCarePath]);
                $pdo->commit();
            }finally{
                if($pdo->inTransaction())$pdo->rollBack();
                queue_release_chair_lock($pdo,$chairLockName);
            }
            workflow_event((int)$queue['patient_id'],'clinical_started',$queueStatus==='in_treatment'?'Clinical encounter reopened':'Clinical encounter started',['appointment_id'=>(int)($queue['appointment_id']??0),'queue_entry_id'=>$queueId,'encounter_id'=>$encounterId],(string)($queue['service_name']??''));
            flash('success',dental_encounter_care_path_label($startCarePath).' selected. DentalCare will require only the clinically relevant steps for this visit.');
            if(($startAssistantDecision['decision'] ?? '') === 'assigned')flash('success','Treatment started with '.$startAssistantDecision['assistant_name'].' as Dental Assistant.');
            elseif(($startAssistantDecision['decision'] ?? '') === 'none')flash('success','Treatment started with no Dental Assistant assigned for this visit.');
            if($releasedTickets)flash('warning','Treatment started. Duplicate chair seating was corrected; '.implode(', ',$releasedTickets).' returned to waiting.');
            header('Location: clinical_workspace.php?encounter_id='.$encounterId);exit;
        }

        $encounterId=(int)($_POST['encounter_id']??0);
        $encounter=workspace_encounter($pdo,$encounterId);
        if(!$encounter)throw new RuntimeException('Clinical encounter not found.');
        if($action==='assign_assistant'){
            if(!workspace_can_write($encounter))throw new RuntimeException('Only the responsible Dentist can assign or change the encounter Dental Assistant.');
            $assistantId=(int)($_POST['assistant_user_id']??0);
            $previousAssistantId=(int)($encounter['assistant_user_id']??0);
            $assistantName=null;
            if($assistantId>0){
                $assistantStmt=$pdo->prepare('SELECT u.id,u.name,u.branch_id FROM `' . table('users') . '` u JOIN `' . table('roles') . '` r ON r.id=u.role_id WHERE u.id=? AND r.code="dental_assistant" AND u.status="active" AND (u.branch_id=? OR u.branch_id IS NULL OR ?=0) LIMIT 1');
                $assistantStmt->execute([$assistantId,(int)($encounter['branch_id']??0),(int)($encounter['branch_id']??0)]);
                $assistant=$assistantStmt->fetch();
                if(!$assistant)throw new RuntimeException('Select an active Dental Assistant authorized for this branch.');
                $assistantName=trim((string)$assistant['name']);
            }
            if(!clinical_flow_stability_schema_ready())throw new RuntimeException('Apply Version 0.7.9.2 before changing the Dental Assistant decision.');
            $assistantDecision=$assistantId>0?'assigned':'none';
            $pdo->prepare('UPDATE `' . table('clinical_encounters') . '` SET assistant_user_id=?,assistant_name=?,assistant_assigned_by=?,assistant_assigned_at=?,assistant_decision=?,assistant_decided_by=?,assistant_decided_at=NOW(),updated_at=NOW() WHERE id=?')
                ->execute([$assistantId?:null,$assistantName,$assistantId>0?$userId:null,$assistantId>0?date('Y-m-d H:i:s'):null,$assistantDecision,$userId,$encounterId]);
            audit($assistantId>0?'clinical_assistant_assigned':'clinical_assistant_removed','clinical_encounter',$encounterId,['previous_assistant_user_id'=>$previousAssistantId?:null,'assistant_user_id'=>$assistantId?:null,'dentist_user_id'=>$userId]);
            flash('success',$assistantId>0?$assistantName.' is now assigned to this patient and Dentist for the active encounter.':'The Dental Assistant assignment was removed. Existing entry attribution remains in the permanent record.');
            header('Location: clinical_workspace.php?encounter_id='.$encounterId);exit;
        }
        if($action==='add_procedure'){
            if(!workspace_can_treatment_entry($encounter))throw new RuntimeException('Only the responsible Dentist or encounter-assigned Dental Assistant can add a treatment entry.');
            if(!clinical_billing_schema_ready())throw new RuntimeException('Apply Version 0.5.9.8.15 before adding procedures.');
            $serviceId=(int)($_POST['service_id']??0);
            $itemId=(int)($_POST['treatment_plan_item_id']??0);
            $source=clinical_billing_resolve_source($pdo,$encounter,$serviceId,$itemId);
            if($itemId>0){
                $item=workspace_treatment_item($pdo,$itemId,(int)$encounter['patient_id']);
                $taskReason=null;
                $responsibleDentistId=(int)$encounter['dentist_user_id'];
                if(!$item||!dentist_can_work_treatment_item($pdo,$responsibleDentistId,$item,$taskReason))throw new RuntimeException($taskReason?:'The responsible Dentist is not assigned or qualified to perform this treatment item.');
            }
            $resolvedServiceId=(int)($source['service_id']??0);
            if($resolvedServiceId>0){
                $service=service_definition($resolvedServiceId,(int)($encounter['branch_id']??0));
                if($service&&($service['provider_type']??'dentist')==='dentist')require_dentist_clinical_privilege((int)$encounter['dentist_user_id'],(string)(service_required_privilege_code($service)?:'consultation'));
            }
            $pdo->beginTransaction();
            $procedureId=clinical_billing_insert_procedure($pdo,$encounter,$source,[
                'tooth_region'=>trim((string)($_POST['procedure_tooth_region']??'')),
                'anesthetic'=>trim((string)($_POST['anesthetic']??'')),
                'materials'=>trim((string)($_POST['materials']??'')),
                'complications'=>trim((string)($_POST['complications']??'')),
                'outcome'=>trim((string)($_POST['procedure_outcome']??'')),
                'responsible_dentist_user_id'=>(int)$encounter['dentist_user_id'],
                'assistant_user_id'=>$isAssistant?$userId:((int)($encounter['assistant_user_id']??0)?:null),
                'entered_by_user_id'=>$userId,
                'entered_by_role'=>$isAssistant?'dental_assistant':'dentist',
            ],$userId);
            if(!$isAssistant)$pdo->prepare('UPDATE `' . table('procedures') . '` SET verified_by_user_id=?,verified_at=NOW() WHERE id=?')->execute([$userId,$procedureId]);
            if($itemId>0){$item=workspace_treatment_item($pdo,$itemId,(int)$encounter['patient_id']);if($item)workspace_sync_treatment_item($pdo,$item,$encounterId,false,$userId);}
            audit_required('clinical_procedure_added','procedure',$procedureId,['encounter_id'=>$encounterId,'service_id'=>$resolvedServiceId?:null,'treatment_plan_item_id'=>$itemId?:null,'approved_fee'=>(float)$source['approved_fee'],'fee_status'=>$source['fee_status'],'responsible_dentist_user_id'=>(int)$encounter['dentist_user_id'],'entered_by_user_id'=>$userId,'entered_by_role'=>$isAssistant?'dental_assistant':'dentist']);
            $pdo->commit();
            flash('success',$isAssistant?'Treatment entry saved for the responsible Dentist to review and verify.':'Performed procedure added with its approved billing snapshot. Add another procedure when more than one service was completed.');
            header('Location: clinical_workspace.php?encounter_id='.$encounterId.'#treatment');exit;
        }
        if($action==='verify_procedure'){
            if(!workspace_can_write($encounter))throw new RuntimeException('Only the responsible Dentist can verify a delegated treatment entry.');
            $procedureId=(int)($_POST['procedure_id']??0);
            $pdo->beginTransaction();
            $stmt=$pdo->prepare('SELECT * FROM `' . table('procedures') . '` WHERE id=? AND encounter_id=? LIMIT 1 FOR UPDATE');$stmt->execute([$procedureId,$encounterId]);$procedureRow=$stmt->fetch();
            if(!$procedureRow)throw new RuntimeException('Treatment entry not found.');
            if((string)($procedureRow['entered_by_role']??'')!=='dental_assistant')throw new RuntimeException('This treatment entry was not delegated by a Dental Assistant.');
            if((int)($procedureRow['verified_by_user_id']??0)>0)throw new RuntimeException('This treatment entry has already been verified.');
            if((string)$procedureRow['status']==='cancelled')throw new RuntimeException('A cancelled treatment entry cannot be verified.');
            $verify=$pdo->prepare('UPDATE `' . table('procedures') . '` SET verified_by_user_id=?,verified_at=NOW() WHERE id=? AND encounter_id=? AND verified_by_user_id IS NULL');
            $verify->execute([$userId,$procedureId,$encounterId]);
            if($verify->rowCount()!==1)throw new RuntimeException('The delegated treatment entry changed before verification. Reload the encounter and review it again.');
            audit_required('clinical_assistant_entry_verified','procedure',$procedureId,['encounter_id'=>$encounterId,'responsible_dentist_user_id'=>$userId,'entered_by_user_id'=>(int)($procedureRow['entered_by_user_id']??0)]);
            $pdo->commit();
            flash('success','Delegated treatment entry verified. The original Dental Assistant attribution remains in the record.');
            header('Location: clinical_workspace.php?encounter_id='.$encounterId.'#treatment');exit;
        }
        if($action==='remove_procedure'){
            if(!workspace_can_treatment_entry($encounter))throw new RuntimeException('Only the responsible Dentist or the assistant who created a draft entry can remove it.');
            $procedureId=(int)($_POST['procedure_id']??0);
            $stmt=$pdo->prepare('SELECT * FROM `' . table('procedures') . '` WHERE id=? AND encounter_id=? LIMIT 1');$stmt->execute([$procedureId,$encounterId]);$procedureRow=$stmt->fetch();
            if(!$procedureRow)throw new RuntimeException('Procedure not found.');
            if($isAssistant && (int)($procedureRow['entered_by_user_id']??0)!==$userId)throw new RuntimeException('A Dental Assistant may remove only their own unverified draft treatment entry.');
            if((int)($procedureRow['verified_by_user_id']??0)>0)throw new RuntimeException('A Dentist-verified treatment entry cannot be removed. Use a signed correction or addendum.');
            if((string)$procedureRow['status']==='completed')throw new RuntimeException('A completed procedure cannot be deleted. Use a signed correction or addendum.');
            $billed=$pdo->prepare('SELECT COUNT(*) FROM `' . table('invoice_items') . '` WHERE procedure_id=?');$billed->execute([$procedureId]);if((int)$billed->fetchColumn()>0)throw new RuntimeException('This procedure is already included in an invoice and cannot be removed.');
            $pdo->prepare('DELETE FROM `' . table('procedures') . '` WHERE id=? AND encounter_id=?')->execute([$procedureId,$encounterId]);
            audit('clinical_procedure_draft_removed','procedure',$procedureId,['encounter_id'=>$encounterId]);
            flash('success','Draft procedure removed.');
            header('Location: clinical_workspace.php?encounter_id='.$encounterId.'#treatment');exit;
        }
        if($action==='mark_procedure_outcome'){
            if(!workspace_can_treatment_entry($encounter))throw new RuntimeException('Only the responsible Dentist or encounter-assigned assistant can mark a treatment entry as not billable.');
            $procedureId=(int)($_POST['procedure_id']??0);
            $targetStatus=(string)($_POST['procedure_status']??'');
            $allowedStatuses=['deferred','moved_follow_up','not_performed','cancelled'];
            if(!in_array($targetStatus,$allowedStatuses,true))throw new RuntimeException('Select a valid non-billable treatment outcome.');
            $reason=trim((string)($_POST['procedure_disposition_reason']??''));
            if(mb_strlen($reason)<10)throw new RuntimeException('Record the reason for deferring, moving, cancelling, or marking the service not performed.');
            $pdo->beginTransaction();
            $stmt=$pdo->prepare('SELECT * FROM `' . table('procedures') . '` WHERE id=? AND encounter_id=? LIMIT 1 FOR UPDATE');$stmt->execute([$procedureId,$encounterId]);$procedureRow=$stmt->fetch();
            if(!$procedureRow)throw new RuntimeException('Treatment entry not found.');
            if((string)($procedureRow['status']??'')==='completed')throw new RuntimeException('A completed procedure cannot be moved out of billing from this screen. Use a signed addendum/correction.');
            if($isAssistant && (int)($procedureRow['entered_by_user_id']??0)!==$userId)throw new RuntimeException('A Dental Assistant may update only their own draft treatment entry.');
            $billed=$pdo->prepare('SELECT COUNT(*) FROM `' . table('invoice_items') . '` WHERE procedure_id=?');$billed->execute([$procedureId]);if((int)$billed->fetchColumn()>0)throw new RuntimeException('This procedure is already included in an invoice and cannot be changed here.');
            $sets=['status=?','ended_at=COALESCE(ended_at,NOW())'];$args=[$targetStatus];
            if(schema_column_exists(table('procedures'),'billing_status')){$sets[]='billing_status="not_billable"';}
            if(schema_column_exists(table('procedures'),'disposition_reason')){$sets[]='disposition_reason=?';$args[]=$reason;}
            if(schema_column_exists(table('procedures'),'patient_agreement_recorded_at')){$sets[]='patient_agreement_recorded_at=?';$args[]=isset($_POST['patient_agreement_recorded'])?date('Y-m-d H:i:s'):null;}
            if(schema_column_exists(table('procedures'),'patient_agreement_recorded_by')){$sets[]='patient_agreement_recorded_by=?';$args[]=isset($_POST['patient_agreement_recorded'])?$userId:null;}
            $args[]=$procedureId;$args[]=$encounterId;
            $pdo->prepare('UPDATE `' . table('procedures') . '` SET '.implode(',',$sets).' WHERE id=? AND encounter_id=?')->execute($args);
            $itemId=(int)($procedureRow['treatment_plan_item_id']??0);
            if($itemId>0 && schema_column_exists(table('treatment_plan_items'),'status')){
                $planStatus=$targetStatus==='cancelled'?'cancelled':($targetStatus==='not_performed'?'deferred':'deferred');
                $pdo->prepare('UPDATE `' . table('treatment_plan_items') . '` SET status=?,notes=CONCAT(COALESCE(notes,""),IF(COALESCE(notes,"")="","","\n"),?),updated_at=NOW() WHERE id=?')->execute([$planStatus,'Visit outcome: '.ucwords(str_replace('_',' ',$targetStatus)).' — '.$reason,$itemId]);
            }
            clinical_billing_event($pdo,$encounter,null,'procedure_excluded_from_cashier',"Procedure/service excluded from today's payable handoff",['procedure_id'=>$procedureId,'procedure_name'=>(string)($procedureRow['procedure_name']??''),'status'=>$targetStatus,'reason'=>$reason,'patient_agreement_recorded'=>isset($_POST['patient_agreement_recorded'])],$userId);
            audit_required('clinical_procedure_excluded_from_billing','procedure',$procedureId,['encounter_id'=>$encounterId,'status'=>$targetStatus,'reason'=>$reason,'patient_agreement_recorded'=>isset($_POST['patient_agreement_recorded'])]);
            $pdo->commit();
            flash('success','Treatment entry marked as '.module_status($targetStatus).'. It will remain in clinical history but will not be sent to Cashier today.');
            header('Location: clinical_workspace.php?encounter_id='.$encounterId.'#treatment');exit;
        }
        if($action==='pause_treatment'){
            if(!workspace_can_write($encounter))throw new RuntimeException('Only the assigned Dentist can pause this treatment.');
            if(!workflow_governance_schema_ready())throw new RuntimeException('Apply Version 0.5.9.8.16 before pausing treatment.');
            $reason=trim((string)($_POST['pause_reason']??''));$releaseChair=isset($_POST['release_chair']);
            if(mb_strlen($reason)<10)throw new RuntimeException('Enter a clear pause reason of at least 10 characters.');
            $pdo->beginTransaction();
            $queueId=(int)($encounter['queue_entry_id']??0);
            if($queueId<1)throw new RuntimeException('This encounter has no active queue visit to pause.');
            $queueStmt=$pdo->prepare('SELECT * FROM `' . table('queue_entries') . '` WHERE id=? FOR UPDATE');$queueStmt->execute([$queueId]);$queue=$queueStmt->fetch();
            if(!$queue||(string)$queue['status']!=='in_treatment')throw new RuntimeException('Only a patient currently in treatment can be paused.');
            $nextStatus=$releaseChair?'waiting':'seated';
            $pdo->prepare('UPDATE `' . table('clinical_encounters') . '` SET paused_at=NOW(),pause_reason=?,paused_by=?,pause_releases_chair=?,updated_at=NOW() WHERE id=?')->execute([$reason,$userId,$releaseChair?1:0,$encounterId]);
            $pdo->prepare('UPDATE `' . table('queue_entries') . '` SET status=?,chair_id=IF(?=1,NULL,chair_id),chair_name=IF(?=1,NULL,chair_name),seated_at=?,updated_at=NOW() WHERE id=? AND status="in_treatment"')->execute([$nextStatus,$releaseChair?1:0,$releaseChair?1:0,$releaseChair?null:date('Y-m-d H:i:s'),$queueId]);
            $pdo->prepare('INSERT INTO `' . table('queue_status_history') . '` (queue_entry_id,previous_status,new_status,notes,changed_by,created_at) VALUES (?,"in_treatment",?,?,?,NOW())')->execute([$queueId,$nextStatus,'Treatment paused: '.$reason,$userId]);
            if(!empty($encounter['appointment_id'])){
                $pdo->prepare('UPDATE `' . table('appointments') . '` SET status="checked_in",updated_at=NOW() WHERE id=? AND status="in_treatment"')->execute([(int)$encounter['appointment_id']]);
                if(schema_table_exists(table('appointment_status_history')))$pdo->prepare('INSERT INTO `' . table('appointment_status_history') . '` (appointment_id,previous_status,new_status,reason,changed_by,created_at) VALUES (? ,"in_treatment","checked_in",?,?,NOW())')->execute([(int)$encounter['appointment_id'],'Treatment paused: '.$reason,$userId]);
            }
            audit_required('clinical_treatment_paused','clinical_encounter',$encounterId,['queue_entry_id'=>$queueId,'reason'=>$reason,'release_chair'=>$releaseChair]);
            $pdo->commit();
            flash('warning',$releaseChair?'Treatment paused and the patient returned to waiting. The chair is available for the next patient.':'Treatment paused. The patient remains seated and can be resumed by the assigned Dentist.');
            header('Location: doctor_treatment.php');exit;
        }
        if($action==='request_encounter_transfer'){
            if(!workspace_can_write($encounter))throw new RuntimeException('Only the assigned Dentist can request consultation or transfer.');
            if(!workflow_governance_schema_ready())throw new RuntimeException('Apply Version 0.5.9.8.16 before requesting another Dentist.');
            $requestType=(string)($_POST['request_type']??'consultation');$targetId=(int)($_POST['to_dentist_user_id']??0);$reason=trim((string)($_POST['transfer_reason']??''));
            if(!in_array($requestType,['consultation','transfer'],true))throw new RuntimeException('Select consultation or responsibility transfer.');
            if($targetId<1||$targetId===$userId)throw new RuntimeException('Select another qualified Dentist.');
            if(mb_strlen($reason)<10)throw new RuntimeException('Enter a clear request reason of at least 10 characters.');
            $required=$requestType==='transfer'?'clinical_note_finalization':'consultation';$eligible=false;$targetName='';
            foreach(qualified_dentists_for_privilege((int)($encounter['branch_id']??0),$required,$userId) as $doctor){if((int)$doctor['id']===$targetId){$eligible=true;$targetName=(string)($doctor['display_name']??$doctor['name']);break;}}
            if(!$eligible)throw new RuntimeException('The selected Dentist is not credentialed, branch-authorized, or granted the required privilege.');
            $pdo->beginTransaction();
            $duplicate=$pdo->prepare('SELECT COUNT(*) FROM `' . table('clinical_encounter_transfers') . '` WHERE encounter_id=? AND to_dentist_user_id=? AND request_type=? AND status IN ("pending","accepted") FOR UPDATE');$duplicate->execute([$encounterId,$targetId,$requestType]);
            if((int)$duplicate->fetchColumn()>0)throw new RuntimeException('This Dentist already has an active request for the encounter.');
            $pdo->prepare('INSERT INTO `' . table('clinical_encounter_transfers') . '` (encounter_id,patient_id,branch_id,request_type,from_dentist_user_id,to_dentist_user_id,required_privilege_code,reason,status,requested_by,requested_at,created_at) VALUES (?,?,?,?,?,?,?,?,"pending",?,NOW(),NOW())')->execute([$encounterId,(int)$encounter['patient_id'],(int)($encounter['branch_id']??0)?:null,$requestType,$userId,$targetId,$required,$reason,$userId]);
            $transferId=(int)$pdo->lastInsertId();
            audit_required('clinical_encounter_dentist_requested','clinical_encounter_transfer',$transferId,['encounter_id'=>$encounterId,'request_type'=>$requestType,'to_dentist_user_id'=>$targetId,'reason'=>$reason]);
            $pdo->commit();
            flash('success',ucfirst($requestType).' request sent to '.$targetName.'. Responsibility does not change until the receiving Dentist accepts.');
            header('Location: clinical_workspace.php?encounter_id='.$encounterId);exit;
        }
        if($action==='decide_encounter_transfer'){
            if(!active_role_is('dentist'))throw new RuntimeException('Only the receiving Dentist can decide this request.');
            $transferId=(int)($_POST['transfer_id']??0);$decision=(string)($_POST['decision']??'');$note=trim((string)($_POST['decision_note']??''));
            if(!in_array($decision,['accepted','declined'],true))throw new RuntimeException('Select accept or decline.');
            $pdo->beginTransaction();$transfer=governance_encounter_transfer_row($pdo,$transferId,true);
            if(!$transfer||(int)$transfer['encounter_id']!==$encounterId||(int)$transfer['to_dentist_user_id']!==$userId||(string)$transfer['status']!=='pending')throw new RuntimeException('This Dentist request is no longer pending for your account.');
            require_dentist_credentials_verified($userId);require_dentist_clinical_privilege($userId,(string)($transfer['required_privilege_code']?:'consultation'));
            $pdo->prepare('UPDATE `' . table('clinical_encounter_transfers') . '` SET status=?,decided_by=?,decided_at=NOW(),decision_note=?,updated_at=NOW() WHERE id=? AND status="pending"')->execute([$decision,$userId,$note?:null,$transferId]);
            if($decision==='accepted'&&(string)$transfer['request_type']==='transfer'){
                $current=$pdo->prepare('SELECT * FROM `' . table('clinical_encounters') . '` WHERE id=? FOR UPDATE');$current->execute([$encounterId]);$lockedEncounter=$current->fetch();
                if(!$lockedEncounter||in_array((string)$lockedEncounter['status'],['finalized','addendum'],true))throw new RuntimeException('A finalized encounter cannot transfer active treatment responsibility.');
                $profile=dentist_profile($userId)?:[];$targetName=$profile?dentist_display_name($profile):(user_full_name((array)current_user()) ?: 'Dentist');$binding=doctor_chair_binding($userId,(int)($lockedEncounter['branch_id']??0));
                if(empty($binding['valid']))throw new RuntimeException((string)($binding['issue']??'The receiving Dentist needs a valid chair assignment.'));
                $pdo->prepare('UPDATE `' . table('clinical_encounters') . '` SET dentist_user_id=?,dentist_name=?,paused_at=NOW(),pause_reason=?,paused_by=?,pause_releases_chair=0,responsibility_transferred_at=NOW(),responsibility_transfer_id=?,updated_at=NOW() WHERE id=?')->execute([$userId,$targetName,'Responsibility transferred from the previous Dentist',$userId,$transferId,$encounterId]);
                if(!empty($lockedEncounter['queue_entry_id'])){
                    $queueStmt=$pdo->prepare('SELECT status FROM `' . table('queue_entries') . '` WHERE id=? FOR UPDATE');$queueStmt->execute([(int)$lockedEncounter['queue_entry_id']]);$oldQueue=(string)($queueStmt->fetchColumn()?:'');$newQueue=$oldQueue==='in_treatment'?'seated':$oldQueue;
                    $pdo->prepare('UPDATE `' . table('queue_entries') . '` SET dentist_user_id=?,dentist_name=?,chair_id=?,chair_name=?,status=?,seated_at=IF(?="seated",NOW(),seated_at),updated_at=NOW() WHERE id=?')->execute([$userId,$targetName,(int)($binding['chair_id']??0)?:null,(string)($binding['chair_name']??'')?:null,$newQueue,$newQueue,(int)$lockedEncounter['queue_entry_id']]);
                    if($oldQueue!==$newQueue)$pdo->prepare('INSERT INTO `' . table('queue_status_history') . '` (queue_entry_id,previous_status,new_status,notes,changed_by,created_at) VALUES (?,?,?,?,?,NOW())')->execute([(int)$lockedEncounter['queue_entry_id'],$oldQueue,$newQueue,'Clinical responsibility transferred; receiving Dentist must resume treatment',$userId]);
                }
                if(!empty($lockedEncounter['appointment_id']))$pdo->prepare('UPDATE `' . table('appointments') . '` SET dentist_user_id=?,dentist_name=?,chair_id=?,chair_name=?,updated_at=NOW() WHERE id=?')->execute([$userId,$targetName,(int)($binding['chair_id']??0)?:null,(string)($binding['chair_name']??'')?:null,(int)$lockedEncounter['appointment_id']]);
            }
            audit_required('clinical_encounter_dentist_request_decided','clinical_encounter_transfer',$transferId,['encounter_id'=>$encounterId,'decision'=>$decision,'request_type'=>$transfer['request_type'],'note'=>$note]);
            $pdo->commit();flash($decision==='accepted'?'success':'warning',$decision==='accepted'?'Dentist request accepted.':'Dentist request declined.');header('Location: clinical_workspace.php?encounter_id='.$encounterId);exit;
        }
        if($action==='emergency_takeover'){
            if(!active_role_is('dentist'))throw new RuntimeException('Only an authenticated Dentist can perform an emergency takeover.');
            if((int)$encounter['dentist_user_id']===$userId)throw new RuntimeException('You already own this encounter.');
            if(in_array((string)$encounter['status'],['finalized','addendum'],true))throw new RuntimeException('A finalized encounter cannot be taken over as active treatment.');
            $reason=trim((string)($_POST['takeover_reason']??''));if(mb_strlen($reason)<15)throw new RuntimeException('Document the emergency takeover reason in at least 15 characters.');
            require_dentist_credentials_verified($userId);require_dentist_clinical_privilege($userId,'consultation');require_dentist_clinical_privilege($userId,'clinical_note_finalization');
            $binding=doctor_chair_binding($userId,(int)($encounter['branch_id']??0));if(empty($binding['valid']))throw new RuntimeException((string)($binding['issue']??'A valid chair assignment is required for takeover.'));
            $profile=dentist_profile($userId)?:[];$targetName=$profile?dentist_display_name($profile):(user_full_name((array)current_user()) ?: 'Dentist');
            $pdo->beginTransaction();$lock=$pdo->prepare('SELECT * FROM `' . table('clinical_encounters') . '` WHERE id=? FOR UPDATE');$lock->execute([$encounterId]);$locked=$lock->fetch();if(!$locked||in_array((string)$locked['status'],['finalized','addendum'],true))throw new RuntimeException('The encounter changed before takeover.');
            $pdo->prepare('INSERT INTO `' . table('clinical_encounter_transfers') . '` (encounter_id,patient_id,branch_id,request_type,from_dentist_user_id,to_dentist_user_id,required_privilege_code,reason,status,requested_by,requested_at,decided_by,decided_at,decision_note,created_at,updated_at) VALUES (?,?,?,?,?,?,"clinical_note_finalization",?,"accepted",?,NOW(),?,NOW(),"Emergency takeover accepted by receiving Dentist",NOW(),NOW())')->execute([$encounterId,(int)$locked['patient_id'],(int)($locked['branch_id']??0)?:null,'emergency_takeover',(int)$locked['dentist_user_id'],$userId,$reason,$userId,$userId]);$transferId=(int)$pdo->lastInsertId();
            $pdo->prepare('UPDATE `' . table('clinical_encounters') . '` SET dentist_user_id=?,dentist_name=?,paused_at=NOW(),pause_reason=?,paused_by=?,pause_releases_chair=0,responsibility_transferred_at=NOW(),responsibility_transfer_id=?,updated_at=NOW() WHERE id=?')->execute([$userId,$targetName,'Emergency takeover: '.$reason,$userId,$transferId,$encounterId]);
            if(!empty($locked['queue_entry_id'])){$q=$pdo->prepare('SELECT status FROM `' . table('queue_entries') . '` WHERE id=? FOR UPDATE');$q->execute([(int)$locked['queue_entry_id']]);$old=(string)($q->fetchColumn()?:'');$new=$old==='in_treatment'?'seated':$old;$pdo->prepare('UPDATE `' . table('queue_entries') . '` SET dentist_user_id=?,dentist_name=?,chair_id=?,chair_name=?,status=?,seated_at=IF(?="seated",NOW(),seated_at),updated_at=NOW() WHERE id=?')->execute([$userId,$targetName,(int)$binding['chair_id'],(string)$binding['chair_name'],$new,$new,(int)$locked['queue_entry_id']]);if($old!==$new)$pdo->prepare('INSERT INTO `' . table('queue_status_history') . '` (queue_entry_id,previous_status,new_status,notes,changed_by,created_at) VALUES (?,?,?,?,?,NOW())')->execute([(int)$locked['queue_entry_id'],$old,$new,'Emergency takeover; receiving Dentist must resume treatment',$userId]);}
            if(!empty($locked['appointment_id']))$pdo->prepare('UPDATE `' . table('appointments') . '` SET dentist_user_id=?,dentist_name=?,chair_id=?,chair_name=?,updated_at=NOW() WHERE id=?')->execute([$userId,$targetName,(int)$binding['chair_id'],(string)$binding['chair_name'],(int)$locked['appointment_id']]);
            audit_required('clinical_emergency_takeover','clinical_encounter',$encounterId,['transfer_id'=>$transferId,'from_dentist_user_id'=>(int)$locked['dentist_user_id'],'to_dentist_user_id'=>$userId,'reason'=>$reason]);$pdo->commit();flash('warning','Emergency takeover recorded. Review the complete chart, then resume treatment under your own identity.');header('Location: clinical_workspace.php?encounter_id='.$encounterId);exit;
        }
        if($action==='complete_consultation'){
            if(!active_role_is('dentist'))throw new RuntimeException('Only the consulting Dentist can sign a consultation note.');
            $transferId=(int)($_POST['transfer_id']??0);$note=trim((string)($_POST['consultation_note']??''));if(mb_strlen($note)<20)throw new RuntimeException('Enter a consultation note of at least 20 characters.');
            $profile=dentist_profile($userId)?:[];$name=$profile?dentist_display_name($profile):(user_full_name((array)current_user()) ?: 'Dentist');$license=trim((string)($profile['license_number']??''));$signature=trim((string)($profile['signature_path']??''))?:null;if($license==='')throw new RuntimeException('A verified professional license is required to sign the consultation note.');
            $pdo->beginTransaction();$transfer=governance_encounter_transfer_row($pdo,$transferId,true);if(!$transfer||(int)$transfer['encounter_id']!==$encounterId||(int)$transfer['to_dentist_user_id']!==$userId||(string)$transfer['request_type']!=='consultation'||(string)$transfer['status']!=='accepted')throw new RuntimeException('This consultation is not accepted and active for your account.');
            $signedAt=date('Y-m-d H:i:s');$hash=hash('sha256',$encounterId.'|'.$transferId.'|'.$note.'|'.$userId.'|'.$signedAt);
            $pdo->prepare('UPDATE `' . table('clinical_encounter_transfers') . '` SET status="completed",consultation_note=?,consultation_signed_name=?,consultation_signed_license=?,consultation_signature_path=?,consultation_signed_at=?,completed_at=NOW(),updated_at=NOW() WHERE id=?')->execute([$note,$name,$license,$signature,$signedAt,$transferId]);
            $pdo->prepare('INSERT INTO `' . table('clinical_note_addenda') . '` (encounter_id,reason,content,author_user_id,author_name_snapshot,author_license_snapshot,signature_path_snapshot,signed_at,addendum_hash,created_at) VALUES (?,?,?,?,?,?,?,?,?,NOW())')->execute([$encounterId,'Consulting Dentist note',$note,$userId,$name,$license,$signature,$signedAt,$hash]);
            audit_required('clinical_consultation_completed','clinical_encounter_transfer',$transferId,['encounter_id'=>$encounterId,'consulting_dentist_user_id'=>$userId]);$pdo->commit();flash('success','Consultation note signed under your own professional identity.');header('Location: clinical_workspace.php?encounter_id='.$encounterId);exit;
        }
        if($action==='correct_procedure_billing'){
            $isAssignedDentist=active_role_is('dentist')&&(int)$encounter['dentist_user_id']===$userId;
            if(!$isAssignedDentist)throw new RuntimeException('Only the currently responsible Dentist may correct what clinical procedure was performed. Administrators may request correction but cannot sign with a Dentist’s credentials.');
            if(!clinical_billing_schema_ready()||!workflow_governance_schema_ready())throw new RuntimeException('Apply Version 0.5.9.8.16 before correcting procedure billing.');
            $procedureId=(int)($_POST['procedure_id']??0);$serviceId=(int)($_POST['service_id']??0);$reason=trim((string)($_POST['correction_reason']??''));
            if(mb_strlen($reason)<15)throw new RuntimeException('Enter a specific correction reason of at least 15 characters.');
            $profile=dentist_profile($userId)?:[];$authorName=$profile?dentist_display_name($profile):(user_full_name((array)current_user()) ?: 'Dentist');$license=trim((string)($profile['license_number']??''));$signature=trim((string)($profile['signature_path']??''))?:null;
            if($license==='')throw new RuntimeException('A verified professional license number is required to sign this clinical correction.');
            $pdo->beginTransaction();
            $stmt=$pdo->prepare('SELECT * FROM `' . table('procedures') . '` WHERE id=? AND encounter_id=? LIMIT 1 FOR UPDATE');$stmt->execute([$procedureId,$encounterId]);$old=$stmt->fetch();if(!$old)throw new RuntimeException('Procedure not found.');
            $source=clinical_billing_resolve_source($pdo,$encounter,$serviceId,0);$feeStatus=(string)$source['fee_status'];$amount=$feeStatus==='no_charge'?0:round((float)$source['approved_fee'],2);
            $pdo->prepare('UPDATE `' . table('procedures') . '` SET service_id=?,procedure_name=?,service_name_snapshot=?,service_code_snapshot=?,approved_fee_snapshot=?,fee_source=?,fee_status=?,no_charge_reason=?,fee_authorized_by=?,fee_authorized_at=?,billing_status=? WHERE id=? AND encounter_id=?')
                ->execute([(int)$source['service_id'],(string)$source['procedure_name'],(string)$source['procedure_name'],trim((string)($source['procedure_code']??''))?:null,$amount,$feeStatus==='no_charge'?'authorized_no_charge':'service_catalog',$feeStatus==='no_charge'?'no_charge':'billable',trim((string)($source['no_charge_reason']??''))?:null,(int)($source['fee_authorized_by']??0)?:$userId,$source['fee_authorized_at']??date('Y-m-d H:i:s'),$feeStatus==='no_charge'?'no_charge':'ready',$procedureId,$encounterId]);
            if(in_array((string)($encounter['status']??''),['finalized','addendum'],true)){
                $signedAt=date('Y-m-d H:i:s');$content='Clinical correction: legacy procedure “'.trim((string)$old['procedure_name']).'” was corrected to “'.(string)$source['procedure_name'].'”. Reason: '.$reason;$hash=hash('sha256',$encounterId.'|'.$reason.'|'.$content.'|'.$userId.'|'.$signedAt);
                $pdo->prepare('INSERT INTO `' . table('clinical_note_addenda') . '` (encounter_id,reason,content,author_user_id,author_name_snapshot,author_license_snapshot,signature_path_snapshot,signed_at,addendum_hash,created_at) VALUES (?,?,?,?,?,?,?,?,?,NOW())')->execute([$encounterId,'Procedure billing source correction',$content,$userId,$authorName,$license,$signature,$signedAt,$hash]);
                $procedures=clinical_billing_procedures($pdo,$encounterId,true);clinical_billing_sync_invoice($pdo,$encounter,$procedures,$userId);
            }
            governance_resolve_billing_corrections($pdo,$encounterId,$procedureId,$userId,'Signed clinical correction: '.$reason);
            audit_required('clinical_procedure_billing_corrected','procedure',$procedureId,['encounter_id'=>$encounterId,'old_name'=>$old['procedure_name'],'service_id'=>$serviceId,'reason'=>$reason,'approved_fee'=>$amount,'fee_status'=>$feeStatus,'signed_by_user_id'=>$userId]);
            $pdo->commit();
            flash('success','Clinical procedure corrected and signed under your own license. The cashier invoice and correction queue were refreshed.');
            header('Location: clinical_workspace.php?encounter_id='.$encounterId.'#treatment');exit;
        }
        if($action==='upload_xray'){
            if(!workspace_can_screen($encounter))throw new RuntimeException('Only the assigned Dentist or Dental Assistant can attach chairside imaging to this encounter.');
            $toothRegion=trim((string)($_POST['tooth_region']??''));
            $category=trim((string)($_POST['category']??'Periapical X-ray'));
            if(!clinical_is_imaging_category($category))throw new RuntimeException('Choose a valid X-ray or clinical imaging type.');
            $documentId=clinical_store_document_upload(
                $pdo,(array)($_FILES['document']??[]),(int)$encounter['patient_id'],$encounterId,
                $category,$toothRegion,
                trim((string)($_POST['description']??'')),'clinical'
            );
            audit('chairside_xray_uploaded','document',$documentId,['patient_id'=>(int)$encounter['patient_id'],'encounter_id'=>$encounterId,'tooth_region'=>$toothRegion]);
            flash('success','X-ray or clinical image uploaded and linked to this encounter.');
            header('Location: clinical_workspace.php?encounter_id='.$encounterId.'#charting');exit;
        }
        elseif($action==='save_screening'){
            $queueForSafety=(int)($encounter['queue_entry_id']??0);
            flash('warning','Dental-safety history and indicated measurements are completed at first seating before treatment starts. The treatment record is read-only for this information.');
            header('Location: '.($queueForSafety>0?dental_safety_assessment_url($queueForSafety):'clinical_workspace.php?encounter_id='.$encounterId));exit;
        }
        elseif($action==='review_prescription_safety'){
            if(!workspace_can_write($encounter))throw new RuntimeException('Only the assigned Dentist can review prescription safety for this encounter.');
            $previewItems=workspace_collect_medications();
            $previewItems=medicine_catalog_bind_posted_items($pdo,$previewItems,$userId,false);
            if(!$previewItems)throw new RuntimeException('Add at least one medicine before running the safety review.');
            $previewAssessment=clinical_safety_evaluate_prescription($pdo,(int)$encounter['patient_id'],$previewItems);
            clinical_safety_store_preview($encounterId,$previewItems,$previewAssessment,[
                'prescription_indication'=>(string)($_POST['prescription_indication']??''),
                'prescription_notes'=>(string)($_POST['prescription_notes']??''),
                'prescription_summary'=>(string)($_POST['prescription_summary']??''),
                'prescription_safety_override_reason'=>(string)($_POST['prescription_safety_override_reason']??''),
                'allergy_review_acknowledged'=>isset($_POST['allergy_review_acknowledged']),
                'prescription_safety_acknowledged'=>isset($_POST['prescription_safety_acknowledged']),
                'prescription_decision'=>(string)($_POST['prescription_decision']??'issued'),
            ]);
            $previewCounts=$previewAssessment['counts']??[];
            $previewMessage=($previewAssessment['status']??'warning')==='blocked'
                ? 'Safety review found '.(int)($previewCounts['hard_stop']??0).' hard stop'.((int)($previewCounts['hard_stop']??0)===1?'':'s').'. The prescription cannot be issued until corrected.'
                : ((($previewCounts['serious_warning']??0)+($previewCounts['data_gap']??0))>0
                    ? 'Safety review completed with warnings. Review every finding and document the clinical justification when required.'
                    : 'Safety review completed with no blocking or serious local-rule finding.');
            flash(($previewAssessment['status']??'warning')==='clear'?'success':'warning',$previewMessage);
            header('Location: clinical_workspace.php?encounter_id='.$encounterId.'&focus=prescription#prescription');exit;
        }
        elseif($action==='save_draft'){
            if(!workspace_can_write($encounter))throw new RuntimeException('Only the assigned dentist can update this encounter.');
            $pdo->beginTransaction();
            workspace_save_clinical($pdo,$encounter,false);
            $pdo->commit();
            audit('clinical_draft_saved','clinical_encounter',$encounterId);
            flash('success','Complete clinical draft saved.');
        }
        elseif(in_array($action,['finalize_cashier','finalize_no_payment','finalize_encounter'],true)){
            if(!workspace_can_write($encounter))throw new RuntimeException('Only the assigned dentist can finalize this encounter.');
            $destination=$action==='finalize_no_payment'?'no_payment':(string)($_POST['completion_destination']??'cashier');
            if(!in_array($destination,['cashier','no_payment'],true))$destination='cashier';
            $noPaymentReason=trim((string)($_POST['no_payment_reason']??''));
            if($destination==='no_payment'&&mb_strlen($noPaymentReason)<10)throw new RuntimeException('Enter the authorized no-payment reason before discharging the patient.');
            require_dentist_clinical_privilege($userId,'diagnosis');
            require_dentist_clinical_privilege($userId,'clinical_note_finalization');
            if(workspace_collect_medications())require_dentist_clinical_privilege($userId,'prescription');
            $pdo->beginTransaction();
            if(!empty($encounter['queue_entry_id'])){
                $lock=$pdo->prepare('SELECT status FROM `' . table('queue_entries') . '` WHERE id=? FOR UPDATE');
                $lock->execute([(int)$encounter['queue_entry_id']]);
                $queueStatus=(string)($lock->fetchColumn()?:'');
                if($queueStatus!=='in_treatment')throw new RuntimeException('The patient must be in treatment before the clinical encounter can be finalized.');
            }
            $result=workspace_save_clinical($pdo,$encounter,true,$destination);
            $finalizedProcedures=clinical_billing_procedures($pdo,$encounterId,true);
            $handoffTotal=workspace_billable_handoff_total($pdo,$encounterId,$finalizedProcedures);
            if($destination==='no_payment'&&$handoffTotal>0.005){
                throw new RuntimeException('No-payment discharge is blocked because this encounter contains ₱'.number_format($handoffTotal,2).' in billable procedures or separately billable clinical items. Choose Cashier handoff or correct the approved billing source.');
            }
            $invoiceId=0;
            if($destination==='cashier'){
                $invoiceId=$finalizedProcedures?clinical_billing_sync_invoice($pdo,$encounter,$finalizedProcedures,$userId):0;
                if($invoiceId){
                    $invoiceAmountStmt=$pdo->prepare('SELECT amount FROM `' . table('invoices') . '` WHERE id=?');
                    $invoiceAmountStmt->execute([$invoiceId]);
                    $handoffTotal=round((float)$invoiceAmountStmt->fetchColumn(),2);
                }
            }
            $pdo->prepare('UPDATE `' . table('procedures') . '` SET verified_by_user_id=?,verified_at=NOW() WHERE encounter_id=? AND status<>"cancelled" AND verified_by_user_id IS NULL AND COALESCE(entered_by_role,"dentist")<>"dental_assistant"')->execute([$userId,$encounterId]);
            $refreshedEncounter=workspace_encounter($pdo,$encounterId)?:$encounter;
            $summary=workspace_build_discharge_summary($pdo,$refreshedEncounter,$destination,$handoffTotal,$destination==='no_payment'?$noPaymentReason:null);
            $summaryJson=(string)json_encode($summary,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES|JSON_PRESERVE_ZERO_FRACTION);
            if($summaryJson===''||$summaryJson==='false')throw new RuntimeException('The discharge summary could not be generated.');
            $pdo->prepare('UPDATE `' . table('clinical_encounters') . '` SET completion_destination=?,no_payment_reason=?,discharge_summary_json=?,billing_handoff_amount=?,billing_handoff_at=IF(?="cashier",NOW(),NULL),discharged_at=IF(?="no_payment",NOW(),NULL),chair_released_at=NOW(),updated_at=NOW() WHERE id=?')
                ->execute([$destination,$destination==='no_payment'?$noPaymentReason:null,$summaryJson,$handoffTotal,$destination,$destination,$encounterId]);
            workspace_apply_signer_snapshot($pdo,$encounterId,$userId);
            if(function_exists('clinical_record_completion_store')){
                clinical_record_completion_store($pdo,$encounterId,$userId);
            }
            if(!empty($encounter['queue_entry_id'])){
                $nextQueue=$destination==='cashier'?'waiting_billing':'completed';
                $queueNote=$destination==='cashier'?'Clinical record finalized and sent to Cashier':'Clinical record finalized with authorized no-payment discharge';
                $queueUpdate=$pdo->prepare('UPDATE `' . table('queue_entries') . '` SET status=?,billing_at=IF(?="waiting_billing",NOW(),billing_at),completed_at=IF(?="completed",NOW(),completed_at),chair_id=NULL,chair_name=NULL,seated_at=NULL,updated_at=NOW() WHERE id=? AND status="in_treatment"');
                $queueUpdate->execute([$nextQueue,$nextQueue,$nextQueue,(int)$encounter['queue_entry_id']]);
                if($queueUpdate->rowCount()!==1)throw new RuntimeException('The queue state changed while the encounter was being completed.');
                $queueVerify=$pdo->prepare('SELECT status,chair_id,chair_name FROM `' . table('queue_entries') . '` WHERE id=?');
                $queueVerify->execute([(int)$encounter['queue_entry_id']]);
                $verifiedQueue=$queueVerify->fetch();
                if(!$verifiedQueue
                    || (string)($verifiedQueue['status']??'')!==$nextQueue
                    || (int)($verifiedQueue['chair_id']??0)>0
                    || trim((string)($verifiedQueue['chair_name']??''))!==''){
                    throw new RuntimeException('Encounter completion could not verify that the treatment chair was released. No completion changes were committed.');
                }
                $pdo->prepare('INSERT INTO `' . table('queue_status_history') . '` (queue_entry_id,previous_status,new_status,notes,changed_by,created_at) VALUES (?,"in_treatment",?,?,?,NOW())')->execute([(int)$encounter['queue_entry_id'],$nextQueue,$queueNote,$userId]);
            }
            if(!empty($encounter['appointment_id'])){
                $appointmentLock=$pdo->prepare('SELECT status,start_at FROM `' . table('appointments') . '` WHERE id=? FOR UPDATE');
                $appointmentLock->execute([(int)$encounter['appointment_id']]);
                $appointmentState=$appointmentLock->fetch();
                if(!$appointmentState)throw new RuntimeException('The linked appointment could not be verified before encounter completion.');
                $nextAppointment=$destination==='cashier'?'awaiting_billing':'completed';
                integrity_assert_appointment_transition((string)$appointmentState['status'],$nextAppointment,(string)$appointmentState['start_at']);
                $appointmentUpdate=$pdo->prepare('UPDATE `' . table('appointments') . '` SET status=?,chair_id=NULL,chair_name=NULL,updated_at=NOW() WHERE id=? AND status=?');
                $appointmentUpdate->execute([$nextAppointment,(int)$encounter['appointment_id'],(string)$appointmentState['status']]);
                if($appointmentUpdate->rowCount()!==1)throw new RuntimeException('The linked appointment changed while encounter completion was being saved.');
                $appointmentVerify=$pdo->prepare('SELECT status,chair_id,chair_name FROM `' . table('appointments') . '` WHERE id=?');
                $appointmentVerify->execute([(int)$encounter['appointment_id']]);
                $verifiedAppointment=$appointmentVerify->fetch();
                if(!$verifiedAppointment
                    || (string)($verifiedAppointment['status']??'')!==$nextAppointment
                    || (int)($verifiedAppointment['chair_id']??0)>0
                    || trim((string)($verifiedAppointment['chair_name']??''))!==''){
                    throw new RuntimeException('Encounter completion could not verify the linked appointment checkout state. No completion changes were committed.');
                }
                if(schema_table_exists(table('appointment_status_history'))){
                    $reason=$destination==='cashier'?'Clinical record finalized and sent to Cashier':'Clinical record finalized with authorized no-payment discharge';
                    $pdo->prepare('INSERT INTO `' . table('appointment_status_history') . '` (appointment_id,previous_status,new_status,reason,changed_by,created_at) VALUES (?,?,?,?,?,NOW())')->execute([(int)$encounter['appointment_id'],(string)$appointmentState['status'],$nextAppointment,$reason,$userId]);
                }
            }
            audit_required('clinical_encounter_finalized','clinical_encounter',$encounterId,['completion_destination'=>$destination,'invoice_id'=>$invoiceId?:null,'billing_handoff_amount'=>$handoffTotal,'no_payment_reason'=>$destination==='no_payment'?$noPaymentReason:null,'chair_released'=>true,'treatment_plan_item_id'=>$result['treatment_plan_item_id']??null,'follow_up_id'=>$result['follow_up_id']??null]);
            if($invoiceId)audit_required('clinical_invoice_prepared','invoice',$invoiceId,['encounter_id'=>$encounterId,'patient_id'=>(int)$encounter['patient_id'],'amount'=>$handoffTotal]);
            $pdo->commit();
            $eventType=$destination==='cashier'?'clinical_finalized':'clinical_discharged_no_payment';
            $eventNote=$destination==='cashier'
                ? 'Sent to Cashier · Approved handoff ₱'.number_format($handoffTotal,2)
                : 'Authorized no-payment discharge · '.$noPaymentReason;
            workflow_event((int)$encounter['patient_id'],$eventType,'Clinical record finalized',['appointment_id'=>(int)($encounter['appointment_id']??0),'queue_entry_id'=>(int)($encounter['queue_entry_id']??0),'encounter_id'=>$encounterId,'invoice_id'=>$invoiceId,'follow_up_id'=>(int)($result['follow_up_id']??0),'completion_destination'=>$destination,'billing_handoff_amount'=>$handoffTotal],$eventNote.(!empty($result['follow_up_id'])?' · Follow-up recommendation awaiting booking':''));
            flash('success',$destination==='cashier'
                ? 'Visit finalized and signed. The chair was released and the verified ₱'.number_format($handoffTotal,2).' handoff is ready at the Cashier.'
                : 'Visit finalized and signed with an authorized no-payment discharge. The chair was released and the discharge summary is ready to print.');
            clinical_safety_clear_preview($encounterId);
            clinical_context_clear();
            header('Location: clinical_workspace.php?encounter_id='.$encounterId.'&completed=1');exit;
        }
        else throw new RuntimeException('Unsupported clinical action.');
        header('Location: clinical_workspace.php?encounter_id='.$encounterId);exit;
    }catch(Throwable $exception){
        if($pdo->inTransaction())$pdo->rollBack();
        $dentalSafetyRedirect=trim((string)($GLOBALS['dental_safety_gate_redirect']??''));
        if($dentalSafetyRedirect!==''){
            unset($GLOBALS['dental_safety_gate_redirect']);
            flash('warning',$exception->getMessage());
            header('Location: '.$dentalSafetyRedirect);exit;
        }
        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(!empty($GLOBALS['clinical_safety_last_assessment'])&&is_array($GLOBALS['clinical_safety_last_assessment'])){
            $restoreEncounterId=(int)($_POST['encounter_id']??0);
            if($restoreEncounterId>0){
                clinical_safety_store_preview($restoreEncounterId,(array)($GLOBALS['clinical_safety_last_items']??[]),(array)$GLOBALS['clinical_safety_last_assessment'],[
                    'prescription_indication'=>(string)($_POST['prescription_indication']??''),
                    'prescription_notes'=>(string)($_POST['prescription_notes']??''),
                    'prescription_summary'=>(string)($_POST['prescription_summary']??''),
                    'prescription_safety_override_reason'=>(string)($_POST['prescription_safety_override_reason']??''),
                    'allergy_review_acknowledged'=>isset($_POST['allergy_review_acknowledged']),
                    'prescription_safety_acknowledged'=>isset($_POST['prescription_safety_acknowledged']),
                    'prescription_decision'=>(string)($_POST['prescription_decision']??'issued'),
                ]);
            }
        }
        $incomplete=!empty($GLOBALS['clinical_finalize_incomplete']);
        flash($incomplete?'warning':'error',$exception->getMessage());
        $id=(int)($_POST['encounter_id']??0);
        if($id){
            $focus=(string)($GLOBALS['clinical_finalize_focus']??'');
            $stage=['intake'=>'intake','alerts'=>'completion','assessment'=>'examination','charting'=>'charting','diagnosis'=>'diagnosis','disposition'=>'treatment','procedure'=>'treatment','consent'=>'treatment','prescription'=>'prescription','soap'=>'notes','instructions'=>'completion','followup'=>'followup','billing'=>'completion'][$focus]??'intake';
            header('Location: clinical_workspace.php?encounter_id='.$id.($focus!==''?'&focus='.rawurlencode($focus):'').'#'.$stage);exit;
        }
        header('Location: doctor_treatment.php');exit;
    }
}

if(isset($_GET['exit_context'])){clinical_context_clear();header('Location: doctor_treatment.php');exit;}
$encounterId=(int)($_GET['encounter_id']??0);$encounter=workspace_encounter($pdo,$encounterId);if(!$encounter){
    http_response_code(404);
    render_header('Clinical Encounter');
    ?>
    <section class="card setup-empty-state">
        <span class="eyebrow">Treatment workspace</span>
        <h2>Clinical encounter not found</h2>
        <p>The treatment record may have been completed, deleted during reset/demo cleanup, or the link may be outdated.</p>
        <div class="status-actions">
            <?php if(active_role_is('dentist')):?><a class="btn primary" href="doctor_treatment.php">Open My Treatment Dashboard</a><?php elseif(active_role_is('dental_assistant')):?><a class="btn primary" href="dashboard.php">Open Chairside Tasks</a><?php else:?><a class="btn primary" href="clinical.php">Open Clinical Oversight</a><?php endif;?>
            <?php if(task_link_allowed('queue.php')):?><a class="btn ghost" href="queue.php">Open Queue</a><?php endif;?>
        </div>
    </section>
    <?php
    render_footer();
    return;
}
$transferViewer=false;$emergencyAccess=false;
if(active_role_is('dentist')&&(int)$encounter['dentist_user_id']!==$userId){
    if(workflow_governance_schema_ready()){$accessStmt=$pdo->prepare('SELECT COUNT(*) FROM `' . table('clinical_encounter_transfers') . '` WHERE encounter_id=? AND to_dentist_user_id=? AND status IN ("pending","accepted")');$accessStmt->execute([$encounterId,$userId]);$transferViewer=(int)$accessStmt->fetchColumn()>0;}
    $emergencyAccess=isset($_GET['emergency'])&&!in_array((string)$encounter['status'],['finalized','addendum'],true)&&((int)($encounter['branch_id']??0)===(int)(current_user()['branch_id']??0)||(int)(current_user()['branch_id']??0)===0);
    if(!$transferViewer&&!$emergencyAccess){http_response_code(403);render_header('Encounter access');?><section class="card setup-empty-state"><h2>Another Dentist owns this encounter</h2><p>A consultation, transfer request, or emergency-review link is required before this record can be opened.</p><div class="status-actions"><a class="btn primary" href="doctor_treatment.php">Return to treatment dashboard</a><a class="btn ghost" href="clinical.php">Clinical records</a></div></section><?php render_footer();return;}
}
if($isAssistant&&!workspace_is_assigned_assistant($encounter)){http_response_code(403);render_header('Encounter access');?><section class="card setup-empty-state"><h2>This encounter is not assigned to you</h2><p>Return to Chairside Tasks and open an encounter assigned to your Dental Assistant account.</p><div class="status-actions"><a class="btn primary" href="dashboard.php">Return to Chairside Tasks</a><a class="btn ghost" href="queue.php">Open clinic queue</a></div></section><?php render_footer();return;}
if($isDentist||$isAssistant)clinical_context_activate($encounter);
$canWrite=workspace_can_write($encounter);$canTreatmentEntry=workspace_can_treatment_entry($encounter);$canCorrectBilling=active_role_is('dentist')&&(int)$encounter['dentist_user_id']===$userId&&in_array((string)$encounter['status'],['finalized','addendum'],true);$canScreen=workspace_can_screen($encounter);$openXray=$canScreen&&$encounter['status']!=='finalized'&&isset($_GET['open_xray']);$intake=active_patient_intake((int)$encounter['patient_id'],(int)($encounter['queue_entry_id']??0)?:null,(int)($encounter['appointment_id']??0)?:null);$vitals=workspace_latest($pdo,'vital_signs','encounter_id=?',[$encounterId]);$assessment=workspace_latest($pdo,'clinical_assessments','encounter_id=?',[$encounterId]);$procedures=clinical_billing_schema_ready()?clinical_billing_procedures($pdo,$encounterId):[];$pendingAssistantEntryCount=count(array_filter($procedures,static fn(array $row):bool=>(string)($row['entered_by_role']??'')==='dental_assistant' && (int)($row['verified_by_user_id']??0)<1));$procedure=$procedures?end($procedures):null;$followup=workspace_latest($pdo,'follow_ups','encounter_id=?',[$encounterId]);$recordCompletionLatest=(function_exists('clinical_record_completion_latest')&&clinical_record_completion_schema_ready($pdo))?clinical_record_completion_latest($pdo,$encounterId):null;$recordCompletionChecklist=$recordCompletionLatest['checklist']??[];$recordCompletionMissing=$recordCompletionLatest['missing']??[];
$assistantImageCount=0;if(schema_table_exists(table('documents'))){try{$imageStmt=$pdo->prepare('SELECT COUNT(*) FROM `' . table('documents') . '` WHERE encounter_id=?');$imageStmt->execute([$encounterId]);$assistantImageCount=(int)$imageStmt->fetchColumn();}catch(Throwable){$assistantImageCount=0;}}
$stmt=$pdo->prepare('SELECT i.*,p.title plan_title,p.status plan_status,p.dentist_user_id plan_dentist_user_id FROM `' . table('treatment_plan_items') . '` i JOIN `' . table('treatment_plans') . '` p ON p.id=i.treatment_plan_id WHERE p.patient_id=? AND i.status NOT IN ("declined","cancelled") ORDER BY FIELD(i.priority,"emergency","urgent","important","routine"),i.sequence_no,i.id');$stmt->execute([(int)$encounter['patient_id']]);$treatmentItems=$stmt->fetchAll();
foreach($treatmentItems as &$treatmentItemRow){$validConsent=clinical_valid_consent_for_item($pdo,(int)$encounter['patient_id'],(int)$treatmentItemRow['id'],(int)$encounter['dentist_user_id']);$treatmentItemRow['valid_consent_id']=$validConsent?(int)$validConsent['id']:0;$workReason=null;$treatmentItemRow['dentist_can_work']=dentist_can_work_treatment_item($pdo,(int)$encounter['dentist_user_id'],$treatmentItemRow,$workReason);$treatmentItemRow['work_reason']=$workReason;}unset($treatmentItemRow);
$encounterConsent=clinical_valid_consent_for_encounter($pdo,(int)$encounter['patient_id'],$encounterId,(int)$encounter['dentist_user_id']);
$selectedTreatmentItemId=(int)($procedure['treatment_plan_item_id']??0);$selectedTreatmentItem=null;foreach($treatmentItems as $item){if((int)$item['id']===$selectedTreatmentItemId){$selectedTreatmentItem=$item;break;}}
$imaging=clinical_recent_imaging($pdo,(int)$encounter['patient_id'],$encounterId,12);
$stmt=$pdo->prepare('SELECT id,invoice_no,amount,paid_amount,status FROM `' . table('invoices') . '` WHERE encounter_id=? AND status NOT IN ("voided","refunded") ORDER BY id DESC LIMIT 1');$stmt->execute([$encounterId]);$encounterInvoice=$stmt->fetch()?:null;
$assistantOptions=[];
if($canWrite){$assistantStmt=$pdo->prepare('SELECT u.id,u.name FROM `' . table('users') . '` u JOIN `' . table('roles') . '` r ON r.id=u.role_id WHERE r.code="dental_assistant" AND u.status="active" AND (u.branch_id=? OR u.branch_id IS NULL OR ?=0) ORDER BY u.name');$assistantStmt->execute([(int)($encounter['branch_id']??0),(int)($encounter['branch_id']??0)]);$assistantOptions=$assistantStmt->fetchAll();}
$encounterTransfers=workflow_governance_schema_ready()?governance_encounter_transfers($pdo,$encounterId):[];$openBillingCorrections=workflow_governance_schema_ready()?governance_open_billing_corrections($pdo,$encounterId,(int)($encounter['queue_entry_id']??0)):[];$qualifiedConsultants=[];if($canWrite&&workflow_governance_schema_ready()){$qualifiedConsultants=qualified_dentists_for_privilege((int)($encounter['branch_id']??0),'clinical_note_finalization',$userId);}
$stmt=$pdo->prepare('SELECT d.*,(SELECT o.tooth_number FROM `' . table('odontogram_entries') . '` o WHERE o.diagnosis_id=d.id ORDER BY o.id DESC LIMIT 1) chart_tooth,(SELECT o.surface FROM `' . table('odontogram_entries') . '` o WHERE o.diagnosis_id=d.id ORDER BY o.id DESC LIMIT 1) chart_surface FROM `' . table('diagnoses') . '` d WHERE d.encounter_id=? ORDER BY d.is_primary DESC,d.id');$stmt->execute([$encounterId]);$diagnoses=$stmt->fetchAll();if(!$diagnoses)$diagnoses=[[]];
$stmt=$pdo->prepare('SELECT * FROM `' . table('prescriptions') . '` WHERE encounter_id=? ORDER BY id DESC LIMIT 1');$stmt->execute([$encounterId]);$rx=$stmt->fetch()?:[];
$usageItems=[];$stmt=$pdo->prepare('SELECT cu.*,i.name inventory_name,i.sku inventory_sku FROM `' . table('clinical_usage_items') . '` cu LEFT JOIN `' . table('inventory_items') . '` i ON i.id=cu.inventory_item_id WHERE cu.encounter_id=? AND cu.fulfillment_status<>"cancelled" ORDER BY cu.id');$stmt->execute([$encounterId]);$usageItems=$stmt->fetchAll();
$inventoryCatalog=[];$inventoryStmt=$pdo->prepare('SELECT i.id,i.sku,i.name,i.category,i.unit,i.usage_cost,COALESCE(bs.current_stock,i.current_stock,0) branch_stock FROM `' . table('inventory_items') . '` i LEFT JOIN `' . table('inventory_branch_stocks') . '` bs ON bs.item_id=i.id AND bs.branch_id=? WHERE i.status="active" AND (i.branch_id=? OR i.branch_id IS NULL) ORDER BY i.category,i.name');$inventoryStmt->execute([(int)($encounter['branch_id']??0),(int)($encounter['branch_id']??0)]);$inventoryCatalog=$inventoryStmt->fetchAll();
$rxItems=[];if(!empty($rx['id'])){$catalogSelect=schema_column_exists(table('prescription_items'),'medicine_catalog_id')?'medicine_catalog_id':'NULL medicine_catalog_id';$stmt=$pdo->prepare('SELECT '.$catalogSelect.',medication_name,generic_name,indication medication_indication,strength,dosage,frequency,route,duration_days,quantity,instructions medication_instructions FROM `' . table('prescription_items') . '` WHERE prescription_id=? ORDER BY id');$stmt->execute([(int)$rx['id']]);$rxItems=$stmt->fetchAll();}
$prescriptionSafetyPreview=clinical_safety_get_preview($encounterId);
$prescriptionSafetyFields=(array)($prescriptionSafetyPreview['fields']??[]);
$prescriptionSafetyAssessment=(array)($prescriptionSafetyPreview['assessment']??[]);
if(!empty($prescriptionSafetyPreview['items'])&&is_array($prescriptionSafetyPreview['items']))$rxItems=$prescriptionSafetyPreview['items'];
if(!$prescriptionSafetyAssessment&&!empty($rx['safety_assessment_id']))$prescriptionSafetyAssessment=(array)(clinical_safety_load_assessment($pdo,(int)$rx['safety_assessment_id'])??[]);
$stmt=$pdo->prepare('SELECT * FROM `' . table('medical_alerts') . '` WHERE patient_id=? AND is_active=1 ORDER BY FIELD(severity,"critical","caution","information"),created_at DESC');$stmt->execute([(int)$encounter['patient_id']]);$alerts=$stmt->fetchAll();
$stmt=$pdo->prepare('SELECT * FROM `' . table('medical_histories') . '` WHERE patient_id=? ORDER BY created_at DESC LIMIT 3');$stmt->execute([(int)$encounter['patient_id']]);$medicalHistory=$stmt->fetchAll();
$stmt=$pdo->prepare('SELECT id,created_at,diagnosis,procedure_done,status,dentist_name FROM `' . table('clinical_encounters') . '` WHERE patient_id=? AND id<>? ORDER BY created_at DESC LIMIT 5');$stmt->execute([(int)$encounter['patient_id'],$encounterId]);$previous=$stmt->fetchAll();
$stmt=$pdo->prepare('SELECT * FROM `' . table('vital_signs') . '` WHERE patient_id=? AND (encounter_id IS NULL OR encounter_id<>?) ORDER BY recorded_at DESC,id DESC LIMIT 1');$stmt->execute([(int)$encounter['patient_id'],$encounterId]);$previousVitals=$stmt->fetch()?:[];
$services=clinic_services_catalog((int)($encounter['branch_id']??0)?:null);$encounterTreatmentServices=function_exists('treatment_path_encounter_services')?treatment_path_encounter_services($pdo,$encounter,$services):[];$billingServices=[];if(clinical_billing_schema_ready()){$billingStmt=$pdo->prepare('SELECT id,name,duration_minutes,standard_fee,fee_status,no_charge_reason FROM `' . table('service_catalog') . '` WHERE is_active=1 AND fee_status IN ("billable","no_charge") AND (branch_id=? OR branch_id IS NULL) ORDER BY name');$billingStmt->execute([(int)($encounter['branch_id']??0)]);$billingServices=$billingStmt->fetchAll();}$age='—';if($encounter['birth_date'])$age=(string)(new DateTime($encounter['birth_date']))->diff(new DateTime())->y;$doctorProfile=dentist_profile((int)$encounter['dentist_user_id'])?:[];$doctorDisplay=$doctorProfile?dentist_display_name($doctorProfile):(string)($encounter['dentist_name']?:'Assigned dentist');
$patientAgeInt=is_numeric($age)?(int)$age:0;$bpScreening=clinical_vitals_bp_screening($vitals?:[],$patientAgeInt);[$effectiveBpSys,$effectiveBpDia,$effectiveBpIsRepeat]=clinical_vitals_effective_bp($vitals?:[]);$bpSymptomLabels=clinical_vitals_symptom_labels((string)($vitals['bp_symptoms']??''));
$completionState=json_decode((string)($encounter['completion_check_json']??''),true);if(!is_array($completionState))$completionState=[];
$carePath=dental_encounter_care_path((string)($encounter['care_path']??'comprehensive'));
$carePathLabel=dental_encounter_care_path_label($carePath);
$condensedIntake=dental_encounter_condensed_intake($carePath);
$hpiRequired=!$condensedIntake;
$assessmentRequired=dental_encounter_requires_full_assessment($carePath);
$effectiveChiefComplaint=trim((string)($encounter['chief_complaint']?:($intake['chief_complaint']??'')));
$effectiveHistoryPresentCondition=trim((string)($encounter['history_present_condition']?:($intake['history_present_condition']??'')));
$intakeConfirmationsReady=$intake&&(int)($intake['allergies_confirmed']??0)===1&&(int)($intake['medications_confirmed']??0)===1&&(int)($intake['consent_acknowledged']??0)===1;
$intakeReady=$intakeConfirmationsReady&&$effectiveChiefComplaint!==''&&(!$hpiRequired||$effectiveHistoryPresentCondition!=='');
$assessmentStates=['extraoral_status','intraoral_status','soft_tissue_status','tmj_status','occlusion_status','radiographic_status'];$assessmentDomainReady=false;foreach($assessmentStates as $stateField){if(($assessment[$stateField]??'not_examined')!=='not_examined'){$assessmentDomainReady=true;break;}}
$generatedExaminationSummary=workspace_examination_summary((array)$assessment);
$effectiveExaminationSummary=trim((string)($encounter['examination']?:$generatedExaminationSummary));
$assessmentSummaryReady=$effectiveExaminationSummary!=='';$assessmentReady=!$assessmentRequired||($assessmentDomainReady&&$assessmentSummaryReady);
$diagnosisReady=(bool)array_filter($diagnoses,static fn(array $row):bool=>trim((string)($row['diagnosis_name']??''))!=='')||trim((string)($encounter['diagnosis']??''))!=='';
$dispositionReady=trim((string)($encounter['clinical_disposition']??''))!=='';
$soapReady=trim((string)($encounter['soap_note']??''))!=='';
$followReady=(string)($encounter['disposition']??'')==='no_follow_up'||(!empty($encounter['follow_up_date'])&&trim((string)($encounter['follow_up_purpose']??''))!=='');
$selectedConsentValid=true;if($procedures){foreach($procedures as $procedureConsentRow){if(clinical_billing_is_excluded_from_handoff($procedureConsentRow))continue;$procedureItemId=(int)($procedureConsentRow['treatment_plan_item_id']??0);$validProcedureConsent=$procedureItemId>0?clinical_valid_consent_for_item($pdo,(int)$encounter['patient_id'],$procedureItemId,(int)$encounter['dentist_user_id']):$encounterConsent;if(!$validProcedureConsent){$selectedConsentValid=false;break;}}}else{$selectedConsentValid=(bool)$encounterConsent;}
$dispositionRequiresProcedure=in_array((string)($encounter['clinical_disposition']??''),['treatment_performed','emergency_stabilization'],true);
$procedureReady=!$dispositionRequiresProcedure||!empty($procedures);
$consentCurrentlyRequired=!empty($procedures)||$dispositionRequiresProcedure||in_array((string)($encounter['clinical_disposition']??''),['medication_administered','diagnostic_procedure'],true);
$consentReady=!$consentCurrentlyRequired||$selectedConsentValid||mb_strlen(trim((string)($encounter['consent_exception_reason']??'')))>=20;
$vitalsReviewRecorded=!empty($completionState['vitals_review']);
$hasMedicalAlerts=!empty($alerts)||trim((string)($encounter['medical_alerts']??''))!=='';
$vitalsRequired=dental_encounter_requires_vitals($carePath,$procedures,(string)($encounter['clinical_disposition']??''),$hasMedicalAlerts,$usageItems);
$vitalsSkipReason=trim((string)($completionState['vitals_skip_reason']??$encounter['vitals_skip_reason']??''));
$vitalsSkipped=!$vitalsRequired&&!empty($completionState['vitals_skipped'])&&mb_strlen($vitalsSkipReason)>=10;
$vitalsMeasurementsReady=dental_encounter_vitals_row_has_measurement((array)$vitals);
$vitalsReviewReady=$vitalsRequired?($vitalsMeasurementsReady&&$vitalsReviewRecorded):($vitalsReviewRecorded||$vitalsSkipped);
$medicalAlertReady=!$hasMedicalAlerts||!empty($completionState['medical_alert_review']);
$chartReviewMode=(string)($completionState['chart_review_mode']??'');
$chartReviewReady=!empty($completionState['chart_review'])&&$chartReviewMode!=='';
$prescriptionDecision=(string)($completionState['prescription_decision']??'');
if(in_array((string)($prescriptionSafetyFields['prescription_decision']??''),['issued','not_required'],true))$prescriptionDecision=(string)$prescriptionSafetyFields['prescription_decision'];
$prescriptionIndicationValue=(string)($prescriptionSafetyFields['prescription_indication']??($rx['clinical_indication']??$encounter['diagnosis']??''));
$prescriptionNotesValue=(string)($prescriptionSafetyFields['prescription_notes']??($rx['notes']??''));
$prescriptionSummaryValue=(string)($prescriptionSafetyFields['prescription_summary']??$encounter['prescription']??'');
$prescriptionSafetyOverrideValue=(string)($prescriptionSafetyFields['prescription_safety_override_reason']??($rx['safety_override_reason']??''));
$prescriptionAllergyAck=!empty($prescriptionSafetyFields['allergy_review_acknowledged'])||!empty($rx['id']);
$prescriptionSafetyAck=!empty($prescriptionSafetyFields['prescription_safety_acknowledged'])||in_array((string)($rx['safety_status']??''),['warning_acknowledged','clear'],true);
$hasPrescriptionItems=!empty($rxItems);
$prescriptionCloseReady=($prescriptionDecision==='not_required'&&!$hasPrescriptionItems)||($prescriptionDecision==='issued'&&$hasPrescriptionItems);
$instructionsReviewReady=!empty($completionState['instructions_review'])&&(!$dispositionRequiresProcedure||trim((string)($encounter['patient_advice']??''))!=='');
$billingReviewReady=!empty($completionState['billing_review']);
$chartAge=is_numeric($age)?(int)$age:18;$chartDentition=$chartAge<6?'primary':($chartAge<=12?'mixed':'permanent');$chartEntries=[];$chartReady=schema_table_exists(table('odontogram_entries'));if($chartReady){$chartDentitionWhere=$chartDentition==='mixed'?'o.dentition IN ("permanent","primary","mixed")':'o.dentition=?';$chartArgs=$chartDentition==='mixed'?[(int)$encounter['patient_id']]:[(int)$encounter['patient_id'],$chartDentition];if(schema_table_exists(table('dental_condition_catalog'))){$stmt=$pdo->prepare('SELECT o.*,COALESCE(c.name,d.diagnosis_name) condition_name,COALESCE(c.category,IF(d.id IS NOT NULL,"diagnosis",o.finding_type)) category,d.diagnosis_name,d.diagnosis_status FROM `' . table('odontogram_entries') . '` o LEFT JOIN `' . table('dental_condition_catalog') . '` c ON c.code=o.condition_code LEFT JOIN `' . table('diagnoses') . '` d ON d.id=o.diagnosis_id WHERE o.patient_id=? AND '.$chartDentitionWhere.' AND o.status="active" ORDER BY o.recorded_at DESC,o.id DESC');}else{$stmt=$pdo->prepare('SELECT o.*,d.diagnosis_name condition_name,IF(d.id IS NOT NULL,"diagnosis",o.finding_type) category,d.diagnosis_name,d.diagnosis_status FROM `' . table('odontogram_entries') . '` o LEFT JOIN `' . table('diagnoses') . '` d ON d.id=o.diagnosis_id WHERE o.patient_id=? AND '.$chartDentitionWhere.' AND o.status="active" ORDER BY o.recorded_at DESC,o.id DESC');}$stmt->execute($chartArgs);$chartEntries=$stmt->fetchAll();}$chartByTooth=dental_group_active_entries_by_tooth($chartEntries);$chartBaseline=['active_count'=>count($chartEntries),'last_recorded_at'=>null,'last_dentist'=>''];if($chartReady){try{$baselineStmt=$pdo->prepare('SELECT MAX(o.recorded_at) last_recorded_at,COUNT(*) active_count,MAX(COALESCE(u.name,"")) last_dentist FROM `' . table('odontogram_entries') . '` o LEFT JOIN `' . table('users') . '` u ON u.id=o.recorded_by WHERE o.patient_id=? AND o.status="active"');$baselineStmt->execute([(int)$encounter['patient_id']]);$chartBaseline=$baselineStmt->fetch()?:$chartBaseline;}catch(Throwable $exception){error_log('DentalCare chart baseline lookup failed: '.$exception->getMessage());}}$chartPermanentUpper=['18','17','16','15','14','13','12','11','21','22','23','24','25','26','27','28'];$chartPermanentLower=['48','47','46','45','44','43','42','41','31','32','33','34','35','36','37','38'];$chartPrimaryUpper=['55','54','53','52','51','61','62','63','64','65'];$chartPrimaryLower=['85','84','83','82','81','71','72','73','74','75'];$chartUpper=$chartDentition==='primary'?$chartPrimaryUpper:($chartDentition==='mixed'?array_merge($chartPermanentUpper,$chartPrimaryUpper):$chartPermanentUpper);$chartLower=$chartDentition==='primary'?$chartPrimaryLower:($chartDentition==='mixed'?array_merge($chartPermanentLower,$chartPrimaryLower):$chartPermanentLower);$chartTeeth=array_values(array_unique(array_merge($chartUpper,$chartLower)));
$billingPreviewTotal=0.0;$billingPreviewBlocked=0;$billingPreviewExcluded=0;foreach($procedures as $billingRow){if(!clinical_billing_is_performed($billingRow)){$billingPreviewExcluded++;continue;}$state=clinical_billing_procedure_fee_status($billingRow);if($state==='billable')$billingPreviewTotal+=round((float)($billingRow['approved_fee_snapshot']??0),2);elseif($state==='unconfigured')$billingPreviewBlocked++;}
foreach($usageItems as $usagePreview){if((string)($usagePreview['billing_mode']??'')==='bill_separately')$billingPreviewTotal+=round((float)($usagePreview['quantity']??0)*(float)($usagePreview['unit_price']??0),2);}
$billingPreviewTotal=round($billingPreviewTotal,2);
$zeroChargeWithoutProcedure=$billingPreviewTotal<=0.005 && !$procedures;
$dischargeSummary=json_decode((string)($encounter['discharge_summary_json']??''),true);if(!is_array($dischargeSummary))$dischargeSummary=[];
$visitFlowState=treatment_flow_state($pdo,$encounter);
$dentistTreatmentSteps = [
    ['key'=>'intake','target'=>'intake','label'=>'First-seating safety and visit review','ready'=>$intakeReady && $vitalsReviewReady,'todo'=>!$intakeReady ? ($hpiRequired?'Confirm the completed first-seating safety summary, chief complaint, HPI, and patient/guardian acknowledgement.':'Confirm the completed first-seating safety summary, chief complaint, and patient/guardian acknowledgement.') : (!$vitalsReviewReady ? ($vitalsRequired?'Review the indicated first-seating measurements.':'Confirm that no additional measurement is required for this dental visit.') : 'Ready.')],
    ['key'=>'alerts','target'=>'completion','label'=>'Dental safety alerts','ready'=>$medicalAlertReady,'todo'=>$medicalAlertReady ? 'Ready.' : 'Acknowledge active dental safety alerts before release.'],
    ['key'=>'assessment','target'=>'examination','label'=>$assessmentRequired?'Examination':'Focused tooth assessment','ready'=>$assessmentReady,'todo'=>$assessmentReady?'Ready.':(!$assessmentDomainReady?'Choose at least one examination domain status.':'Confirm or edit the examination summary.')],
    ['key'=>'charting','target'=>'charting','label'=>'Odontogram review','ready'=>$chartReviewReady,'todo'=>!$chartReviewMode ? 'Choose today’s odontogram result: no changes, updated findings, continued planned treatment, completed treatment, or not applicable.' : (!$chartReviewReady ? 'Check Odontogram reviewed for this visit.' : 'Ready.')],
    ['key'=>'diagnosis','target'=>'diagnosis','label'=>'Diagnosis','ready'=>$diagnosisReady,'todo'=>$diagnosisReady ? 'Ready.' : 'Enter at least one diagnosis or use Healthy / no active dental disease.'],
    ['key'=>'disposition','target'=>'treatment','label'=>'Treatment / procedure outcome','ready'=>$dispositionReady && $procedureReady && $consentReady,'todo'=>!$dispositionReady ? 'Select what happened during this visit.' : (!$procedureReady ? 'Add the performed procedure for treatment/emergency outcomes.' : (!$consentReady ? 'Link consent or document the allowed exception.' : 'Ready.'))],
    ['key'=>'prescription','target'=>'prescription','label'=>'Prescription decision','ready'=>$prescriptionCloseReady,'todo'=>$prescriptionCloseReady ? 'Ready.' : 'Choose Prescription issued or No prescription required.'],
    ['key'=>'soap','target'=>'notes','label'=>'SOAP and patient instructions','ready'=>$soapReady && $instructionsReviewReady,'todo'=>!$soapReady ? 'Complete the SOAP clinical narrative.' : (!$instructionsReviewReady ? 'Confirm patient advice and instructions.' : 'Ready.')],
    ['key'=>'followup','target'=>'followup','label'=>'Follow-up decision','ready'=>$followReady,'todo'=>$followReady ? 'Ready.' : 'Choose no follow-up required or recommend a follow-up date and purpose.'],
    ['key'=>'billing','target'=>'completion','label'=>'Billing or no-payment release','ready'=>$billingReviewReady && $billingPreviewBlocked===0,'todo'=>$billingPreviewBlocked ? 'Correct blocked procedure fee source(s).' : (!$billingReviewReady ? 'Verify the billing handoff/no-payment release.' : 'Ready.')],
];
$dentistCompletedStepCount = count(array_filter($dentistTreatmentSteps, static fn(array $step): bool => !empty($step['ready'])));
$dentistNextStep = null;
foreach ($dentistTreatmentSteps as $step) { if (empty($step['ready'])) { $dentistNextStep = $step; break; } }
if (!$dentistNextStep) $dentistNextStep = ['key'=>'complete','target'=>'completion','label'=>'Ready to complete','ready'=>true,'todo'=>'All Dentist treatment path requirements are ready. Select the completion outcome and finalize.'];
$dentistTreatmentReady = $dentistCompletedStepCount === count($dentistTreatmentSteps);
$dentistCompletionButtonLabel = $dentistTreatmentReady ? 'Complete selected outcome' : 'Finish required items first';
$dentistCompletionDisabledAttr = $dentistTreatmentReady ? '' : ' disabled aria-disabled="true"';
render_header('Clinical Encounter');
$inventoryCatalogJson=e((string)json_encode($inventoryCatalog,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
?>
<div class="clinical-patient-banner card clinical-sticky-context">
  <div class="clinical-patient-identity"><span class="eyebrow"><?=e($carePathLabel)?> · <?=e(ucwords(str_replace('_',' ',(string)$encounter['visit_type'])))?> visit</span><h2><?=e(patient_full_name($encounter))?></h2><p><?=e((string)$encounter['patient_no'])?> · Age <?=e($age)?> · Queue <?=e((string)($encounter['queue_no']?:'—'))?> · <?=e((string)($encounter['chair_name']?:'No chair'))?></p></div>
  <div class="clinical-alert-summary"><span class="eyebrow">Dental treatment safety</span><strong><?=($encounter['medical_alerts']||$alerts)?'Alerts require review':'No active alert recorded'?></strong><small><?=e((string)($encounter['queue_service']?:'Dental visit'))?></small></div>
  <div class="clinical-provider-identity"><div class="doctor-avatar doctor-avatar-small"><?php if(!empty($doctorProfile['photo_path'])):?><img src="doctor_asset.php?type=photo&user_id=<?=(int)$encounter['dentist_user_id']?>" alt="<?=e($doctorDisplay)?>"><?php else:?><span><?=e(strtoupper(substr($doctorDisplay,0,1)))?></span><?php endif;?></div><div><span class="eyebrow">Treating dentist</span><strong><?=e($doctorDisplay)?></strong><small><?=e((string)($doctorProfile['specialty_name']??'Dentist'))?></small><small>Dental Assistant: <?=e((string)(($encounter['assistant_name']??'')?:'Not assigned'))?></small></div></div>
  <div class="status-actions"><span class="badge success">Active patient context</span><span class="badge"><?=e($carePathLabel)?></span><span class="badge"><?=e(ucwords(str_replace('_',' ',(string)$encounter['status'])))?></span><?php if($canWrite):?><button class="btn ghost" type="button" data-open="assistant-assignment-form"><?=!empty($encounter['assistant_user_id'])?'Change assistant':'Assign assistant'?></button><?php endif;?><?php if($canWrite&&($encounter['queue_status']??'')==='in_treatment'):?><button class="btn ghost" type="button" data-open="pause-treatment-form">Pause treatment</button><?php endif;?><?php if($canWrite&&workflow_governance_schema_ready()):?><button class="btn ghost" type="button" data-open="dentist-handoff-form">Request Dentist</button><?php endif;?><?php if($emergencyAccess):?><button class="btn danger" type="button" data-open="emergency-takeover-form">Emergency takeover</button><?php endif;?><a class="btn ghost" href="print_record.php?type=encounter&amp;id=<?=$encounterId?>" target="_blank" rel="noopener">Print summary</a><a class="btn ghost" href="visit_workflow.php?patient_id=<?=(int)$encounter['patient_id']?>">Timeline</a><a class="btn ghost" href="patients.php?action=view&id=<?=(int)$encounter['patient_id']?>&amp;tab=clinical&amp;encounter_id=<?=$encounterId?>">Patient profile</a><a class="btn danger ghost" href="clinical_workspace.php?exit_context=1">Exit patient record</a></div>
</div>
<?php if(!$isAssistant): ?><div class="clinical-flow-reference-popout" aria-label="Full visit flow reference">
  <button type="button" class="context-help-trigger" data-context-help-toggle aria-expanded="false">?</button>
  <div class="context-help-popover compact-flow-reference" role="tooltip">
    <strong>Full visit flow</strong>
    <ol><?php foreach($dentistTreatmentSteps as $step): ?><li class="<?=!empty($step['ready'])?'complete':'missing'?>"><strong><?=e((string)$step['label'])?></strong><small><?=e((string)$step['todo'])?></small></li><?php endforeach; ?></ol>
  </div>
</div><?php endif; ?>
<?php if($encounter['medical_alerts']||$alerts):?><div class="flash error clinical-alert-banner"><strong>Dental safety alerts:</strong> <?=nl2br(e((string)$encounter['medical_alerts']))?><?php foreach($alerts as $alert):?><span><?=e((string)$alert['alert_type'])?>: <?=e((string)$alert['description'])?></span><?php endforeach;?></div><?php endif;?>
<?php if($openBillingCorrections):?><div class="flash warning"><strong>Cashier returned this visit for billing correction.</strong> Correct each blocked procedure under Treatment. The visit returns to Cashier automatically after the responsible Dentist signs the correction.</div><?php endif;?>
<?php foreach($encounterTransfers as $handoff):if((int)$handoff['to_dentist_user_id']!==$userId||!in_array((string)$handoff['status'],['pending','accepted'],true))continue;?><div class="card"><div class="card-head"><div><h3><?=e(ucfirst((string)$handoff['request_type']))?> request</h3><p><?=e((string)$handoff['from_dentist_name'])?> → <?=e((string)$handoff['to_dentist_name'])?> · <?=e((string)$handoff['reason'])?></p></div><span class="badge"><?=e(module_status((string)$handoff['status']))?></span></div><?php if($handoff['status']==='pending'):?><form method="post" class="form-grid compact-form"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="decide_encounter_transfer"><input type="hidden" name="encounter_id" value="<?=$encounterId?>"><input type="hidden" name="transfer_id" value="<?=(int)$handoff['id']?>"><label class="wide">Decision note<input name="decision_note"></label><div class="status-actions wide"><button class="btn primary" name="decision" value="accepted">Accept</button><button class="btn ghost" name="decision" value="declined">Decline</button></div></form><?php elseif($handoff['request_type']==='consultation'):?><form method="post" class="form-grid compact-form"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="complete_consultation"><input type="hidden" name="encounter_id" value="<?=$encounterId?>"><input type="hidden" name="transfer_id" value="<?=(int)$handoff['id']?>"><label class="wide">Signed consultation note<textarea name="consultation_note" minlength="20" required></textarea></label><button class="btn primary wide">Sign consultation note</button></form><?php else:?><div class="alert info">Responsibility transfer accepted. Resume treatment from the assigned chair when ready.</div><?php endif;?></div><?php endforeach;?>

<?php if($canWrite):?>
<section class="clinical-flow-coach clinical-treatment-cockpit card" aria-label="Dentist treatment cockpit" data-dentist-treatment-cockpit data-current-required-key="<?=e((string)$dentistNextStep['key'])?>">
  <div class="cockpit-primary">
    <span class="eyebrow">Dentist treatment path · v0.7.4 compact cockpit</span>
    <h3>Do now: <strong data-next-required-label><?=e((string)$dentistNextStep['label'])?></strong></h3>
    <p class="cockpit-active-blocker" data-next-required-copy><?=e((string)$dentistNextStep['todo'])?></p>
    <small class="clinical-focus-status" data-clinical-focus-status aria-live="polite">Press Alt+N or click the button. Focus stays inside the treatment form and goes to the exact missing control.</small>
  </div>
  <div class="status-actions cockpit-actions compact-cockpit-actions">
    <span class="badge warning" data-next-required-chip><?=count($dentistTreatmentSteps)-$dentistCompletedStepCount?> required item<?=count($dentistTreatmentSteps)-$dentistCompletedStepCount===1?'':'s'?> left</span>
    <button class="btn primary" type="button" data-next-clinical-required>Go to exact missing field <kbd>Alt+N</kbd></button>
    <span class="context-help clinical-progress-help" tabindex="0">
      <button type="button" class="context-help-trigger" data-context-help-toggle aria-expanded="false">View checklist</button>
      <span class="context-help-popover wide" role="tooltip">
        <strong>Treatment checklist</strong>
        <ol class="cockpit-step-strip popout-step-strip" aria-label="Dentist treatment path progress"><?php foreach($dentistTreatmentSteps as $idx=>$step):?><li class="<?=!empty($step['ready'])?'complete':'missing'?>" data-cockpit-step="<?=e((string)$step['key'])?>"><span><?=!empty($step['ready'])?'✓':($idx+1)?></span><strong><?=e((string)$step['label'])?></strong><small><?=e((string)$step['todo'])?></small></li><?php endforeach;?></ol>
      </span>
    </span>
  </div>
</section>
<?php endif;?>

<?php if(!$isAssistant && in_array($carePath,['focused_dental','follow_up'],true)): ?>
<section class="card adaptive-encounter-banner" data-adaptive-encounter-banner>
  <div><span class="eyebrow">Adaptive encounter</span><h3><?=e($carePathLabel)?> — teeth-first path</h3><p>DentalCare uses the completed first-seating safety summary and skips a full HPI, complete examination, or additional measurement when they are not required for this dental visit. Tooth charting, diagnosis, consent, performed treatment, instructions, and billing remain protected.</p></div>
  <div class="status-actions"><button class="btn primary" type="button" data-clinical-jump="charting">Go directly to tooth chart</button><button class="btn ghost" type="button" data-clinical-jump="treatment">Go to treatment</button></div>
</section>
<?php endif; ?>

<?php if($isAssistant): ?>
<section class="assistant-clinical-lane card" aria-label="Dental Assistant chairside workflow">
  <div><span class="eyebrow">Dental Assistant chairside lane</span><h3>Prepare and document support work only</h3><p>Use the completed first-seating safety summary, then prepare chairside images, materials, and delegated procedure entries. The Dentist owns diagnosis, prescription, signature, billing release, and discharge.</p></div>
  <div class="assistant-handoff-state"><span>Next owner</span><strong><?=e((string)$encounter['dentist_name'])?></strong><small>Submit all entries for Dentist verification before leaving this encounter.</small></div>
</section>
<nav class="clinical-phase-nav card assistant-phase-nav" data-clinical-phase-tabs aria-label="Dental Assistant workflow phases">
  <button type="button" class="active" data-clinical-phase-target="review" data-clinical-phase-start="intake"><span>1</span><strong>Prepare</strong><small data-phase-state>First-seating summary</small></button>
  <button type="button" data-clinical-phase-target="assess" data-clinical-phase-start="charting"><span>2</span><strong>Document</strong><small data-phase-state>Chart and images</small></button>
  <button type="button" data-clinical-phase-target="treat" data-clinical-phase-start="treatment"><span>3</span><strong>Support</strong><small data-phase-state>Delegated treatment entries</small></button>
</nav>
<nav class="clinical-workspace-tabs clinical-step-tabs card assistant-step-tabs" data-clinical-section-tabs aria-label="Dental Assistant encounter steps">
  <button type="button" class="active" data-clinical-phase="review" data-clinical-target="intake"><span>1</span> Safety summary</button>
  <button type="button" data-clinical-phase="assess" data-clinical-target="charting"><span>2</span> Tooth chart &amp; images</button>
  <button type="button" data-clinical-phase="treat" data-clinical-target="treatment"><span>3</span> Delegated treatment</button>
</nav>
<?php else: ?>
<nav class="clinical-phase-nav card" data-clinical-phase-tabs aria-label="Clinical encounter workflow phases">
  <button type="button" class="active" data-clinical-phase-target="review" data-clinical-phase-start="intake"><span>1</span><strong>Review</strong><small data-phase-state>Visit and safety review</small></button>
  <button type="button" data-clinical-phase-target="assess" data-clinical-phase-start="examination"><span>2</span><strong>Assess</strong><small data-phase-state>Examine and diagnose</small></button>
  <button type="button" data-clinical-phase-target="treat" data-clinical-phase-start="treatment"><span>3</span><strong>Treat</strong><small data-phase-state>Procedure and medication</small></button>
  <button type="button" data-clinical-phase-target="close" data-clinical-phase-start="notes"><span>4</span><strong>Close</strong><small data-phase-state>SOAP, follow-up, billing</small></button>
</nav>
<nav class="clinical-workspace-tabs clinical-step-tabs card" data-clinical-section-tabs aria-label="Clinical encounter steps">
  <button type="button" class="active" data-clinical-phase="review" data-clinical-target="intake"><span>1</span> Visit review</button>
  <button type="button" data-clinical-phase="assess" data-clinical-target="examination"><span>2</span> Examination</button>
  <button type="button" data-clinical-phase="assess" data-clinical-target="charting"><span>3</span> Tooth chart</button>
  <button type="button" data-clinical-phase="assess" data-clinical-target="diagnosis"><span>4</span> Diagnosis</button>
  <button type="button" data-clinical-phase="treat" data-clinical-target="treatment"><span>5</span> Treatment / outcome</button>
  <button type="button" data-clinical-phase="treat" data-clinical-target="prescription"><span>6</span> Prescription <small>optional</small></button>
  <button type="button" data-clinical-phase="close" data-clinical-target="notes"><span>7</span> SOAP</button>
  <button type="button" data-clinical-phase="close" data-clinical-target="followup"><span>8</span> Follow-up</button>
  <button type="button" data-clinical-phase="close" data-clinical-target="completion"><span>9</span> Complete</button>
</nav>
<?php endif; ?>

<div class="clinical-workspace-layout" data-clinical-workspace data-clinical-focus-mode="0730" data-auto-focus-first-missing="<?=isset($_GET['completed'])?'0':'1'?>" data-chart-review-mode="<?=e($chartReviewMode)?>" data-care-path="<?=e($carePath)?>" data-default-clinical-target="<?=e(dental_encounter_care_path_target($carePath))?>" data-hpi-required="<?=$hpiRequired?'1':'0'?>" data-assessment-required="<?=$assessmentRequired?'1':'0'?>" data-vitals-required="<?=$vitalsRequired?'1':'0'?>" data-vitals-skipped="<?=$vitalsSkipped?'1':'0'?>" data-can-write="<?=$canWrite?'1':'0'?>" data-intake-ready="<?=$intakeReady?'1':'0'?>" data-intake-confirmations-ready="<?=$intakeConfirmationsReady?'1':'0'?>" data-vitals-review-ready="<?=$vitalsReviewReady?'1':'0'?>" data-has-medical-alerts="<?=$hasMedicalAlerts?'1':'0'?>" data-billing-blocked="<?=$billingPreviewBlocked?>" data-focus-requirement="<?=e((string)($_GET['focus']??''))?>" data-inventory-catalog="<?=$inventoryCatalogJson?>">
<main class="clinical-workspace-main">
<?php
$firstSeatingAssessment=dental_safety_assessment_for_encounter($encounter);
$firstSeatingHistory=dental_safety_latest_history($pdo,(int)$encounter['patient_id']);
$firstSeatingStatus=(string)($firstSeatingAssessment['status']??'missing');
$firstSeatingReady=dental_safety_assessment_is_ready($firstSeatingAssessment);
$firstSeatingAllergies=trim((string)($firstSeatingAssessment['allergies_value']??$firstSeatingHistory['allergies']??''));
$firstSeatingMedicines=trim((string)($firstSeatingAssessment['medicines_value']??$firstSeatingHistory['medications']??''));
$firstSeatingConditions=trim((string)($firstSeatingAssessment['conditions_value']??$firstSeatingHistory['conditions']??''));
$firstSeatingBp='';
if($firstSeatingAssessment&&((int)($firstSeatingAssessment['blood_pressure_systolic']??0)>0||(int)($firstSeatingAssessment['blood_pressure_diastolic']??0)>0)){
    $firstSeatingBp=trim((string)($firstSeatingAssessment['blood_pressure_systolic']??'')).'/'.trim((string)($firstSeatingAssessment['blood_pressure_diastolic']??''));
}
?>
<section class="card compact-clinical-section clinical-intake-vitals" data-clinical-panel="intake">
  <div class="card-head"><div><span class="eyebrow">Completed before treatment</span><h2>First-seating dental safety</h2><p>This treatment workspace uses the safety information confirmed at first seating. It is not a second health-intake form.</p></div><span class="badge <?=$firstSeatingReady?'success':($firstSeatingStatus==='hold'?'danger':'warning')?>"><?=e(dental_safety_assessment_status_label($firstSeatingStatus))?></span></div>
  <?php if($firstSeatingAssessment):?>
  <div class="clinical-summary-grid dental-safety-readonly-summary">
    <article><span>Change review</span><strong><?=e(match((string)($firstSeatingAssessment['change_status']??'')){'none'=>'No change reported','reported'=>'Change reported','unknown'=>'Clarification required',default=>'Not recorded'})?></strong><?php if(!empty($firstSeatingAssessment['changes_summary'])):?><small><?=e((string)$firstSeatingAssessment['changes_summary'])?></small><?php endif;?></article>
    <article><span>Allergies relevant to dental care</span><strong><?=e($firstSeatingAllergies!==''?$firstSeatingAllergies:'None recorded')?></strong></article>
    <article><span>Current medicines relevant to dental care</span><strong><?=e($firstSeatingMedicines!==''?$firstSeatingMedicines:'None recorded')?></strong></article>
    <article><span>Conditions affecting dental care</span><strong><?=e($firstSeatingConditions!==''?$firstSeatingConditions:'None recorded')?></strong></article>
    <?php if($firstSeatingBp!==''):?><article><span>Indicated blood pressure</span><strong><?=e($firstSeatingBp)?> mmHg</strong><small><?=e(ucwords(str_replace('_',' ',(string)($firstSeatingAssessment['bp_indication']??'dental indication'))))?></small></article><?php endif;?>
    <article><span>Reviewed by</span><strong><?=e((string)($firstSeatingAssessment['verified_by_name']??$firstSeatingAssessment['recorded_by_name']??'Clinical team'))?></strong><small><?=e(!empty($firstSeatingAssessment['verified_at'])?'Dentist verified '.date('M j, Y g:i A',strtotime((string)$firstSeatingAssessment['verified_at'])):'Recorded '.date('M j, Y g:i A',strtotime((string)$firstSeatingAssessment['recorded_at'])))?></small></article>
  </div>
  <?php if(!empty($firstSeatingAssessment['outcome_note'])):?><div class="notice <?=$firstSeatingStatus==='hold'?'warning':'info'?>"><strong>Safety decision note:</strong> <?=e((string)$firstSeatingAssessment['outcome_note'])?></div><?php endif;?>
  <div class="button-row"><a class="btn ghost" href="<?=e(dental_safety_assessment_url((int)($encounter['queue_entry_id']??0)))?>">View first-seating assessment</a></div>
  <?php else:?><div class="notice warning"><strong>Legacy encounter.</strong> This treatment was opened before the first-seating gate was installed. Do not recreate intake inside treatment; record any newly reported safety information as a dated clinical addendum and complete the assessment before a future treatment visit.</div><?php endif;?>
</section>

<section class="card clinical-record-shell">
<div class="card-head"><div><h2>Clinical record</h2><p>Document what happened. A performed procedure is not required when a valid no-treatment outcome is recorded.</p></div><div class="status-actions"><a class="btn ghost" href="odontogram.php?patient_id=<?=(int)$encounter['patient_id']?>&encounter_id=<?=$encounterId?>">Tooth model</a><a class="btn ghost" href="consents.php?patient_id=<?=(int)$encounter['patient_id']?>&encounter_id=<?=$encounterId?><?=$selectedTreatmentItemId?'&item_id='.$selectedTreatmentItemId:''?>&return=clinical">Consent</a><?php if($canScreen&&$encounter['status']!=='finalized'):?><button class="btn ghost" type="button" data-open="chairside-xray-form">Capture X-ray</button><?php endif;?></div></div>
<?php if($recordCompletionLatest):?><div class="alert <?=($recordCompletionLatest['review_status']??'needs_review')==='complete'?'success':'warning'?>"><strong>Signed record completion: <?=e(module_status((string)($recordCompletionLatest['review_status']??'needs_review')))?>.</strong> <?php if($recordCompletionMissing):?>Missing/needs review: <?=e(implode(', ',array_map(static fn(array $x):string=>(string)($x['label']??$x['key']??'item'),array_slice($recordCompletionMissing,0,6))))?><?=count($recordCompletionMissing)>6?'…':''?><?php else:?>The signed encounter has a complete review snapshot.<?php endif;?> <a target="_blank" href="print_record.php?type=encounter&amp;id=<?=$encounterId?>">Print signed summary</a></div><?php elseif(clinical_record_completion_schema_ready($pdo)&&$encounter['status']==='finalized'):?><div class="alert warning"><strong>Record completion review not yet generated.</strong> Re-save/finalize this encounter or use System Setup catch-up repair on copied systems.</div><?php endif;?>
<div class="clinical-charting-panel" data-clinical-panel="charting" hidden>
<div class="embedded-chart-layout">
<section class="embedded-odontogram">
<div class="card-head"><div><h3>Live tooth model</h3><p><?= $canWrite ? 'Review the latest patient chart. Click a tooth only when there is a finding/change; healthy or unchanged charts can be confirmed without tooth-by-tooth charting.' : 'This chart is read-only. Only the assigned dentist can record findings.' ?></p></div><span class="badge"><?=e(ucfirst($chartDentition))?></span></div><?php if(!$canWrite):?><div class="flash warning chart-access-notice" data-chart-access-notice>Read-only chart. Sign in as <?=e($doctorDisplay)?> to record tooth findings for this encounter.</div><?php endif;?>
<div class="odontogram-baseline-card">
  <div><strong>Previous odontogram baseline</strong><span><?= (int)($chartBaseline['active_count']??0) ?> active finding<?= (int)($chartBaseline['active_count']??0)===1?'':'s' ?><?= !empty($chartBaseline['last_recorded_at'])?' · Last updated '.e(date('M j, Y g:i A',strtotime((string)$chartBaseline['last_recorded_at']))):'' ?><?= !empty($chartBaseline['last_dentist'])?' by '.e((string)$chartBaseline['last_dentist']):'' ?></span></div>
  <?php if($canWrite):?><div class="chart-review-result" role="radiogroup" aria-label="Today odontogram result">
    <?php foreach(['no_changes'=>'Reviewed today — no changes / healthy dentition','updated_findings'=>'Updated with new findings','continued_planned_treatment'=>'Continued previous planned treatment','completed_treatment'=>'Marked treatment completed on chart','not_applicable'=>'Charting not applicable with reason in notes'] as $value=>$label):?>
      <label><input type="radio" name="chart_review_mode" value="<?=$value?>" form="clinical-record-main" data-chart-review-mode-option <?=$chartReviewMode===$value?'checked':''?>> <span><?=$label?></span></label>
    <?php endforeach;?>
    <label class="check-label"><input type="checkbox" name="chart_review_acknowledged" value="1" form="clinical-record-main" data-shared-clinical-check="chart_review_acknowledged" <?=!empty($completionState['chart_review'])?'checked':''?>><span><strong>Odontogram reviewed for this visit</strong><small>Previous chart carries forward. Update only what changed today.</small></span></label>
    <button class="btn ghost compact" type="button" data-healthy-dentition-shortcut>Healthy / no findings</button>
  </div><?php endif;?>
</div>
<?php if($chartReady):?>
<div class="embedded-arch"><span>Upper</span><div class="tooth-model-row compact-row"><?php foreach($chartUpper as $tooth):$url='odontogram.php?patient_id='.(int)$encounter['patient_id'].'&dentition='.urlencode($chartDentition).'&tooth='.$tooth.'&encounter_id='.$encounterId.($canWrite?'&open_finding=1':'');echo dental_render_tooth_model($tooth,$chartByTooth[$tooth]??[],$url,false,'upper',true,['interactive'=>true,'editable'=>$canWrite,'dialog_id'=>'finding-form','read_only_message'=>'Read-only chart. Only '.$doctorDisplay.' can record findings for this encounter.']);endforeach;?></div></div>
<div class="dental-midline"><span>Patient right</span><span>Midline</span><span>Patient left</span></div>
<div class="embedded-arch"><span>Lower</span><div class="tooth-model-row compact-row"><?php foreach($chartLower as $tooth):$url='odontogram.php?patient_id='.(int)$encounter['patient_id'].'&dentition='.urlencode($chartDentition).'&tooth='.$tooth.'&encounter_id='.$encounterId.($canWrite?'&open_finding=1':'');echo dental_render_tooth_model($tooth,$chartByTooth[$tooth]??[],$url,false,'lower',true,['interactive'=>true,'editable'=>$canWrite,'dialog_id'=>'finding-form','read_only_message'=>'Read-only chart. Only '.$doctorDisplay.' can record findings for this encounter.']);endforeach;?></div></div>
<?php else:?><div class="queue-empty">Apply the structured dental-chart update before recording tooth findings.</div><?php endif;?>
<div class="patient-quick-actions"><a class="btn primary" href="odontogram.php?patient_id=<?=(int)$encounter['patient_id']?>&dentition=<?=e($chartDentition)?>&encounter_id=<?=$encounterId?>">Open full tooth chart</a><?php if($canScreen&&$encounter['status']!=='finalized'):?><button class="btn ghost" type="button" data-open="chairside-xray-form">Capture / upload X-ray</button><?php endif;?><a class="btn ghost" href="periodontal.php?patient_id=<?=(int)$encounter['patient_id']?>">Periodontal chart</a><a class="btn ghost" href="documents.php?patient_id=<?=(int)$encounter['patient_id']?>">Images and X-rays</a><a class="btn ghost" href="consents.php?patient_id=<?=(int)$encounter['patient_id']?>">Consents</a></div>
</section>
<aside class="embedded-findings-panel"><div class="card-head"><div><h3>Active findings</h3><p>Current conditions recorded for this dentition.</p></div><span class="badge"><?=count($chartEntries)?></span></div>
<?php foreach(array_slice($chartEntries,0,8) as $finding):?><article><strong><?=e(dental_tooth_display_label((string)$finding['tooth_number']))?> · <?=e(dental_surface_display((string)($finding['surface']??''),(string)$finding['tooth_number']))?></strong><span><?=e((string)($finding['condition_name']??module_status((string)$finding['condition_code'])))?></span><small><?=e(module_status((string)($finding['severity']??'not recorded')))?> · <?=e(module_status((string)($finding['chart_layer']??'existing')))?></small></article><?php endforeach;?>
<?php if(!$chartEntries):?><div class="queue-empty">No active tooth findings recorded.</div><?php endif;?>
<a class="btn ghost wide" href="treatment.php?patient_id=<?=(int)$encounter['patient_id']?>">Open treatment plan</a></aside>
</div>
<section class="clinical-imaging-strip"><div class="card-head"><div><h3>Encounter imaging</h3><p>X-rays and photographs linked to this treatment visit and tooth region.</p></div><div class="status-actions"><span class="badge"><?=count($imaging)?></span><?php if($canScreen&&$encounter['status']!=='finalized'):?><button class="btn ghost" type="button" data-open="chairside-xray-form">Capture / upload</button><?php endif;?></div></div><div class="clinical-imaging-grid"><?php foreach($imaging as $image):$isImage=str_starts_with((string)($image['mime_type']??''),'image/');$imageRegion=trim((string)($image['tooth_region']??''));?><article><?php if($isImage):?><a class="clinical-image-preview" href="download_document.php?id=<?=(int)$image['id']?>" target="_blank" rel="noopener"><img src="download_document.php?id=<?=(int)$image['id']?>&amp;preview=1" alt="<?=e((string)$image['category'])?><?= $imageRegion!==''?' · '.e($imageRegion):'' ?>" loading="lazy"></a><?php else:?><div class="clinical-image-icon">PDF</div><?php endif;?><div><strong><?=e((string)$image['category'])?></strong><span><?= $imageRegion!==''?e((dental_is_valid_fdi_tooth($imageRegion)?dental_tooth_display_label($imageRegion):$imageRegion)):'General / full arch' ?></span><small><?=e(date('M j, Y g:i A',strtotime((string)$image['created_at'])))?> · <?=e((string)($image['uploader']?:'Clinical team'))?></small><?php if(!empty($image['description'])):?><small><?=e((string)$image['description'])?></small><?php endif;?></div><a href="download_document.php?id=<?=(int)$image['id']?>" target="_blank" rel="noopener">Open</a></article><?php endforeach;?><?php if(!$imaging):?><div class="queue-empty">No X-ray or clinical image has been attached to this encounter.</div><?php endif;?></div></section>
</div>

<form id="clinical-record-main" method="post" class="clinical-record-form redesigned-clinical-form" data-preserve-scroll data-keyboard-entry data-clinical-record-form>
<input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="encounter_id" value="<?=$encounterId?>">
<?php if($canWrite):?><div class="clinical-command-strip"><button class="btn secondary" type="button" data-next-clinical-required>Focus next missing field <kbd>Alt+N</kbd></button><small>Current focus remains inside the treatment form. Use Save draft anytime; Complete is enabled only when required items are ready.</small></div><?php endif;?>

<section class="clinical-form-panel" data-clinical-panel="examination" hidden>
  <div class="section-heading"><div><span class="eyebrow">Dentist validation</span><h3><?=$assessmentRequired?'Comprehensive examination':'Optional broader examination'?></h3><p><?=$assessmentRequired?'Choose Normal, Abnormal, Not examined, or Not applicable. Details open only when needed.':'For a focused tooth visit, use this section only when broader findings are clinically relevant. Tooth-specific charting remains in the odontogram.'?></p></div></div>
  <div class="form-grid compact-form"><label>Chief complaint <span class="required-mark">Required</span><textarea rows="2" name="chief_complaint" data-required-first <?=$canWrite?'':'readonly'?>><?=e($effectiveChiefComplaint)?></textarea></label><label>History of present condition <?=$hpiRequired?'<span class="required-mark">Required</span>':'<small>Optional for this focused path</small>'?><textarea rows="2" name="history_present_condition" <?=$hpiRequired?'data-required-first':''?> <?=$canWrite?'':'readonly'?>><?=e($effectiveHistoryPresentCondition)?></textarea></label></div>
  <div class="exam-domain-grid">
  <?php foreach([
    ['extraoral','Extraoral'],['intraoral','Intraoral / dental'],['soft_tissue','Soft tissue'],['tmj','TMJ'],['occlusion','Occlusion'],['radiographic','Radiographic']
  ] as [$key,$label]):$state=(string)($assessment[$key.'_status']??'not_examined');$finding=(string)($assessment[$key.'_findings']??'');?>
    <article class="exam-domain" data-exam-domain><div><strong><?=$label?></strong><select name="<?=$key?>_status" data-exam-status <?=$canWrite?'':'disabled'?>><?php foreach(['normal'=>'Normal','abnormal'=>'Abnormal','not_examined'=>'Not examined','not_applicable'=>'Not applicable'] as $value=>$text):?><option value="<?=$value?>" <?=$state===$value?'selected':''?>><?=$text?></option><?php endforeach;?></select></div><textarea rows="3" name="<?=$key?>_findings" data-exam-detail placeholder="Describe abnormal findings or relevant observations" <?=$canWrite?'':'readonly'?>><?=e($finding)?></textarea></article>
  <?php endforeach;?>
  </div>
  <div class="form-grid compact-form"><label>Oral hygiene<select name="oral_hygiene_status" <?=$canWrite?'':'disabled'?>><option value="">Not recorded</option><?php foreach(['Good','Fair','Poor','Requires intensive instruction'] as $value):?><option <?=($assessment['oral_hygiene_status']??'')===$value?'selected':''?>><?=e($value)?></option><?php endforeach;?></select></label><label>Risk assessment<textarea rows="2" name="risk_assessment" <?=$canWrite?'':'readonly'?>><?=e((string)($assessment['risk_assessment']??''))?></textarea></label><label>Prognosis<textarea rows="2" name="prognosis" <?=$canWrite?'':'readonly'?>><?=e((string)($assessment['prognosis']??''))?></textarea></label><label class="wide">Examination summary <?=$assessmentRequired?'<span class="required-mark">Built automatically and required</span>':'<small>Optional for this focused path</small>'?><textarea rows="3" name="examination_summary" <?=$assessmentRequired?'data-required-first':''?> data-examination-summary data-generated-summary="<?=trim((string)($encounter['examination']??''))===''?'1':'0'?>" <?=$canWrite?'':'readonly'?>><?=e($effectiveExaminationSummary)?></textarea></label></div>
</section>

<section class="clinical-form-panel" data-clinical-panel="diagnosis" hidden>
  <div class="section-heading"><div><span class="eyebrow">Clinical assessment</span><h3>Diagnosis</h3><p>Choose the tooth and affected surface when applicable. If the teeth are healthy/unchanged, use Healthy / no active dental disease instead of tooth-by-tooth charting.</p></div><?php if($canWrite):?><div class="status-actions"><button type="button" class="btn ghost" data-healthy-dentition-shortcut>Healthy / no active dental disease</button><button type="button" class="btn ghost" data-add-diagnosis>+ Add diagnosis</button></div><?php endif;?></div>
  <div class="diagnosis-list" data-diagnosis-list>
  <?php foreach($diagnoses as $i=>$diagnosis):
      $rawDiagnosisRegion=(string)($diagnosis['tooth_region']??'');
      $diagnosisTooth=(string)($diagnosis['chart_tooth']??'');
      if($diagnosisTooth==='')$diagnosisTooth=(string)(dental_extract_fdi_tooth($rawDiagnosisRegion)??'');
      $diagnosisSurfaceText=(string)($diagnosis['chart_surface']??'');
      if($diagnosisSurfaceText==='')$diagnosisSurfaceText=implode(',',dental_surface_codes_from_text($rawDiagnosisRegion,$diagnosisTooth));
      $diagnosisRegionValue=$diagnosisTooth!==''?$diagnosisTooth:$rawDiagnosisRegion;
      $selectedDiagnosisSurfaces=dental_surface_codes_from_text($diagnosisSurfaceText,$diagnosisTooth);
  ?>
    <article class="diagnosis-row" data-diagnosis-row>
      <input type="hidden" name="diagnosis_id[]" value="<?=(int)($diagnosis['id']??0)?>">
      <div class="diagnosis-row-head"><strong data-diagnosis-label><?=$i===0?'Primary diagnosis':'Additional diagnosis'?></strong><?php if($canWrite):?><button type="button" class="icon-btn" data-remove-diagnosis aria-label="Remove diagnosis">×</button><?php endif;?></div>
      <div class="diagnosis-fields">
        <label>Tooth / region<input name="diagnosis_region[]" value="<?=e($diagnosisRegionValue)?>" placeholder="FDI tooth, arch, quadrant, or soft tissue" data-diagnosis-region <?=$canWrite?'':'readonly'?>></label>
        <label class="diagnosis-search-label">Search or enter diagnosis<input type="search" name="diagnosis_name[]" value="<?=e((string)($diagnosis['diagnosis_name']??($i===0?$encounter['diagnosis']:'')))?>" autocomplete="off" data-diagnosis-search <?=$canWrite?'':'readonly'?>><div class="lookup-results" data-diagnosis-results hidden></div></label>
        <label>Code<input name="diagnosis_code[]" value="<?=e((string)($diagnosis['diagnosis_code']??''))?>" data-diagnosis-code <?=$canWrite?'':'readonly'?>></label>
        <label>Severity<select name="diagnosis_severity[]" <?=$canWrite?'':'disabled'?>><option value="">Not set</option><?php foreach(['mild','moderate','severe','critical'] as $value):?><option value="<?=$value?>" <?=($diagnosis['severity']??'')===$value?'selected':''?>><?=e(ucfirst($value))?></option><?php endforeach;?></select></label>
        <label>Status<select name="diagnosis_status[]" data-diagnosis-status <?=$canWrite?'':'disabled'?>><?php foreach(['provisional','confirmed','resolved','chronic','under_observation','referred'] as $value):?><option value="<?=$value?>" <?=($diagnosis['diagnosis_status']??'provisional')===$value?'selected':''?>><?=e(ucwords(str_replace('_',' ',$value)))?></option><?php endforeach;?></select></label>
        <fieldset class="wide diagnosis-surface-control" data-diagnosis-surface-control <?=$diagnosisTooth===''?'hidden':''?>>
          <legend data-diagnosis-surface-title>Affected tooth surface</legend>
          <input type="hidden" name="diagnosis_surfaces[]" value="<?=e(implode(',',$selectedDiagnosisSurfaces))?>" data-diagnosis-surfaces>
          <div class="diagnosis-surface-options">
            <?php foreach(['M'=>['Mesial','all'],'D'=>['Distal','all'],'F'=>['Facial','anterior'],'L'=>['Lingual','all'],'B'=>['Buccal','posterior']] as $surfaceCode=>$surfaceMeta):?>
              <label data-diagnosis-surface-option data-surface-scope="<?=e($surfaceMeta[1])?>"><input type="checkbox" value="<?=e($surfaceCode)?>" <?=in_array($surfaceCode,$selectedDiagnosisSurfaces,true)?'checked':''?> <?=$canWrite?'':'disabled'?>><span><strong><?=e($surfaceCode)?></strong><?=e($surfaceMeta[0])?></span></label>
            <?php endforeach;?>
          </div>
          <small data-diagnosis-surface-help>For precise caries charting, choose the affected surface; otherwise Whole tooth is used.</small>
        </fieldset>
        <label class="wide">Notes<textarea rows="2" name="diagnosis_notes[]" <?=$canWrite?'':'readonly'?>><?=e((string)($diagnosis['notes']??''))?></textarea></label>
      </div>
    </article>
  <?php endforeach;?>
  </div>
  <label>Diagnosis summary<input name="diagnosis_summary" value="<?=e((string)$encounter['diagnosis'])?>" <?=$canWrite?'':'readonly'?>></label>
</section>

<section class="clinical-form-panel" data-clinical-panel="treatment" hidden>
  <div class="section-heading"><div><span class="eyebrow">Treatment or disposition</span><h3>What happened during this visit?</h3><p>Select the clinical outcome first. Only applicable fields remain open.</p></div></div>
  <div class="disposition-picker"><label class="wide">Clinical disposition<select name="clinical_disposition" data-clinical-disposition <?=$canWrite?'':'disabled'?>><option value="">Select outcome</option><?php foreach(['treatment_performed'=>'Treatment performed today','medication_prescribed_only'=>'Medication prescribed only','medication_administered'=>'Medication administered in clinic','diagnostic_procedure'=>'Diagnostic procedure / test','imaging_only'=>'Imaging only','examination_only'=>'Examination and advice only','no_treatment_required'=>'No treatment required','observation'=>'Observation / monitor','treatment_advised_declined'=>'Treatment advised but declined','treatment_deferred'=>'Treatment deferred','referral'=>'Referred to another provider','emergency_stabilization'=>'Emergency stabilization'] as $value=>$label):?><option value="<?=$value?>" <?=($encounter['clinical_disposition']??'')===$value?'selected':''?>><?=$label?></option><?php endforeach;?></select></label></div>
  <div class="form-grid compact-form" data-disposition-explanation><label class="wide">Clinical reason / outcome explanation<textarea rows="3" name="disposition_reason" <?=$canWrite?'':'readonly'?>><?=e((string)($encounter['disposition_reason']??''))?></textarea></label><label class="wide">Advice given to patient<textarea rows="3" name="patient_advice" <?=$canWrite?'':'readonly'?>><?=e((string)($encounter['patient_advice']??''))?></textarea></label><label class="wide">Proposed, deferred, declined, or referral plan<textarea rows="3" name="treatment_plan" <?=$canWrite?'':'readonly'?>><?=e((string)$encounter['treatment_plan'])?></textarea></label></div>

  <div class="procedure-panel" data-procedure-panel>
    <div class="section-heading minor"><div><h4>Procedures performed</h4><p>Add every completed clinical service separately. The system copies the approved service or treatment-plan fee and prepares the Cashier invoice automatically.</p></div><?php if($canTreatmentEntry):?><button class="btn primary" type="button" data-open="procedure-add-form">+ <?=$isAssistant?'Add treatment entry':'Add performed procedure'?></button><?php endif;?></div>
    <?php if(!clinical_billing_schema_ready()):?><div class="alert warning"><strong>Update required.</strong> Apply Version 0.5.9.8.15 before recording a procedure.</div><?php endif;?>
    <div class="module-card-grid clinical-procedure-list">
    <?php foreach($procedures as $row):$feeState=clinical_billing_procedure_fee_status($row);$itemId=(int)($row['treatment_plan_item_id']??0);$rowConsent=$itemId>0?clinical_valid_consent_for_item($pdo,(int)$encounter['patient_id'],$itemId,(int)$encounter['dentist_user_id']):$encounterConsent;$enteredName=(string)(($row['entered_by_name']??'')?:($row['assistant_name']??$row['dentist_name']??'Unknown'));$enteredRole=(string)($row['entered_by_role']??'dentist');?>
      <article class="module-card" data-clinical-procedure>
        <div class="card-head"><div><span class="eyebrow"><?=e($itemId>0?'Treatment plan':'Service catalogue')?></span><h4><?=e((string)$row['procedure_name'])?><?=!empty($row['tooth_region'])?' · '.e((string)$row['tooth_region']):''?></h4></div><span class="badge"><?=e(module_status((string)$row['status']))?></span></div>
        <dl><dt>Cashier handoff</dt><dd><?php if($feeState==='billable'):?><strong>₱<?=number_format((float)$row['approved_fee_snapshot'],2)?></strong><?php elseif($feeState==='no_charge'):?><span class="badge success">Authorized no-charge</span><?php elseif($feeState==='not_billable'):?><span class="badge">Not billed today</span><?php elseif($feeState==='pending_handoff'):?><span class="badge warning">Pending finalization</span><?php else:?><span class="badge danger">Fee blocked</span><?php endif;?></dd><dt>Billing source</dt><dd><?=e(module_status((string)($row['fee_source']??'unlinked')))?></dd><dt>Consent</dt><dd><?= clinical_billing_is_excluded_from_handoff($row)?'Not required for non-billable outcome':($rowConsent?'Signed':'Required before finalization') ?></dd></dl>
        <?php if(!empty($row['no_charge_reason'])):?><p class="notice"><strong>No-charge reason:</strong> <?=e((string)$row['no_charge_reason'])?></p><?php endif;?>
        <?php if(!empty($row['disposition_reason'])):?><p class="notice"><strong>Not billed today:</strong> <?=e((string)$row['disposition_reason'])?><?php if(!empty($row['patient_agreement_recorded_at'])):?> · Patient agreement recorded <?=e(date('M j, Y g:i A',strtotime((string)$row['patient_agreement_recorded_at'])))?><?php endif;?></p><?php endif;?>
        <?php if(!empty($row['outcome'])):?><p><?=nl2br(e((string)$row['outcome']))?></p><?php endif;?><p class="muted"><strong>Responsible Dentist:</strong> <?=e((string)($row['dentist_name']??$encounter['dentist_name']))?> · <strong>Entered by:</strong> <?=e($enteredName)?> (<?=e(module_status($enteredRole))?>)<?php if(!empty($row['verified_by_user_id'])):?> · <strong>Verified by:</strong> <?=e((string)($row['verified_by_name']??'Dentist'))?><?=!empty($row['verified_at'])?' on '.e(date('M j, Y g:i A',strtotime((string)$row['verified_at']))):''?><?php elseif($enteredRole==='dental_assistant'):?> · <span class="badge warning">Awaiting Dentist verification</span><?php endif;?></p>
        <div class="status-actions"><a class="btn ghost" href="consents.php?patient_id=<?=(int)$encounter['patient_id']?>&encounter_id=<?=$encounterId?><?=$itemId?'&item_id='.$itemId:''?>&return=clinical"><?=$rowConsent?'Review consent':'Obtain consent'?></a><?php if($canWrite && $enteredRole==='dental_assistant' && empty($row['verified_by_user_id']) && (string)$row['status']!=='cancelled'):?><button class="btn primary" type="submit" form="verify-procedure-<?=(int)$row['id']?>">Verify entry</button><?php endif;?><?php if($canTreatmentEntry && (string)$row['status'] !== 'completed' && (!$isAssistant || (int)($row['entered_by_user_id']??0)===$userId) && empty($row['verified_by_user_id'])):?><button class="btn ghost" type="submit" form="remove-procedure-<?=(int)$row['id']?>">Remove draft</button><button class="btn ghost" type="button" data-open="procedure-outcome-<?=(int)$row['id']?>">Defer / not performed</button><?php endif;?><?php if($canCorrectBilling && $feeState === 'unconfigured'):?><button class="btn primary" type="button" data-open="procedure-correction-<?=(int)$row['id']?>">Correct billing source</button><?php endif;?></div>
      </article>
    <?php endforeach;?>
    <?php if(!$procedures):?><div class="queue-empty">No performed procedure has been added. For treatment-performed outcomes, add each service before finalization.</div><?php endif;?>
    </div>
    <?php if($pendingAssistantEntryCount>0):?><div class="alert warning wide"><strong>Dentist verification required.</strong> <?=$pendingAssistantEntryCount?> delegated treatment <?=$pendingAssistantEntryCount===1?'entry is':'entries are'?> still awaiting review. Open each entry and select <b>Verify entry</b> before completing the encounter.</div><?php endif;?>
    <div class="wide consent-status-card <?=(!$procedures||$selectedConsentValid)?'ready':'blocked'?>" data-consent-status><div><strong><?=!$procedures?'Consent will be checked when a procedure is added':($selectedConsentValid?'Consent record available':'Consent review required')?></strong><span>Each treatment-plan procedure requires its matching signed consent. Unplanned services use the encounter consent.</span></div><a class="btn ghost" href="consents.php?patient_id=<?=(int)$encounter['patient_id']?>&encounter_id=<?=$encounterId?>&return=clinical">Manage consents</a></div>
    <label class="wide check-label emergency-consent-toggle"><input type="checkbox" name="emergency_consent_exception" value="1" data-emergency-consent <?=$canWrite?'':'disabled'?>> <span>Genuine emergency: treatment cannot safely be delayed and ordinary consent cannot reasonably be obtained.</span></label><label class="wide" data-emergency-reason>Emergency exception reason<textarea rows="2" name="consent_exception_reason" minlength="20" <?=$canWrite?'':'readonly'?>><?=e((string)($encounter['consent_exception_reason']??''))?></textarea></label>
    <div class="notice <?=$billingPreviewBlocked?'warning':'success'?>"><strong>Expected Cashier handoff:</strong> ₱<?=number_format($billingPreviewTotal,2)?> across <?=count($procedures)?> completed procedure<?=count($procedures)===1?'':'s'?>. <?=$billingPreviewBlocked?'Finalization is blocked until '.$billingPreviewBlocked.' procedure fee source is corrected.':'All procedure fee snapshots are authorized.'?></div>
    <?php if($encounterInvoice):?><div class="notice success"><strong>Cashier invoice prepared automatically:</strong> <?=e((string)$encounterInvoice['invoice_no'])?> · ₱<?=number_format((float)$encounterInvoice['amount'],2)?> · <?=e(module_status((string)$encounterInvoice['status']))?></div><?php endif;?>
  </div>

  <?php if (function_exists('inventory_render_treatment_guard')) inventory_render_treatment_guard($pdo, $encounterId, (int)($encounter['branch_id'] ?? 0)); ?>
  <div class="clinical-resource-section"><div class="section-heading minor"><div><h4>Medicines, materials, equipment, and diagnostic services</h4><p>Record actual use or clinic dispensing. Separately billable entries are handed to Cashier with their clinical source.</p></div><?php if($canWrite):?><button class="btn ghost" type="button" data-add-usage>+ Add used / dispensed item</button><?php endif;?></div><div class="usage-list" data-usage-list>
  <?php foreach($usageItems as $usage):?><article class="usage-row" data-usage-row><div class="usage-row-head"><strong><?=e(module_status((string)$usage['usage_type']))?></strong><?php if($canWrite&&in_array((string)$usage['fulfillment_status'],['draft','requested'],true)):?><button type="button" class="icon-btn" data-remove-usage>×</button><?php endif;?></div><div class="usage-fields"><label>Type<select name="usage_type[]" data-usage-type <?=$canWrite?'':'disabled'?>><?php foreach(['medication_administered'=>'Medication administered','medicine_dispense'=>'Medicine to dispense','consumable'=>'Consumable material','equipment'=>'Equipment / utilization','diagnostic_service'=>'Diagnostic service'] as $value=>$label):?><option value="<?=$value?>" <?=$usage['usage_type']===$value?'selected':''?>><?=$label?></option><?php endforeach;?></select></label><label>Clinic inventory<select name="usage_inventory_item_id[]" data-usage-inventory <?=$canWrite?'':'disabled'?>> <option value="">Not inventory-linked</option><?php foreach($inventoryCatalog as $item):?><option value="<?=(int)$item['id']?>" data-name="<?=e((string)$item['name'])?>" data-unit="<?=e((string)$item['unit'])?>" data-price="<?=e(number_format((float)$item['usage_cost'],2,'.',''))?>" data-stock="<?=e((string)$item['branch_stock'])?>" <?=(int)($usage['inventory_item_id']??0)===(int)$item['id']?'selected':''?>><?=e((string)$item['name'])?> · Stock <?=e((string)$item['branch_stock'])?> <?=e((string)$item['unit'])?></option><?php endforeach;?></select></label><label class="wide">Description<input name="usage_description[]" value="<?=e((string)$usage['description'])?>" data-usage-description <?=$canWrite?'':'readonly'?>></label><label>Quantity<input type="number" min="0.01" step="0.01" name="usage_quantity[]" value="<?=e((string)$usage['quantity'])?>" <?=$canWrite?'':'readonly'?>></label><label>Unit<input name="usage_unit[]" value="<?=e((string)$usage['unit'])?>" data-usage-unit <?=$canWrite?'':'readonly'?>></label><label>Billing<select name="usage_billing_mode[]" data-usage-billing <?=$canWrite?'':'disabled'?>><?php foreach(['included'=>'Included in procedure','bill_separately'=>'Bill separately','track_only'=>'Track only'] as $value=>$label):?><option value="<?=$value?>" <?=$usage['billing_mode']===$value?'selected':''?>><?=$label?></option><?php endforeach;?></select></label><label>Unit price<input type="number" min="0" step="0.01" name="usage_unit_price[]" value="<?=e((string)$usage['unit_price'])?>" data-usage-price <?=$canWrite?'':'readonly'?>></label><label class="wide">Notes<input name="usage_notes[]" value="<?=e((string)$usage['notes'])?>" <?=$canWrite?'':'readonly'?>></label></div></article><?php endforeach;?>
  </div></div>
</section>

<section class="clinical-form-panel" data-clinical-panel="notes" hidden><div class="section-heading"><div><span class="eyebrow">Signed clinical note</span><h3>SOAP note</h3></div></div><label>SOAP clinical note<textarea name="soap_note" rows="12" <?=$canWrite?'':'readonly'?>><?=e((string)$encounter['soap_note'])?></textarea></label></section>

<section class="clinical-form-panel" data-clinical-panel="prescription" hidden>
  <div class="section-heading"><div><span class="eyebrow">Medication order</span><h3>Prescription decision</h3><p>Choose this first. If there is no medicine, mark <strong>No prescription required</strong> and continue.</p></div></div>
  <fieldset class="closeout-choice primary-decision-panel" data-prescription-decision-primary>
    <legend>Prescription decision required before completion</legend>
    <div class="completion-choice-grid">
      <label><input type="radio" name="prescription_decision" value="issued" <?=$prescriptionDecision==='issued'?'checked':''?> <?=$canWrite?'':'disabled'?>> <span><strong>Prescription issued</strong><small>Medication details and the local medication-safety review are complete.</small></span></label>
      <label><input type="radio" name="prescription_decision" value="not_required" <?=$prescriptionDecision==='not_required'?'checked':''?> <?=$canWrite?'':'disabled'?>> <span><strong>No prescription required</strong><small>The Dentist determined that no medication order is needed for this visit.</small></span></label>
    </div>
  </fieldset>
  <?php render_medicine_builder($rxItems,$canWrite,['indication'=>'medication_indication[]','instructions'=>'medication_instructions[]'],'workspace-medicine-builder');?>
  <div class="form-grid compact-form">
    <label class="wide">Overall clinical indication<textarea rows="2" name="prescription_indication" <?=$canWrite?'':'readonly'?>><?=e($prescriptionIndicationValue)?></textarea></label>
    <label class="wide check-label"><input type="checkbox" name="allergy_review_acknowledged" value="1" <?=$prescriptionAllergyAck?'checked':''?> <?=$canWrite?'':'disabled'?>><span>I reviewed allergies, current medicines, bleeding risk, pregnancy/radiography considerations, and alerts relevant to this dental treatment.</span></label>
    <label class="wide">Prescription notes<textarea rows="2" name="prescription_notes" <?=$canWrite?'':'readonly'?>><?=e($prescriptionNotesValue)?></textarea></label>
    <label class="wide">Plain-language summary<textarea rows="3" name="prescription_summary" <?=$canWrite?'':'readonly'?>><?=e($prescriptionSummaryValue)?></textarea></label>
  </div>
  <?php if($canWrite):?><div class="status-actions"><button type="submit" name="action" value="review_prescription_safety" class="btn ghost" formnovalidate>Run dental prescription safety review</button><small class="muted">Supports dental prescribing only. It does not diagnose or treat medical conditions and does not replace an authoritative interaction reference or clinical judgment.</small></div><?php endif;?>
  <?php if($prescriptionSafetyAssessment):
      $safetyCounts=(array)($prescriptionSafetyAssessment['counts']??[]);
      $safetyStatus=(string)($prescriptionSafetyAssessment['status']??$prescriptionSafetyAssessment['safety_status']??$rx['safety_status']??'pending');
      $safetyFindings=(array)($prescriptionSafetyAssessment['findings']??[]);
      $safetyAlertClass=$safetyStatus==='blocked'?'danger':($safetyStatus==='clear'?'success':'warning');
  ?>
  <section class="alert <?=$safetyAlertClass?>" aria-live="polite">
    <strong><?=e(clinical_safety_status_label($safetyStatus))?></strong>
    <span>Hard stops: <?=(int)($safetyCounts['hard_stop']??0)?> · Serious warnings: <?=(int)($safetyCounts['serious_warning']??0)?> · Data gaps: <?=(int)($safetyCounts['data_gap']??0)?> · Advisories: <?=(int)($safetyCounts['advisory']??0)?></span>
    <?php if($safetyStatus==='clear'):?><p>No finding was produced by the installed local rules. This is not a declaration that the medicines are universally safe or interaction-free.</p><?php endif;?>
  </section>
  <?php if($safetyFindings):?><div class="timeline-list clinical-safety-findings">
    <?php foreach($safetyFindings as $finding):$severity=(string)($finding['severity']??'advisory');?><article class="card">
      <div class="card-head"><strong><?=e((string)($finding['title']??'Dental prescription safety finding'))?></strong><span class="badge"><?=e(module_status($severity))?></span></div>
      <?php if(!empty($finding['medicine_name'])):?><small><?=e((string)$finding['medicine_name'])?></small><?php endif;?>
      <p><?=e((string)($finding['detail']??''))?></p>
    </article><?php endforeach;?>
  </div><?php endif;?>
  <?php endif;?>
  <div class="form-grid compact-form">
    <label class="wide check-label"><input type="checkbox" name="prescription_safety_acknowledged" value="1" <?=$prescriptionSafetyAck?'checked':''?> <?=$canWrite?'':'disabled'?>><span>I reviewed the displayed medication-safety findings and any limitations or missing interaction data.</span></label>
    <label class="wide">Clinical justification for serious warning override<textarea rows="3" name="prescription_safety_override_reason" minlength="20" <?=$canWrite?'':'readonly'?> placeholder="Required only when a serious warning is acknowledged and prescribing will continue."><?=e($prescriptionSafetyOverrideValue)?></textarea></label>
  </div>
</section>

<section class="clinical-form-panel" data-clinical-panel="followup" hidden><div class="section-heading"><div><span class="eyebrow">Dentist decides; staff books</span><h3>Follow-up disposition</h3><p>Choose whether clinical follow-up is required. Receptionist or Cashier books the actual available schedule after finalization.</p></div></div><?php $savedFollowDecision=($encounter['disposition']??'')==='no_follow_up'?'none':($followReady?'recommended':'');?><div class="followup-decision-grid" role="radiogroup" aria-label="Follow-up decision"><label class="followup-decision-card"><input type="radio" name="follow_up_decision" value="recommended" data-follow-up-decision <?=$savedFollowDecision==='recommended'?'checked':''?> <?=$canWrite?'':'disabled'?>> <span><strong>Follow-up recommended</strong><small>Record the clinical purpose and recommended date. Staff will select the actual appointment slot.</small></span></label><label class="followup-decision-card"><input type="radio" name="follow_up_decision" value="none" data-follow-up-decision <?=$savedFollowDecision==='none'?'checked':''?> <?=$canWrite?'':'disabled'?>> <span><strong>No follow-up required</strong><small>Use only when the Dentist has determined that no return visit is clinically required.</small></span></label></div><div class="form-grid compact-form" data-follow-up-fields><label>Clinical purpose <span class="required-mark">Required when recommended</span><input name="follow_up_purpose" data-required-first value="<?=e((string)($followup['purpose']??$encounter['follow_up_purpose']))?>" <?=$canWrite?'':'readonly'?>></label><label>Recommended date <span class="required-mark">Required when recommended</span><input type="date" name="follow_up_date" data-required-first value="<?=e((string)($followup['recommended_date']??$encounter['follow_up_date']))?>" <?=$canWrite?'':'readonly'?>></label><label>Preferred time<input type="time" name="follow_up_time" value="<?=e(isset($followup['preferred_time'])?substr((string)$followup['preferred_time'],0,5):'')?>" <?=$canWrite?'':'readonly'?>></label><label>Urgency<select name="follow_up_urgency" <?=$canWrite?'':'disabled'?>><?php foreach(['routine','important','urgent'] as $value):?><option value="<?=$value?>" <?=($followup['urgency']??$encounter['follow_up_urgency']??'routine')===$value?'selected':''?>><?=e(ucfirst($value))?></option><?php endforeach;?></select></label><label>Suggested service<select name="follow_up_service_id" <?=$canWrite?'':'disabled'?>> <option value="">Choose during scheduling</option><?php foreach($services as $service):?><option value="<?=(int)$service['id']?>" <?=(int)($followup['service_id']??0)===(int)$service['id']?'selected':''?>><?=e((string)$service['name'])?></option><?php endforeach;?></select></label><label>Duration minutes<input type="number" min="15" step="5" name="follow_up_duration" value="<?=e((string)($followup['duration_minutes']??30))?>" <?=$canWrite?'':'readonly'?>></label><label class="wide">Instructions<textarea rows="3" name="follow_up_instructions" <?=$canWrite?'':'readonly'?>><?=e((string)($followup['instructions']??''))?></textarea></label></div></section>


<section class="clinical-form-panel completion-outcome-panel" data-clinical-panel="completion" hidden>
  <div class="section-heading"><div><span class="eyebrow">Guided closeout</span><h3>Verify, complete, and release the patient</h3><p>Confirm each clinical handoff before signing. The chair is released immediately after either completion outcome.</p></div><?php if($encounter['status']==='finalized'):?><a class="btn ghost" target="_blank" href="print_record.php?type=encounter&amp;id=<?=$encounterId?>">Print discharge summary</a><?php endif;?></div>
  <?php if($pendingAssistantEntryCount>0):?><div class="alert warning"><strong>Completion blocked:</strong> <?=$pendingAssistantEntryCount?> Dental Assistant treatment <?=$pendingAssistantEntryCount===1?'entry requires':'entries require'?> Dentist verification.</div><?php endif;?>
  <div class="closeout-confirmation-grid">
    <label class="check-label"><input type="checkbox" name="vitals_review_acknowledged" value="1" data-shared-clinical-check="vitals_review_acknowledged" <?=!empty($completionState['vitals_review'])?'checked':''?> <?=$canWrite?'':'disabled'?>><span><strong><?=$vitalsRequired?'Indicated first-seating measurements reviewed':'First-seating measurement decision reviewed'?></strong><small><?=$vitalsRequired?'The indicated measurements were considered before dental treatment completion.':'Confirm the documented no-additional-measurement decision for this dental visit.'?></small></span></label>
    <?php if($hasMedicalAlerts):?><label class="check-label"><input type="checkbox" name="medical_alert_review_acknowledged" value="1" <?=!empty($completionState['medical_alert_review'])?'checked':''?> <?=$canWrite?'':'disabled'?>><span><strong>Dental safety alerts acknowledged</strong><small>Active allergies, medicines, conditions, and clinical warnings were reviewed.</small></span></label><?php else:?><div class="closeout-auto-complete"><strong>Dental safety alerts</strong><small>No active alert recorded.</small></div><?php endif;?>
    <label class="check-label"><input type="checkbox" name="chart_review_acknowledged" value="1" data-shared-clinical-check="chart_review_acknowledged" <?=!empty($completionState['chart_review'])?'checked':''?> <?=$canWrite?'':'disabled'?>><span><strong>Dental chart reviewed</strong><small>The previous chart was reviewed. Choose no changes, updated findings, continued planned treatment, completed treatment, or not applicable.</small></span></label>
    <label class="check-label"><input type="checkbox" name="instructions_review_acknowledged" value="1" <?=!empty($completionState['instructions_review'])?'checked':''?> <?=$canWrite?'':'disabled'?>><span><strong>Patient instructions completed</strong><small>Advice, precautions, home care, and return instructions were explained as applicable.</small></span></label>
    <label class="check-label"><input type="checkbox" name="billing_review_acknowledged" value="1" <?=!empty($completionState['billing_review'])?'checked':''?> <?=$canWrite?'':'disabled'?>><span><strong>Billing handoff verified</strong><small>Every performed procedure and separately billable clinical item has the correct approved source and amount.</small></span></label>
  </div>
  <div class="prescription-decision-summary <?=$prescriptionCloseReady?'ready':'missing'?>"><strong>Prescription decision</strong><small><?=$prescriptionCloseReady?($prescriptionDecision==='issued'?'Prescription issued and medicine details recorded':'No prescription required'):'Incomplete — open the Prescription step or press Alt+N.'?></small></div>
  <div class="billing-verification-card"><span>Verified clinical handoff</span><strong>₱<?=number_format($billingPreviewTotal,2)?></strong><small><?=$billingPreviewBlocked?'Blocked: correct '.$billingPreviewBlocked.' procedure fee source before completion.':($zeroChargeWithoutProcedure?'No performed procedure has been recorded. Use the authorized no-payment checkout unless a billable procedure should be added first.':'Includes approved procedures and separately billable clinical usage.')?></small></div>
  <?php if($zeroChargeWithoutProcedure):?><div class="notice warning"><strong>Zero-balance checkout:</strong> no performed procedure or separately billable item is recorded. DentalCare selected the controlled no-payment checkout so the visit can close without creating an empty Cashier handoff.</div><?php endif;?>
  <?php if($canWrite):?><fieldset class="closeout-choice"><legend>Completion destination</legend><div class="completion-choice-grid">
    <label><input type="radio" name="completion_destination" value="cashier" data-completion-destination <?=$zeroChargeWithoutProcedure?'':'checked'?>> <span><strong>Complete and send to Cashier</strong><small>Finalize, sign, release the chair, and open the verified payment handoff.</small></span></label>
    <label><input type="radio" name="completion_destination" value="no_payment" data-completion-destination <?=$zeroChargeWithoutProcedure?'checked':''?>> <span><strong>Complete—no payment required</strong><small>Allowed only when all clinical charges are authorized no-charge or the visit has no billable items.</small></span></label>
  </div></fieldset>
  <label class="wide no-payment-reason" data-no-payment-reason <?=$zeroChargeWithoutProcedure?'':'hidden'?>>Authorized no-payment reason<textarea name="no_payment_reason" minlength="10" placeholder="Example: Post-operative review included in the original procedure; no additional fee is authorized."><?=$zeroChargeWithoutProcedure?'No billable procedure or separately billable clinical item was performed during this visit.':''?></textarea></label>
  <?php else:?><div class="notice success"><strong><?=e(($encounter['completion_destination']??'cashier')==='no_payment'?'Authorized no-payment discharge':'Cashier handoff')?></strong><br><?=e(($encounter['completion_destination']??'cashier')==='no_payment'?(string)($encounter['no_payment_reason']??''):'Verified handoff ₱'.number_format((float)($encounter['billing_handoff_amount']??0),2))?></div><?php endif;?>
</section>

<?php if($canWrite&&$isAssistant):?><div class="clinical-mobile-actions assistant-mobile-actions"><button class="btn primary" name="action" value="save_draft" data-save-draft>Save assistant entries</button><small>Diagnosis, signature, billing release, and discharge remain with the Dentist.</small></div><?php elseif($canWrite):?><div class="clinical-mobile-actions"><button class="btn ghost" name="action" value="save_draft" data-save-draft>Save draft</button><button class="btn primary" name="action" value="finalize_encounter" data-finalize-treatment data-confirm="Finalize and sign this clinical record?"<?=$dentistCompletionDisabledAttr?>><?=e($dentistCompletionButtonLabel)?></button></div><?php endif;?>
</form>
</section>
</main>

<?php if($isAssistant): ?>
<aside class="clinical-completion-panel card assistant-handoff-panel">
  <div class="card-head"><div><span class="eyebrow">Assistant handoff</span><h3>Ready for Dentist review</h3></div><span class="badge <?= $pendingAssistantEntryCount>0?'warning':'success' ?>"><?=$pendingAssistantEntryCount?> draft entr<?= $pendingAssistantEntryCount===1?'y':'ies' ?></span></div>
  <ol class="completion-list assistant-completion-list">
    <li class="<?=$intakeReady?'complete':'missing'?>"><span><?=$intakeReady?'✓':'!'?></span><div><strong>First-seating safety summary</strong><small><?=$intakeReady?'Completed safety information is available':'Return to first seating and complete the dental safety assessment'?></small></div></li>
    <li class="<?=($vitals||!$vitalsRequired)?'complete':'missing'?>"><span><?=($vitals||!$vitalsRequired)?'✓':'!'?></span><div><strong>Indicated chairside measurement</strong><small><?=$vitals?'First-seating measurements are available':(!$vitalsRequired?'No measurement is required for this dental visit':'Return to first seating and record the indicated measurement')?></small></div></li>
    <li class="<?=($chartReviewMode||$assistantImageCount>0)?'complete':'missing'?>"><span><?=($chartReviewMode||$assistantImageCount>0)?'✓':'!'?></span><div><strong>Chart and images</strong><small>Update the tooth chart or upload chairside images when delegated.</small></div></li>
    <li class="complete"><span>✓</span><div><strong>Professional boundary</strong><small>Diagnosis, prescription, SOAP signature, billing release, and discharge remain with <?=e((string)$encounter['dentist_name'])?>.</small></div></li>
  </ol>
  <a class="btn primary wide" href="dashboard.php">Return to Chairside Tasks</a>
  <small class="muted">Saved entries stay attributed to your account and remain pending until the responsible Dentist verifies them.</small>
</aside>
<?php else: ?>
<aside class="clinical-completion-panel card" data-clinical-checklist>
  <div class="card-head"><div><span class="eyebrow">Treatment completion</span><h3>Patient release checklist</h3></div><span class="badge" data-completion-count>0 / 12</span></div>
  <ol class="completion-list">
    <li class="<?=($intakeReady&&$vitalsReviewReady)?'complete':'missing'?>" data-check-item="intake"><span><?=($intakeReady&&$vitalsReviewReady)?'✓':'!'?></span><div><strong>First-seating safety and visit review</strong><small><?=!$intakeReady?($hpiRequired?'Confirm the first-seating summary, chief complaint, HPI, and visit acknowledgements':'Confirm the first-seating summary, chief complaint, and visit acknowledgements'):(!$vitalsReviewReady?($vitalsRequired?'Review the indicated first-seating measurements':'Confirm that no additional measurement is required'):($vitalsSkipped?'No additional measurement required':'Reviewed and ready'))?></small></div></li>
    <li class="<?=$medicalAlertReady?'complete':'missing'?>" data-check-item="alerts"><span><?=$medicalAlertReady?'✓':'!'?></span><div><strong>Dental safety alerts</strong><small><?=$medicalAlertReady?($hasMedicalAlerts?'Alerts acknowledged':'No active alert recorded'):'Acknowledge active dental safety alerts'?></small></div></li>
    <li class="<?=$assessmentReady?'complete':'missing'?>" data-check-item="assessment"><span><?=$assessmentReady?'✓':'!'?></span><div><strong><?=$assessmentRequired?'Examination':'Focused tooth assessment'?></strong><small><?=$assessmentReady?($assessmentRequired?'Domain status and summary recorded':'Full general examination skipped by the selected care path; continue with tooth-specific charting'): 'Complete examination findings and summary'?></small></div></li>
    <li class="<?=$chartReviewReady?'complete':'missing'?>" data-check-item="charting"><span><?=$chartReviewReady?'✓':'!'?></span><div><strong>Dental chart</strong><small><?=$chartReviewReady?'Reviewed and updated as needed':'Review the odontogram and acknowledge it'?></small></div></li>
    <li class="<?=$diagnosisReady?'complete':'missing'?>" data-check-item="diagnosis"><span><?=$diagnosisReady?'✓':'!'?></span><div><strong>Diagnosis</strong><small><?=$diagnosisReady?'Diagnosis recorded':'Add at least one diagnosis'?></small></div></li>
    <li class="<?=($dispositionReady&&$procedureReady)?'complete':'missing'?>" data-check-item="disposition"><span><?=($dispositionReady&&$procedureReady)?'✓':'!'?></span><div><strong>Treatment and procedures</strong><small><?=!$dispositionReady?'Select the clinical outcome':(!$procedureReady?'Add the performed procedure':'Outcome and procedures recorded')?></small></div></li>
    <li class="<?=$consentReady?'complete':'missing'?>" data-check-item="consent"><span><?=$consentReady?'✓':'!'?></span><div><strong>Treatment consent</strong><small data-consent-check-copy><?=$consentReady?'Not required or validly linked':'Obtain and link consent before finalizing'?></small></div></li>
    <li class="<?=$prescriptionCloseReady?'complete':'missing'?>" data-check-item="prescription"><span><?=$prescriptionCloseReady?'✓':'!'?></span><div><strong>Prescription decision</strong><small><?=$prescriptionCloseReady?($prescriptionDecision==='issued'?'Prescription completed':'Marked not required'):'Issue the prescription or mark it not required'?></small></div></li>
    <li class="<?=$soapReady?'complete':'missing'?>" data-check-item="soap"><span><?=$soapReady?'✓':'!'?></span><div><strong>SOAP note</strong><small><?=$soapReady?'Clinical narrative complete':'Complete the signed clinical narrative'?></small></div></li>
    <li class="<?=$instructionsReviewReady?'complete':'missing'?>" data-check-item="instructions"><span><?=$instructionsReviewReady?'✓':'!'?></span><div><strong>Patient instructions</strong><small><?=$instructionsReviewReady?'Advice and discharge instructions confirmed':'Complete and acknowledge patient instructions'?></small></div></li>
    <li class="<?=$followReady?'complete':'missing'?>" data-check-item="followup"><span><?=$followReady?'✓':'!'?></span><div><strong>Follow-up decision</strong><small><?=$followReady?'Follow-up disposition recorded':'Recommend follow-up or mark none required'?></small></div></li>
    <li class="<?=$billingReviewReady&&$billingPreviewBlocked===0?'complete':'missing'?>" data-check-item="billing"><span><?=$billingReviewReady&&$billingPreviewBlocked===0?'✓':'!'?></span><div><strong>Billing handoff</strong><small><?=$billingPreviewBlocked?'Correct blocked fee sources':($billingReviewReady?'Verified ₱'.number_format($billingPreviewTotal,2).' handoff':'Review and acknowledge the billing handoff')?></small></div></li>
  </ol>
  <div class="completion-blockers" data-completion-blockers></div>
  <?php if($canWrite):?><button class="btn secondary wide" type="button" data-next-clinical-required>Go to next missing item <kbd>Alt+N</kbd></button><button class="btn ghost wide" type="button" data-checklist-save>Save draft</button><button class="btn primary wide" type="button" data-checklist-finalize<?=$dentistCompletionDisabledAttr?>><?=e($dentistCompletionButtonLabel)?></button><button class="btn ghost wide" type="button" data-open="pause-treatment-form">Pause instead</button><?php else:?><a class="btn primary wide" target="_blank" href="print_record.php?type=encounter&amp;id=<?=$encounterId?>">Print discharge summary</a><?php endif;?>
  <small class="muted">Completion signs the record, releases the chair, and routes the patient to Cashier or authorized no-payment discharge.</small>
</aside>
<?php endif; ?>
</div>

<template id="diagnosis-row-template"><article class="diagnosis-row" data-diagnosis-row><input type="hidden" name="diagnosis_id[]" value="0"><div class="diagnosis-row-head"><strong data-diagnosis-label>Additional diagnosis</strong><button type="button" class="icon-btn" data-remove-diagnosis>×</button></div><div class="diagnosis-fields"><label>Tooth / region<input name="diagnosis_region[]" placeholder="FDI tooth, arch, quadrant, or soft tissue" data-diagnosis-region></label><label class="diagnosis-search-label">Search or enter diagnosis<input type="search" name="diagnosis_name[]" autocomplete="off" data-diagnosis-search><div class="lookup-results" data-diagnosis-results hidden></div></label><label>Code<input name="diagnosis_code[]" data-diagnosis-code></label><label>Severity<select name="diagnosis_severity[]"><option value="">Not set</option><option value="mild">Mild</option><option value="moderate">Moderate</option><option value="severe">Severe</option><option value="critical">Critical</option></select></label><label>Status<select name="diagnosis_status[]" data-diagnosis-status><option value="provisional">Provisional</option><option value="confirmed">Confirmed</option><option value="resolved">Resolved</option><option value="chronic">Chronic</option><option value="under_observation">Under observation</option><option value="referred">Referred</option></select></label><fieldset class="wide diagnosis-surface-control" data-diagnosis-surface-control hidden><legend data-diagnosis-surface-title>Affected tooth surface</legend><input type="hidden" name="diagnosis_surfaces[]" value="" data-diagnosis-surfaces><div class="diagnosis-surface-options"><label data-diagnosis-surface-option data-surface-scope="all"><input type="checkbox" value="M"><span><strong>M</strong>Mesial</span></label><label data-diagnosis-surface-option data-surface-scope="all"><input type="checkbox" value="D"><span><strong>D</strong>Distal</span></label><label data-diagnosis-surface-option data-surface-scope="anterior"><input type="checkbox" value="F"><span><strong>F</strong>Facial</span></label><label data-diagnosis-surface-option data-surface-scope="all"><input type="checkbox" value="L"><span><strong>L</strong>Lingual</span></label><label data-diagnosis-surface-option data-surface-scope="posterior"><input type="checkbox" value="B"><span><strong>B</strong>Buccal</span></label></div><small data-diagnosis-surface-help>For precise caries charting, choose the affected surface; otherwise Whole tooth is used.</small></fieldset><label class="wide">Notes<textarea rows="2" name="diagnosis_notes[]"></textarea></label></div></article></template>
<template id="usage-row-template"><article class="usage-row" data-usage-row><div class="usage-row-head"><strong>New clinical usage</strong><button type="button" class="icon-btn" data-remove-usage>×</button></div><div class="usage-fields"><label>Type<select name="usage_type[]" data-usage-type><option value="medication_administered">Medication administered</option><option value="medicine_dispense">Medicine to dispense</option><option value="consumable">Consumable material</option><option value="equipment">Equipment / utilization</option><option value="diagnostic_service">Diagnostic service</option></select></label><label>Clinic inventory<select name="usage_inventory_item_id[]" data-usage-inventory><option value="">Not inventory-linked</option><?php foreach($inventoryCatalog as $item):?><option value="<?=(int)$item['id']?>" data-name="<?=e((string)$item['name'])?>" data-unit="<?=e((string)$item['unit'])?>" data-price="<?=e(number_format((float)$item['usage_cost'],2,'.',''))?>" data-stock="<?=e((string)$item['branch_stock'])?>"><?=e((string)$item['name'])?> · Stock <?=e((string)$item['branch_stock'])?> <?=e((string)$item['unit'])?></option><?php endforeach;?></select></label><label class="wide">Description<input name="usage_description[]" data-usage-description></label><label>Quantity<input type="number" min="0.01" step="0.01" name="usage_quantity[]" value="1"></label><label>Unit<input name="usage_unit[]" data-usage-unit></label><label>Billing<select name="usage_billing_mode[]" data-usage-billing><option value="included">Included in procedure</option><option value="bill_separately">Bill separately</option><option value="track_only">Track only</option></select></label><label>Unit price<input type="number" min="0" step="0.01" name="usage_unit_price[]" value="0" data-usage-price></label><label class="wide">Notes<input name="usage_notes[]"></label></div></article></template>
<?php if($canWrite&&workflow_governance_schema_ready()):?>
<dialog id="pause-treatment-form" class="wide-dialog"><form method="post" class="form-grid"><button type="button" class="dialog-close" data-close>×</button><h2 class="wide">Pause active treatment</h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="pause_treatment"><input type="hidden" name="encounter_id" value="<?=$encounterId?>"><label class="wide">Pause reason<textarea name="pause_reason" minlength="10" required placeholder="Patient needs a break, equipment unavailable, consultation required, or treatment interrupted"></textarea></label><label class="wide check-label"><input type="checkbox" name="release_chair" value="1" checked><span>Return patient to waiting and release the chair for another patient</span></label><button class="btn primary wide">Pause treatment</button></form></dialog>
<dialog id="dentist-handoff-form" class="wide-dialog"><form method="post" class="form-grid"><button type="button" class="dialog-close" data-close>×</button><h2 class="wide">Request another Dentist</h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="request_encounter_transfer"><input type="hidden" name="encounter_id" value="<?=$encounterId?>"><label>Request type<select name="request_type"><option value="consultation">Consultation only — responsibility stays with me</option><option value="transfer">Transfer full clinical responsibility after acceptance</option></select></label><label>Receiving Dentist<select name="to_dentist_user_id" required><option value="">Choose qualified receiving Dentist</option><?php foreach($qualifiedConsultants as $doctor):?><option value="<?=(int)$doctor['id']?>"><?=e((string)($doctor['display_name']??$doctor['name']))?></option><?php endforeach;?></select></label><label class="wide">Reason<textarea name="transfer_reason" minlength="10" required placeholder="Required specialty, clinical concern, coverage, or emergency support"></textarea></label><div class="alert info wide">Consultation permits a separately signed consulting note. A transfer changes responsibility only after the receiving Dentist accepts.</div><button class="btn primary wide">Send Dentist request</button></form></dialog>
<?php endif;?>
<?php if($emergencyAccess):?><dialog id="emergency-takeover-form" class="wide-dialog"><form method="post" class="form-grid"><button type="button" class="dialog-close" data-close>×</button><h2 class="wide">Emergency clinical takeover</h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="emergency_takeover"><input type="hidden" name="encounter_id" value="<?=$encounterId?>"><div class="alert danger wide"><strong>This immediately transfers responsibility to your account.</strong> The previous Dentist’s entries remain attributed to them. All new documentation and signatures use your own license.</div><label class="wide">Emergency reason<textarea name="takeover_reason" minlength="15" required></textarea></label><button class="btn danger wide" data-confirm="Take over this active encounter under your own professional identity?">Confirm emergency takeover</button></form></dialog><?php endif;?>
<?php if($canWrite):?><dialog id="assistant-assignment-form" class="wide-dialog"><form method="post" class="form-grid"><button type="button" class="dialog-close" data-close>×</button><h2 class="wide">Assign Dental Assistant</h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="assign_assistant"><input type="hidden" name="encounter_id" value="<?=$encounterId?>"><div class="notice wide"><strong>Encounter-specific access.</strong> The selected assistant will see this Dentist, patient, chair, and active treatment and may record delegated treatment entries. Diagnosis, prescription, finalization, and discharge remain Dentist-only.</div><label class="wide">Dental Assistant<select name="assistant_user_id"><option value="">No assistant / remove assignment</option><?php foreach($assistantOptions as $assistantOption):?><option value="<?=(int)$assistantOption['id']?>" <?=(int)($encounter['assistant_user_id']??0)===(int)$assistantOption['id']?'selected':''?>><?=e((string)$assistantOption['name'])?></option><?php endforeach;?></select></label><button class="btn primary wide" type="submit">Save assistant assignment</button></form></dialog><?php endif;?>
<?php if($canWrite):foreach($procedures as $row):if((string)($row['entered_by_role']??'')!=='dental_assistant'||!empty($row['verified_by_user_id'])||(string)$row['status']==='cancelled')continue;?><form id="verify-procedure-<?=(int)$row['id']?>" method="post" hidden><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="verify_procedure"><input type="hidden" name="encounter_id" value="<?=$encounterId?>"><input type="hidden" name="procedure_id" value="<?=(int)$row['id']?>"></form><?php endforeach;endif;?>
<?php if($canTreatmentEntry):?>
<dialog id="procedure-add-form" class="wide-dialog"><form method="post" class="form-grid"><button type="button" class="dialog-close" data-close>×</button><h2 class="wide"><?=$isAssistant?'Add delegated treatment entry':'Add performed procedure'?></h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="add_procedure"><input type="hidden" name="encounter_id" value="<?=$encounterId?>"><div class="notice wide"><strong><?=$isAssistant?'Document what was performed for Dentist review.':'Choose one approved source.'?></strong> Select an accepted treatment-plan item when available. Otherwise select an active service from the catalogue. The approved amount is copied automatically and cannot be edited by Cashier.</div><label class="wide">Accepted treatment-plan item<select name="treatment_plan_item_id"><option value="">Not linked to a treatment plan</option><?php foreach($treatmentItems as $item):$eligible=in_array((string)$item['status'],['accepted','scheduled','in_progress'],true)&&!empty($item['dentist_can_work'])&&in_array((string)($item['fee_status']??'unconfigured'),['billable','no_charge'],true);?><option value="<?=(int)$item['id']?>" <?=$eligible?'':'disabled'?>><?=e((string)$item['plan_title'])?> · <?=e((string)$item['procedure_name'])?><?=!empty($item['tooth_region'])?' · '.e((string)$item['tooth_region']):''?> · <?=($item['fee_status']??'')==='no_charge'?'Authorized no-charge':'₱'.number_format((float)$item['estimated_fee'],2)?> · Consent <?=!empty($item['valid_consent_id'])?'signed':'required'?></option><?php endforeach;?></select></label><label class="wide">Or approved service<select name="service_id"><option value="">Select service when this is not a treatment-plan item</option><?php foreach($billingServices as $service):?><option value="<?=(int)$service['id']?>"><?=e((string)$service['name'])?> · <?=($service['fee_status']==='no_charge'?'Authorized no-charge':'₱'.number_format((float)$service['standard_fee'],2))?></option><?php endforeach;?></select></label><label>Tooth / region<input name="procedure_tooth_region" placeholder="FDI tooth, surface, arch, or region"></label><label>Anesthetic<textarea rows="2" name="anesthetic"></textarea></label><label>Materials used<textarea rows="2" name="materials"></textarea></label><label>Complications<textarea rows="2" name="complications"></textarea></label><label class="wide">Outcome / procedure note<textarea rows="3" name="procedure_outcome"></textarea></label><button class="btn primary wide" type="submit"><?=$isAssistant?'Save entry for Dentist verification':'Add procedure with approved fee'?></button></form></dialog>
<?php foreach($procedures as $row):if((string)$row['status']==='completed')continue;?><form id="remove-procedure-<?=(int)$row['id']?>" method="post" hidden><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="remove_procedure"><input type="hidden" name="encounter_id" value="<?=$encounterId?>"><input type="hidden" name="procedure_id" value="<?=(int)$row['id']?>"></form><?php endforeach;?>
<?php foreach($procedures as $row):if((string)$row['status']==='completed')continue;?><dialog id="procedure-outcome-<?=(int)$row['id']?>" class="wide-dialog"><form method="post" class="form-grid"><button type="button" class="dialog-close" data-close>×</button><h2 class="wide">Defer, move, cancel, or mark not performed</h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="mark_procedure_outcome"><input type="hidden" name="encounter_id" value="<?=$encounterId?>"><input type="hidden" name="procedure_id" value="<?=(int)$row['id']?>"><div class="notice wide"><strong><?=e((string)$row['procedure_name'])?></strong> will remain in the clinical record but will not be sent to Cashier today unless it is later recorded as performed in a new/follow-up visit.</div><label>Status<select name="procedure_status" required><option value="deferred">Deferred to a later visit</option><option value="moved_follow_up">Moved to follow-up appointment</option><option value="not_performed">Not performed today</option><option value="cancelled">Cancelled</option></select></label><label class="wide">Reason / patient discussion note<textarea name="procedure_disposition_reason" minlength="10" required placeholder="Example: Patient agreed to defer extraction because swelling needs medication first."></textarea></label><label class="wide checkbox-line"><input type="checkbox" name="patient_agreement_recorded" value="1"> Patient or guardian agreement was recorded for this change.</label><button class="btn primary wide" type="submit">Save non-billable outcome</button></form></dialog><?php endforeach;?>
<?php endif;?>
<?php if($canCorrectBilling):foreach($procedures as $row):if(clinical_billing_procedure_fee_status($row)!=='unconfigured')continue;?>
<dialog id="procedure-correction-<?=(int)$row['id']?>" class="wide-dialog"><form method="post" class="form-grid"><button type="button" class="dialog-close" data-close>×</button><h2 class="wide">Correct legacy procedure billing source</h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="correct_procedure_billing"><input type="hidden" name="encounter_id" value="<?=$encounterId?>"><input type="hidden" name="procedure_id" value="<?=(int)$row['id']?>"><div class="alert warning wide"><strong>Current legacy entry:</strong> <?=e((string)$row['procedure_name'])?>. Select the actual approved service. The correction is audited and a signed addendum is appended; the original finalized snapshot is not silently replaced.</div><label class="wide">Approved service<select name="service_id" required><option value="">Select actual procedure</option><?php foreach($billingServices as $service):?><option value="<?=(int)$service['id']?>"><?=e((string)$service['name'])?> · <?=($service['fee_status']==='no_charge'?'Authorized no-charge':'₱'.number_format((float)$service['standard_fee'],2))?></option><?php endforeach;?></select></label><label class="wide">Correction reason<textarea name="correction_reason" minlength="15" required placeholder="Explain why the original procedure was not linked to the correct service"></textarea></label><button class="btn primary wide" type="submit">Apply audited billing correction</button></form></dialog>
<?php endforeach;endif;?>
<?php if(isset($_GET['assign_assistant'])&&$canWrite):?><span hidden data-auto-open-dialog="assistant-assignment-form"></span><?php endif;?><?php if($openXray):?><span hidden data-auto-open-dialog="chairside-xray-form"></span><?php endif;?>
<?php if($canScreen&&$encounter['status']!=='finalized'):?><dialog id="chairside-xray-form" class="wide-dialog"><form method="post" enctype="multipart/form-data" class="form-grid" data-keyboard-entry><button type="button" class="dialog-close" data-close>×</button><h2 class="wide">Capture or upload X-ray</h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="upload_xray"><input type="hidden" name="encounter_id" value="<?=$encounterId?>"><label>Imaging type<select name="category"><?php foreach(clinical_imaging_categories() as $category):?><option><?=e($category)?></option><?php endforeach;?></select></label><label>Tooth or region<select name="tooth_region" data-xray-tooth-input><option value="">General / full arch</option><?php foreach($chartTeeth as $tooth):?><option value="<?=e($tooth)?>"><?=e(dental_tooth_display_label($tooth))?></option><?php endforeach;?></select></label><label class="wide">Captured X-ray or exported file<input type="file" name="document" accept="image/jpeg,image/png,image/webp,application/pdf,.jpg,.jpeg,.png,.webp,.pdf" capture="environment" required><small>Use the device camera when supported or choose an exported JPG, PNG, WebP, or PDF up to 10 MB.</small></label><label class="wide">Clinical note<textarea name="description" placeholder="Projection, reason captured, image quality, radiographic observations, or retake note"></textarea></label><button class="btn primary wide">Upload and link to this encounter</button></form></dialog><?php endif;?>
<div class="grid-2"><section class="card"><h2>Health information relevant to dental care</h2><?php foreach($medicalHistory as $row):?><article class="history-entry"><strong><?=e(date('M j, Y',strtotime((string)$row['created_at'])))?></strong><p><b>Allergies:</b> <?=e(function_exists('dentalcare_medical_display') ? dentalcare_medical_display($row['allergies'] ?? '', 'No allergy recorded') : (string)($row['allergies']?:'No changes recorded'))?><br><b>Medications:</b> <?=e(function_exists('dentalcare_medical_display') ? dentalcare_medical_display($row['medications'] ?? '', 'No medication recorded') : (string)($row['medications']?:'No changes recorded'))?><br><b>Conditions:</b> <?=e(function_exists('dentalcare_medical_display') ? dentalcare_medical_display($row['conditions'] ?? '', 'No condition recorded') : (string)($row['conditions']?:'No changes recorded'))?></p></article><?php endforeach;?><?php if(!$medicalHistory):?><p class="muted">No dental-safety history versions found.</p><?php endif;?></section><section class="card"><h2>Previous clinical visits</h2><?php foreach($previous as $row):?><article class="history-entry"><strong><?=e(date('M j, Y',strtotime((string)$row['created_at'])))?> · <?=e((string)$row['dentist_name'])?></strong><p><?=e((string)($row['diagnosis']?:'No diagnosis summary'))?> · <?=e((string)($row['procedure_done']?:'No procedure summary'))?></p><a href="clinical_workspace.php?encounter_id=<?=(int)$row['id']?>">Open record</a></article><?php endforeach;?><?php if(!$previous):?><p class="muted">This is the first clinical visit recorded in DentalCare.</p><?php endif;?></section></div>
<script src="public/assets/js/dental-chart.js?v=<?=e(app_release_version())?>"></script><script src="public/assets/js/medicine-builder.js?v=<?=e(app_release_version())?>"></script><script src="public/assets/js/clinical-workspace.js?v=<?=e(app_release_version())?>"></script><?php render_footer(); ?>
