<?php

declare(strict_types=1);

/**
 * DentalCare v0.9.0.5 controlled administrative break-glass access.
 *
 * Break-glass access is deliberately temporary, MFA re-authenticated, scoped,
 * independently reviewable, and incapable of granting clinical authorship or
 * bypassing financial/sterilization segregation of duties.
 */

function dental_break_glass_sessions_table(): string
{
    return table('administrative_break_glass_sessions');
}

function dental_break_glass_events_table(): string
{
    return table('administrative_break_glass_events');
}

function dental_break_glass_notifications_table(): string
{
    return table('administrative_break_glass_notifications');
}

function dental_break_glass_schema_ready(): bool
{
    try {
        $sessions = dental_break_glass_sessions_table();
        $events = dental_break_glass_events_table();
        $notifications = dental_break_glass_notifications_table();
        if (!schema_table_exists($sessions) || !schema_table_exists($events) || !schema_table_exists($notifications)) return false;
        foreach (['user_id','branch_id','status','reason_code','reason_text','scope_permissions_json','token_hash','started_at','expires_at','review_due_at','reviewer_user_id','reviewed_at'] as $column) {
            if (!schema_column_exists($sessions, $column)) return false;
        }
        foreach (['session_id','event_type','permission_code','route_key','created_at'] as $column) {
            if (!schema_column_exists($events, $column)) return false;
        }
        foreach (['session_id','reviewer_user_id','status','created_at'] as $column) {
            if (!schema_column_exists($notifications, $column)) return false;
        }
        return true;
    } catch (Throwable) {
        return false;
    }
}

function dental_break_glass_actor_allowed(): bool
{
    return signed_identity_has_role(['super_admin','clinic_admin']) && has_role(['super_admin','clinic_admin']);
}

function dental_break_glass_reason_catalog(): array
{
    return [
        'patient_safety_emergency' => 'Patient safety emergency',
        'unavailable_authorized_staff' => 'Authorized staff unavailable',
        'approved_data_correction' => 'Approved data correction or incident recovery',
        'legal_regulatory_request' => 'Legal or regulatory request',
        'system_recovery' => 'System recovery with minimum necessary access',
    ];
}

function dental_break_glass_permission_catalog(): array
{
    return [
        'patients.identity.view' => 'View patient identity',
        'patients.contact.view' => 'View patient contact information',
        'patients.safety_alert.view' => 'View patient safety-alert indicator',
        'patients.medical.view' => 'View health information relevant to dental care',
        'patients.financial.view' => 'View patient financial records',
        'appointments.manage' => 'Review or coordinate appointments',
        'queue.manage' => 'Review or coordinate patient flow',
        'communications.manage' => 'Review or record patient communications',
        'billing.manage' => 'Review billing and cashier records',
        'insurance.manage' => 'Review insurance and HMO records',
        'inventory.manage' => 'Review inventory records',
        'sterilization.manage' => 'Review sterilization records',
        'reports.view' => 'View authorized operational reports',
        'records.print' => 'Print an authorized record',
        'uploads.manage' => 'Review protected upload records',
    ];
}


function dental_break_glass_route_permission(string $route): string
{
    $route = trim($route);
    $map = [
        'patients' => 'patients.identity.view',
        'appointment_requests' => 'appointments.manage',
        'portal_requests' => 'appointments.manage',
        'waitlist' => 'appointments.manage',
        'appointments' => 'appointments.manage',
        'appointment_service_actions' => 'appointments.manage',
        'queue' => 'queue.manage',
        'followups' => 'communications.manage',
        'communications' => 'communications.manage',
        'billing' => 'billing.manage',
        'insurance' => 'insurance.manage',
        'inventory' => 'inventory.manage',
        'sterilization' => 'sterilization.manage',
        'reports' => 'reports.view',
        'print_center' => 'records.print',
        'print_record' => 'records.print',
        'uploads' => 'uploads.manage',
        'download_upload' => 'uploads.manage',
        'download_document' => 'uploads.manage',
    ];
    return $map[$route] ?? '';
}

function dental_break_glass_route_allowed(string $route): bool
{
    $permission = dental_break_glass_route_permission($route);
    if ($permission === '') return false;
    return dental_break_glass_permission_allowed($permission, signed_user_branch_id() ?: null);
}

function dental_break_glass_reviewer_authorized(int $sessionId, int $reviewerId): bool
{
    if ($sessionId < 1 || $reviewerId < 1 || !dental_break_glass_schema_ready()) return false;
    try {
        $stmt = db()->prepare(
            'SELECT COUNT(*) FROM `' . dental_break_glass_notifications_table() . '` '
            . 'WHERE session_id=? AND reviewer_user_id=?'
        );
        $stmt->execute([$sessionId,$reviewerId]);
        return (int)$stmt->fetchColumn() > 0;
    } catch (Throwable) {
        return false;
    }
}

function dental_break_glass_permission_never_allowed(string $permission): bool
{
    $permission = strtolower(trim($permission));
    if ($permission === '') return true;
    $exact = [
        'clinical.manage','clinical.draft','clinical.write_self','clinical.finalize','clinical.finalize_self',
        'patients.medical.verify','prescriptions.manage','prescription.issue','consents.sign',
        'refund.approve','discount.approve','zero_charge.approve','payment.adjustment.approve',
        'sterilization.release','privileges.approve','credentials.approve',
        'audit.manage','audit.delete','security.manage','permission.manage','role.manage','staff.manage',
        'system.manage','backup.manage','restore.manage','license.manage','smtp.manage','configuration.manage',
    ];
    if (in_array($permission, $exact, true)) return true;
    return (bool)preg_match('/(?:^|\.)(?:finalize|prescribe|issue_prescription|sign|approve|delete_audit|disable_audit|restore|reset|license|permission|role|credential)(?:\.|$)/i', $permission);
}

function dental_break_glass_permission_is_grantable(string $permission): bool
{
    return isset(dental_break_glass_permission_catalog()[$permission])
        && !dental_break_glass_permission_never_allowed($permission);
}

function dental_break_glass_current_session_reference(): ?array
{
    $session = $_SESSION['dental_break_glass'] ?? null;
    if (!is_array($session)) return null;
    $id = (int)($session['id'] ?? 0);
    $token = trim((string)($session['token'] ?? ''));
    if ($id < 1 || $token === '') return null;
    return ['id'=>$id,'token'=>$token];
}

function dental_break_glass_clear_session_reference(): void
{
    unset($_SESSION['dental_break_glass']);
}

function dental_break_glass_decode_permissions(?string $json): array
{
    $decoded = json_decode((string)$json, true);
    if (!is_array($decoded)) return [];
    $allowed = [];
    foreach ($decoded as $permission) {
        $permission = trim((string)$permission);
        if ($permission !== '' && dental_break_glass_permission_is_grantable($permission)) $allowed[] = $permission;
    }
    return array_values(array_unique($allowed));
}

function dental_break_glass_write_event(
    int $sessionId,
    string $eventType,
    string $permission = '',
    string $entityType = '',
    int|string|null $entityId = null,
    array $details = []
): void {
    if ($sessionId < 1 || !dental_break_glass_schema_ready()) return;
    try {
        $stmt = db()->prepare(
            'INSERT INTO `' . dental_break_glass_events_table() . '` '
            . '(session_id,user_id,event_type,permission_code,route_key,entity_type,entity_id,details_json,ip_address,user_agent,created_at) '
            . 'VALUES (?,?,?,?,?,?,?,?,?,?,NOW())'
        );
        $stmt->execute([
            $sessionId,
            (int)(current_user()['id'] ?? 0) ?: null,
            mb_substr($eventType,0,80),
            $permission !== '' ? mb_substr($permission,0,120) : null,
            mb_substr(function_exists('task_route_key') ? task_route_key() : basename((string)($_SERVER['SCRIPT_NAME'] ?? '')),0,120),
            $entityType !== '' ? mb_substr($entityType,0,80) : null,
            $entityId !== null ? mb_substr((string)$entityId,0,80) : null,
            $details ? json_encode($details,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE) : null,
            mb_substr((string)($_SERVER['REMOTE_ADDR'] ?? ''),0,64),
            mb_substr((string)($_SERVER['HTTP_USER_AGENT'] ?? ''),0,500),
        ]);
    } catch (Throwable $exception) {
        error_log('DentalCare break-glass event logging failed: ' . $exception->getMessage());
    }
}

function dental_break_glass_transition_to_review(int $sessionId, string $reason): void
{
    if ($sessionId < 1 || !dental_break_glass_schema_ready()) return;
    try {
        db()->prepare(
            'UPDATE `' . dental_break_glass_sessions_table() . '` '
            . 'SET status="pending_review",ended_at=COALESCE(ended_at,NOW()),ended_reason=COALESCE(NULLIF(ended_reason,""),?),updated_at=NOW() '
            . 'WHERE id=? AND status="active"'
        )->execute([mb_substr($reason,0,190),$sessionId]);
        dental_break_glass_write_event($sessionId,'session_ended','', '', null, ['reason'=>$reason]);
    } catch (Throwable $exception) {
        error_log('DentalCare break-glass close failed: ' . $exception->getMessage());
    }
}

function dental_break_glass_active_session(bool $refresh = false): ?array
{
    static $cached = false;
    static $row = null;
    if (!$refresh && $cached) return is_array($row) ? $row : null;
    $cached = true;
    $row = null;

    $reference = dental_break_glass_current_session_reference();
    $userId = (int)(current_user()['id'] ?? 0);
    if (!$reference || $userId < 1 || !dental_break_glass_schema_ready()) {
        dental_break_glass_clear_session_reference();
        return null;
    }

    try {
        $stmt = db()->prepare('SELECT * FROM `' . dental_break_glass_sessions_table() . '` WHERE id=? AND user_id=? LIMIT 1');
        $stmt->execute([(int)$reference['id'],$userId]);
        $candidate = $stmt->fetch();
        if (!$candidate || (string)($candidate['status'] ?? '') !== 'active') {
            dental_break_glass_clear_session_reference();
            return null;
        }
        $expectedHash = hash('sha256',(string)$reference['token']);
        if (!hash_equals((string)($candidate['token_hash'] ?? ''),$expectedHash)) {
            dental_break_glass_transition_to_review((int)$candidate['id'],'session_token_mismatch');
            dental_break_glass_clear_session_reference();
            return null;
        }
        if (strtotime((string)($candidate['expires_at'] ?? '')) <= time()) {
            dental_break_glass_transition_to_review((int)$candidate['id'],'expired');
            dental_break_glass_clear_session_reference();
            return null;
        }
        $uaHash = hash('sha256',(string)($_SERVER['HTTP_USER_AGENT'] ?? ''));
        if ((string)($candidate['user_agent_hash'] ?? '') !== '' && !hash_equals((string)$candidate['user_agent_hash'],$uaHash)) {
            dental_break_glass_transition_to_review((int)$candidate['id'],'client_fingerprint_changed');
            dental_break_glass_clear_session_reference();
            return null;
        }
        $candidate['scope_permissions'] = dental_break_glass_decode_permissions((string)($candidate['scope_permissions_json'] ?? '[]'));
        $row = $candidate;
        return $row;
    } catch (Throwable $exception) {
        error_log('DentalCare break-glass session validation failed: ' . $exception->getMessage());
        dental_break_glass_clear_session_reference();
        return null;
    }
}

function dental_break_glass_refresh(): void
{
    dental_break_glass_active_session(true);
}

function dental_break_glass_request_entity_context(): array
{
    $keys = [
        'patient_id'=>'patient','appointment_id'=>'appointment','invoice_id'=>'invoice',
        'encounter_id'=>'encounter','queue_entry_id'=>'queue_entry','document_id'=>'document',
    ];
    foreach ($keys as $key=>$type) {
        $value = (int)($_POST[$key] ?? $_GET[$key] ?? 0);
        if ($value > 0) return ['type'=>$type,'id'=>(string)$value];
    }
    return ['type'=>'','id'=>''];
}

function dental_break_glass_scope_matches(array $session, ?int $branchId = null, string $entityType = '', int|string|null $entityId = null): bool
{
    $scopeBranch = (int)($session['branch_id'] ?? 0);
    if ($scopeBranch > 0 && $branchId !== null && $branchId > 0 && $scopeBranch !== $branchId) return false;

    $scopeType = trim((string)($session['entity_type'] ?? ''));
    $scopeId = trim((string)($session['entity_id'] ?? ''));
    if ($scopeType === '' && $scopeId === '') return true;

    if ($entityType === '' || $entityId === null || (string)$entityId === '') {
        $requestEntity = dental_break_glass_request_entity_context();
        $entityType = (string)$requestEntity['type'];
        $entityId = (string)$requestEntity['id'];
    }
    return $entityType === $scopeType && (string)$entityId === $scopeId;
}

function dental_break_glass_permission_allowed(
    string $permission,
    ?int $branchId = null,
    string $entityType = '',
    int|string|null $entityId = null
): bool {
    static $logged = [];
    $requestedPermission = $permission;
    // Opening the patient directory is a container permission; the session
    // must explicitly include patient identity before that container opens.
    if ($permission === 'patients.view') $permission = 'patients.identity.view';
    if (!dental_break_glass_permission_is_grantable($permission)) return false;
    $session = dental_break_glass_active_session();
    if (!$session || !in_array($permission,(array)($session['scope_permissions'] ?? []),true)) return false;
    if (!dental_break_glass_scope_matches($session,$branchId,$entityType,$entityId)) return false;

    $key = (int)$session['id'] . '|' . $permission . '|' . $entityType . '|' . (string)$entityId;
    if (!isset($logged[$key])) {
        $logged[$key] = true;
        dental_break_glass_write_event((int)$session['id'],'permission_used',$permission,$entityType,$entityId,[
            'requested_permission'=>$requestedPermission,
            'branch_id'=>$branchId,
            'active_role'=>active_role(),
        ]);
        if (function_exists('dental_access_record_decision')) {
            dental_access_record_decision('break_glass',$permission,$entityType,$entityId,'Temporary emergency access session #' . (int)$session['id']);
        }
    }
    return true;
}

function dental_break_glass_branch_allowed(int $branchId, string $entityType = '', int|string|null $entityId = null): bool
{
    $session = dental_break_glass_active_session();
    if (!$session) return false;
    return dental_break_glass_scope_matches($session,$branchId,$entityType,$entityId);
}

function dental_break_glass_verify_reauthentication(int $userId, string $password, string $mfaCode): void
{
    if ($userId < 1) throw new RuntimeException('The signed-in account is unavailable.');
    $stmt = db()->prepare('SELECT password_hash FROM `' . table('users') . '` WHERE id=? AND status="active" LIMIT 1');
    $stmt->execute([$userId]);
    $hash = (string)$stmt->fetchColumn();
    if ($hash === '' || !password_verify($password,$hash)) {
        throw new RuntimeException('The current password is incorrect.');
    }
    if (!function_exists('dental_mfa_user_enabled') || !dental_mfa_user_enabled($userId)) {
        throw new RuntimeException('A working authenticator must be enrolled before emergency administrative access can be started.');
    }
    if (!dental_mfa_verify_user_code($userId,$mfaCode,true)) {
        throw new RuntimeException('The authenticator or recovery code is incorrect.');
    }
}

function dental_break_glass_notify_reviewers(PDO $pdo, int $sessionId, int $actorId, ?int $branchId, string $reasonLabel, string $expiresAt): int
{
    if ($sessionId < 1 || !dental_break_glass_schema_ready()) return 0;
    $sql = 'SELECT DISTINCT u.id,u.name,u.email,r.code role_code,u.branch_id '
        . 'FROM `' . table('users') . '` u JOIN `' . table('roles') . '` r ON r.id=u.role_id '
        . 'WHERE u.status="active" AND u.id<>? AND r.code IN ("super_admin","clinic_admin")';
    $args = [$actorId];
    if ($branchId !== null && $branchId > 0) {
        $sql .= ' AND (r.code="super_admin" OR u.branch_id=?)';
        $args[] = $branchId;
    }
    $sql .= ' ORDER BY r.code="super_admin" DESC,u.id';
    $stmt = $pdo->prepare($sql);
    $stmt->execute($args);
    $reviewers = $stmt->fetchAll();
    if (!$reviewers) return 0;

    $insert = $pdo->prepare(
        'INSERT INTO `' . dental_break_glass_notifications_table() . '` '
        . '(session_id,reviewer_user_id,channel,status,queued_email_id,created_at,updated_at) '
        . 'VALUES (?,? ,"in_app","pending",NULL,NOW(),NOW()) '
        . 'ON DUPLICATE KEY UPDATE status=IF(status="acknowledged","acknowledged","pending"),updated_at=NOW()'
    );
    $count = 0;
    foreach ($reviewers as $reviewer) {
        $reviewerId = (int)($reviewer['id'] ?? 0);
        if ($reviewerId < 1) continue;
        $insert->execute([$sessionId,$reviewerId]);
        $notificationId = (int)$pdo->lastInsertId();
        $email = trim((string)($reviewer['email'] ?? ''));
        if ($email !== '' && filter_var($email,FILTER_VALIDATE_EMAIL) && function_exists('queue_mail_message') && email_queue_schema_ready()) {
            try {
                $subject = 'DentalCare emergency access review required';
                $text = 'Emergency administrative access session #' . $sessionId . ' was started. Reason: ' . $reasonLabel . '. It expires at ' . $expiresAt . '. Sign in and open Administration → Emergency Access Review.';
                $html = '<p>Emergency administrative access session <strong>#' . $sessionId . '</strong> was started.</p><p><strong>Reason:</strong> ' . htmlspecialchars($reasonLabel,ENT_QUOTES,'UTF-8') . '<br><strong>Expires:</strong> ' . htmlspecialchars($expiresAt,ENT_QUOTES,'UTF-8') . '</p><p>Sign in and open <strong>Administration → Emergency Access Review</strong>.</p>';
                $outboxId = queue_mail_message($email,$subject,$html,$text,['type'=>'break_glass_review','session_id'=>$sessionId,'reviewer_user_id'=>$reviewerId]);
                $pdo->prepare('UPDATE `' . dental_break_glass_notifications_table() . '` SET channel="in_app+email",status="queued",queued_email_id=?,updated_at=NOW() WHERE session_id=? AND reviewer_user_id=?')
                    ->execute([$outboxId,$sessionId,$reviewerId]);
            } catch (Throwable $exception) {
                $pdo->prepare('UPDATE `' . dental_break_glass_notifications_table() . '` SET status="pending",last_error=?,updated_at=NOW() WHERE session_id=? AND reviewer_user_id=?')
                    ->execute([mb_substr($exception->getMessage(),0,500),$sessionId,$reviewerId]);
            }
        }
        $count++;
    }
    return $count;
}

function dental_break_glass_start(array $input): array
{
    if (!dental_break_glass_actor_allowed()) throw new RuntimeException('Only a signed-in Administrator or Superuser can request emergency administrative access.');
    if (!dental_break_glass_schema_ready()) throw new RuntimeException('Apply the v0.9.0.5 database update before starting emergency access.');
    if (dental_break_glass_active_session()) throw new RuntimeException('An emergency access session is already active. End it before starting another.');

    $userId = (int)(current_user()['id'] ?? 0);
    $password = (string)($input['password'] ?? '');
    $mfaCode = trim((string)($input['mfa_code'] ?? ''));
    dental_break_glass_verify_reauthentication($userId,$password,$mfaCode);

    $reasons = dental_break_glass_reason_catalog();
    $reasonCode = trim((string)($input['reason_code'] ?? ''));
    $reasonText = trim((string)($input['reason_text'] ?? ''));
    if (!isset($reasons[$reasonCode])) throw new RuntimeException('Select an approved emergency-access reason.');
    if (mb_strlen($reasonText) < 20) throw new RuntimeException('Enter a specific explanation of at least 20 characters.');

    $duration = (int)($input['duration_minutes'] ?? 15);
    if (!in_array($duration,[15,30],true)) throw new RuntimeException('Emergency access may last only 15 or 30 minutes.');

    $requestedPermissions = (array)($input['permissions'] ?? []);
    $permissions = [];
    foreach ($requestedPermissions as $permission) {
        $permission = trim((string)$permission);
        if (dental_break_glass_permission_is_grantable($permission)) $permissions[] = $permission;
    }
    $permissions = array_values(array_unique($permissions));
    if (!$permissions) throw new RuntimeException('Select at least one minimum-necessary permission.');
    if (count($permissions) > 8) throw new RuntimeException('Select no more than eight permissions for one emergency session.');

    $branchId = (int)($input['branch_id'] ?? 0);
    $actual = actual_role();
    if ($actual === 'clinic_admin') {
        $ownBranch = signed_user_branch_id();
        if ($ownBranch < 1) throw new RuntimeException('Assign the Administrator to a clinic branch before starting emergency access.');
        $branchId = $ownBranch;
    }
    if ($branchId < 1) throw new RuntimeException('Select the clinic branch for this emergency-access session.');
    $stmt = db()->prepare('SELECT COUNT(*) FROM `' . table('branches') . '` WHERE id=? AND is_active=1');
    $stmt->execute([$branchId]);
    if ((int)$stmt->fetchColumn() !== 1) throw new RuntimeException('Select an active clinic branch.');

    $entityType = trim((string)($input['entity_type'] ?? ''));
    $entityId = trim((string)($input['entity_id'] ?? ''));
    $allowedEntityTypes = ['','patient','appointment','encounter','invoice','queue_entry','document'];
    if (!in_array($entityType,$allowedEntityTypes,true)) throw new RuntimeException('The emergency entity scope is not supported.');
    if (($entityType === '') !== ($entityId === '')) throw new RuntimeException('Provide both an entity type and entity ID, or leave both blank.');
    if ($entityId !== '' && !preg_match('/^[1-9][0-9]{0,18}$/',$entityId)) throw new RuntimeException('The scoped entity ID must be a positive record number.');

    $token = bin2hex(random_bytes(32));
    $tokenHash = hash('sha256',$token);
    $startedAt = date('Y-m-d H:i:s');
    $expiresAt = date('Y-m-d H:i:s',time()+($duration*60));
    $reviewDueAt = date('Y-m-d H:i:s',time()+86400);
    $uaHash = hash('sha256',(string)($_SERVER['HTTP_USER_AGENT'] ?? ''));
    $pdo = db();
    $pdo->beginTransaction();
    try {
        // A user may have only one active emergency session. Close stale rows
        // before inserting the new, explicitly re-authenticated session.
        $pdo->prepare('UPDATE `' . dental_break_glass_sessions_table() . '` SET status="pending_review",ended_at=COALESCE(ended_at,NOW()),ended_reason="superseded",updated_at=NOW() WHERE user_id=? AND status="active"')
            ->execute([$userId]);
        $stmt = $pdo->prepare(
            'INSERT INTO `' . dental_break_glass_sessions_table() . '` '
            . '(user_id,branch_id,status,reason_code,reason_text,scope_permissions_json,entity_type,entity_id,token_hash,user_agent_hash,mfa_verified_at,started_at,expires_at,review_due_at,created_ip,created_at,updated_at) '
            . 'VALUES (?,?,"active",?,?,?,?,?,?,?,NOW(),?,?,?,?,NOW(),NOW())'
        );
        $stmt->execute([
            $userId,$branchId ?: null,$reasonCode,mb_substr($reasonText,0,1000),
            json_encode($permissions,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE),
            $entityType !== '' ? $entityType : null,$entityId !== '' ? $entityId : null,
            $tokenHash,$uaHash,$startedAt,$expiresAt,$reviewDueAt,
            mb_substr((string)($_SERVER['REMOTE_ADDR'] ?? ''),0,64),
        ]);
        $sessionId = (int)$pdo->lastInsertId();
        $reviewerCount = dental_break_glass_notify_reviewers($pdo,$sessionId,$userId,$branchId ?: null,$reasons[$reasonCode],$expiresAt);
        if ($reviewerCount < 1) {
            throw new RuntimeException('Emergency access requires another active Administrator or Superuser to receive the review notification. Create or activate an independent reviewer first.');
        }
        audit_required('break_glass_started','administrative_break_glass_session',$sessionId,[
            'reason_code'=>$reasonCode,'reason_text'=>$reasonText,'branch_id'=>$branchId ?: null,
            'permissions'=>$permissions,'entity_type'=>$entityType ?: null,'entity_id'=>$entityId ?: null,
            'expires_at'=>$expiresAt,'review_due_at'=>$reviewDueAt,'reviewer_count'=>$reviewerCount,
        ]);
        $pdo->commit();
    } catch (Throwable $exception) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        throw $exception;
    }

    $_SESSION['dental_break_glass'] = ['id'=>$sessionId,'token'=>$token,'started_at'=>time(),'expires_at'=>strtotime($expiresAt)];
    dental_break_glass_active_session(true);
    dental_break_glass_write_event($sessionId,'session_started','',$entityType,$entityId !== '' ? $entityId : null,[
        'permissions'=>$permissions,'branch_id'=>$branchId ?: null,'expires_at'=>$expiresAt,
    ]);
    return ['id'=>$sessionId,'expires_at'=>$expiresAt,'review_due_at'=>$reviewDueAt,'permissions'=>$permissions];
}

function dental_break_glass_end(string $reason = 'ended_by_user'): void
{
    $session = dental_break_glass_active_session();
    if (!$session) {
        dental_break_glass_clear_session_reference();
        return;
    }
    $sessionId = (int)$session['id'];
    dental_break_glass_transition_to_review($sessionId,$reason);
    try {
        audit_required('break_glass_ended','administrative_break_glass_session',$sessionId,['reason'=>$reason]);
    } catch (Throwable $exception) {
        error_log('DentalCare break-glass end audit failed: ' . $exception->getMessage());
    }
    dental_break_glass_clear_session_reference();
    dental_break_glass_active_session(true);
}

function dental_break_glass_pending_review_count(): int
{
    $userId = (int)(current_user()['id'] ?? 0);
    if ($userId < 1 || !dental_break_glass_schema_ready()) return 0;
    try {
        $stmt = db()->prepare(
            'SELECT COUNT(*) FROM `' . dental_break_glass_notifications_table() . '` n '
            . 'JOIN `' . dental_break_glass_sessions_table() . '` s ON s.id=n.session_id '
            . 'WHERE n.reviewer_user_id=? AND n.acknowledged_at IS NULL AND s.user_id<>? AND s.status IN ("active","pending_review")'
        );
        $stmt->execute([$userId,$userId]);
        return (int)$stmt->fetchColumn();
    } catch (Throwable) {
        return 0;
    }
}

function dental_break_glass_review_session(int $sessionId, string $outcome, string $notes): void
{
    if (!dental_break_glass_actor_allowed()) throw new RuntimeException('Only an Administrator or Superuser may review emergency access.');
    if ($sessionId < 1 || !dental_break_glass_schema_ready()) throw new RuntimeException('The emergency session is unavailable.');
    $outcomes = ['approved','concerning','escalated'];
    if (!in_array($outcome,$outcomes,true)) throw new RuntimeException('Select a review outcome.');
    if (mb_strlen(trim($notes)) < 10) throw new RuntimeException('Enter review notes of at least 10 characters.');

    $reviewerId = (int)(current_user()['id'] ?? 0);
    $pdo = db();
    $pdo->beginTransaction();
    try {
        $stmt = $pdo->prepare('SELECT * FROM `' . dental_break_glass_sessions_table() . '` WHERE id=? FOR UPDATE');
        $stmt->execute([$sessionId]);
        $session = $stmt->fetch();
        if (!$session) throw new RuntimeException('The emergency session was not found.');
        if ((int)$session['user_id'] === $reviewerId) throw new RuntimeException('Independent review is required. The emergency-access user cannot review their own session.');
        if (!dental_break_glass_reviewer_authorized($sessionId,$reviewerId)) throw new RuntimeException('This emergency session was not assigned to you for independent review.');
        if (!in_array((string)$session['status'],['active','pending_review'],true)) throw new RuntimeException('This emergency session has already been reviewed or revoked.');

        $status = (string)$session['status'];
        if ($status === 'active') {
            $pdo->prepare('UPDATE `' . dental_break_glass_sessions_table() . '` SET status="pending_review",ended_at=NOW(),ended_reason="reviewer_closed_active_session",updated_at=NOW() WHERE id=?')->execute([$sessionId]);
        }
        $pdo->prepare(
            'UPDATE `' . dental_break_glass_sessions_table() . '` SET status="reviewed",reviewer_user_id=?,review_outcome=?,review_notes=?,reviewed_at=NOW(),updated_at=NOW() WHERE id=?'
        )->execute([$reviewerId,$outcome,mb_substr(trim($notes),0,1000),$sessionId]);
        $pdo->prepare('UPDATE `' . dental_break_glass_notifications_table() . '` SET status="acknowledged",acknowledged_at=NOW(),updated_at=NOW() WHERE session_id=? AND reviewer_user_id=?')
            ->execute([$sessionId,$reviewerId]);
        audit_required('break_glass_reviewed','administrative_break_glass_session',$sessionId,[
            'outcome'=>$outcome,'notes'=>$notes,'subject_user_id'=>(int)$session['user_id'],
        ]);
        $pdo->commit();
    } catch (Throwable $exception) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        throw $exception;
    }
    dental_break_glass_write_event($sessionId,'session_reviewed','', '', null,['outcome'=>$outcome,'notes'=>$notes]);
}

function dental_break_glass_revoke_session(int $sessionId, string $reason): void
{
    if (!dental_break_glass_actor_allowed()) throw new RuntimeException('Only an Administrator or Superuser may revoke emergency access.');
    if (mb_strlen(trim($reason)) < 10) throw new RuntimeException('Enter a revocation reason of at least 10 characters.');
    $reviewerId = (int)(current_user()['id'] ?? 0);
    $pdo = db();
    $pdo->beginTransaction();
    try {
        $stmt = $pdo->prepare('SELECT * FROM `' . dental_break_glass_sessions_table() . '` WHERE id=? FOR UPDATE');
        $stmt->execute([$sessionId]);
        $session = $stmt->fetch();
        if (!$session || (string)$session['status'] !== 'active') throw new RuntimeException('The emergency session is no longer active.');
        if ((int)$session['user_id'] === $reviewerId) throw new RuntimeException('Use End emergency access to close your own session.');
        if (!dental_break_glass_reviewer_authorized($sessionId,$reviewerId)) throw new RuntimeException('This emergency session was not assigned to you for independent review.');
        $pdo->prepare('UPDATE `' . dental_break_glass_sessions_table() . '` SET status="pending_review",ended_at=NOW(),ended_reason=?,updated_at=NOW() WHERE id=?')
            ->execute(['revoked_by_reviewer: ' . mb_substr(trim($reason),0,150),$sessionId]);
        audit_required('break_glass_revoked','administrative_break_glass_session',$sessionId,['reason'=>$reason,'subject_user_id'=>(int)$session['user_id']]);
        $pdo->commit();
    } catch (Throwable $exception) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        throw $exception;
    }
    dental_break_glass_write_event($sessionId,'session_revoked','', '', null,['reason'=>$reason]);
}
