<?php

declare(strict_types=1);

/**
 * DentalCare v0.9.1.0 first-seating dental treatment safety controls.
 *
 * Health information is collected/reviewed before treatment begins. Treatment
 * pages consume a read-only safety summary and cannot become a second intake
 * form. This module is intentionally limited to information that can affect
 * dental treatment, dental prescribing, local anaesthesia/sedation, bleeding,
 * radiography, healing, infection risk, or a referral decision.
 */

function dental_safety_assessment_schema_ready(): bool
{
    static $ready = null;
    if ($ready !== null) return $ready;
    try {
        return $ready = schema_table_exists(table('dental_safety_assessments'))
            && schema_column_exists(table('clinical_encounters'), 'dental_safety_assessment_id')
            && schema_column_exists(table('vital_signs'), 'queue_entry_id')
            && schema_column_exists(table('vital_signs'), 'dental_safety_assessment_id');
    } catch (Throwable) {
        return $ready = false;
    }
}

function dental_safety_assessment_for_queue(int $queueId, bool $forUpdate = false): ?array
{
    if ($queueId < 1 || !dental_safety_assessment_schema_ready()) return null;
    $sql = 'SELECT dsa.*,u.name recorded_by_name,vu.name verified_by_name '
        . 'FROM `' . table('dental_safety_assessments') . '` dsa '
        . 'LEFT JOIN `' . table('users') . '` u ON u.id=dsa.recorded_by '
        . 'LEFT JOIN `' . table('users') . '` vu ON vu.id=dsa.verified_by '
        . 'WHERE dsa.queue_entry_id=? ORDER BY dsa.id DESC LIMIT 1' . ($forUpdate ? ' FOR UPDATE' : '');
    $stmt = db()->prepare($sql);
    $stmt->execute([$queueId]);
    return $stmt->fetch() ?: null;
}

function dental_safety_assessment_for_encounter(array $encounter): ?array
{
    $assessmentId = (int)($encounter['dental_safety_assessment_id'] ?? 0);
    if ($assessmentId > 0 && dental_safety_assessment_schema_ready()) {
        $stmt = db()->prepare('SELECT dsa.*,u.name recorded_by_name,vu.name verified_by_name FROM `' . table('dental_safety_assessments') . '` dsa LEFT JOIN `' . table('users') . '` u ON u.id=dsa.recorded_by LEFT JOIN `' . table('users') . '` vu ON vu.id=dsa.verified_by WHERE dsa.id=? LIMIT 1');
        $stmt->execute([$assessmentId]);
        $row = $stmt->fetch();
        if ($row) return $row;
    }
    return dental_safety_assessment_for_queue((int)($encounter['queue_entry_id'] ?? 0));
}

function dental_safety_assessment_status_label(string $status): string
{
    return match ($status) {
        'ready' => 'Ready for Dentist',
        'verified' => 'Dentist verified',
        'needs_dentist_review' => 'Dentist review required',
        'hold' => 'Treatment on hold',
        'draft' => 'Assessment incomplete',
        default => 'Not completed',
    };
}

function dental_safety_assessment_is_ready(?array $assessment): bool
{
    return $assessment && in_array((string)($assessment['status'] ?? ''), ['ready','verified'], true);
}

function dental_safety_assessment_url(int $queueId): string
{
    return 'dental_safety_assessment.php?queue_id=' . max(0, $queueId);
}


function dental_safety_measurement_required(array $queue, ?string $carePath = null): bool
{
    $carePath = strtolower(trim((string)$carePath));
    if ($carePath === 'emergency') return true;
    if (trim((string)($queue['medical_alerts'] ?? '')) !== '') return true;
    $riskSource = trim(implode(' ', [
        (string)($queue['service_name'] ?? $queue['queue_service'] ?? ''),
        (string)($queue['reason'] ?? $queue['queue_reason'] ?? ''),
    ]));
    $riskText = function_exists('mb_strtolower') ? mb_strtolower($riskSource) : strtolower($riskSource);
    if ($riskText === '') return false;
    return (bool)preg_match('/extract|odontect|impacted|surg|implant|sedat|general\s+anesth|local\s+anesth|nerve\s+block|biopsy|incision|drainage|alveol|bone\s+graft|apico|flap|gingivect|pulpotom|pulpectom|root\s+canal|endodont|hemosta|uncontrolled\s+bleeding|trauma|avuls/u', $riskText);
}

function dental_safety_treatment_gate(array $queue, ?string $carePath = null): array
{
    $queueId = (int)($queue['id'] ?? $queue['queue_entry_id'] ?? 0);
    if (($queue['provider_type'] ?? 'dentist') !== 'dentist') {
        return ['ready' => true, 'status' => 'not_applicable', 'label' => 'Not applicable', 'message' => '', 'assessment' => null];
    }
    if ((string)($queue['status'] ?? '') === 'in_treatment') {
        // Existing treatment that was already opened before v0.9.1.0 remains
        // accessible. New starts are gated below before the queue can enter this state.
        $assessment = dental_safety_assessment_for_queue($queueId);
        return [
            'ready' => true,
            'status' => (string)($assessment['status'] ?? 'legacy_active'),
            'label' => $assessment ? dental_safety_assessment_status_label((string)$assessment['status']) : 'Active legacy encounter',
            'message' => $assessment ? '' : 'This treatment was already active before the first-seating gate was installed.',
            'assessment' => $assessment,
        ];
    }
    if (!dental_safety_assessment_schema_ready()) {
        return ['ready' => false, 'status' => 'schema_missing', 'label' => 'Update required', 'message' => 'Apply v0.9.1.0 before starting another treatment.', 'assessment' => null];
    }
    $assessment = dental_safety_assessment_for_queue($queueId);
    if (!$assessment) {
        return ['ready' => false, 'status' => 'missing', 'label' => 'First seating required', 'message' => 'Complete the dental treatment safety assessment before treatment starts.', 'assessment' => null];
    }
    $status = (string)($assessment['status'] ?? 'draft');
    $ready = dental_safety_assessment_is_ready($assessment);
    $measurementRequired = dental_safety_measurement_required($queue, $carePath);
    $measurementComplete = (int)($assessment['blood_pressure_systolic'] ?? 0) > 0
        && (int)($assessment['blood_pressure_diastolic'] ?? 0) > 0;
    if ($ready && $measurementRequired && !$measurementComplete) {
        return [
            'ready' => false,
            'status' => 'measurement_required',
            'label' => 'Indicated measurement required',
            'message' => 'This dental visit requires an indicated blood-pressure assessment at first seating before treatment starts.',
            'assessment' => $assessment,
        ];
    }
    return [
        'ready' => $ready,
        'status' => $status,
        'label' => dental_safety_assessment_status_label($status),
        'message' => match ($status) {
            'needs_dentist_review' => 'The assigned Dentist must review the reported change or alert before treatment.',
            'hold' => 'Treatment is on hold until the documented safety concern is resolved.',
            'draft' => 'Finish the first-seating assessment before treatment.',
            default => '',
        },
        'assessment' => $assessment,
    ];
}

function dental_safety_assert_treatment_ready(PDO $pdo, array $queue, ?string $carePath = null): array
{
    $gate = dental_safety_treatment_gate($queue, $carePath);
    if (!empty($gate['ready'])) return $gate;
    $queueId = (int)($queue['id'] ?? $queue['queue_entry_id'] ?? 0);
    $message = trim((string)($gate['message'] ?? ''));
    if ($message === '') $message = 'Complete first-seating dental safety assessment before treatment starts.';
    $GLOBALS['dental_safety_gate_redirect'] = dental_safety_assessment_url($queueId);
    throw new RuntimeException($message);
}

function dental_safety_latest_history(PDO $pdo, int $patientId): ?array
{
    if ($patientId < 1 || !schema_table_exists(table('medical_histories'))) return null;
    $stmt = $pdo->prepare('SELECT mh.*,u.name verified_by_name FROM `' . table('medical_histories') . '` mh LEFT JOIN `' . table('users') . '` u ON u.id=mh.verified_by WHERE mh.patient_id=? ORDER BY mh.created_at DESC,mh.id DESC LIMIT 1');
    $stmt->execute([$patientId]);
    return $stmt->fetch() ?: null;
}

function dental_safety_assessment_requires_dentist_review(array $payload, array $patient, bool $firstHistory): bool
{
    if ($firstHistory) return true;
    if (($payload['change_status'] ?? 'unknown') !== 'none') return true;
    if (trim((string)($patient['medical_alerts'] ?? '')) !== '') return true;
    $systolic = (int)($payload['blood_pressure_systolic'] ?? 0);
    $diastolic = (int)($payload['blood_pressure_diastolic'] ?? 0);
    if (($systolic > 0 && ($systolic >= 160 || $systolic < 90)) || ($diastolic > 0 && ($diastolic >= 100 || $diastolic < 60))) return true;
    return false;
}

function dental_safety_role_landing_url(string $role): string
{
    return match ($role) {
        'dentist' => 'clinical_day.php',
        'dental_assistant' => 'queue.php',
        'receptionist' => 'queue.php',
        'cashier' => 'billing.php',
        'inventory_officer' => 'inventory.php',
        'staff' => 'dashboard.php',
        'clinic_admin' => 'dashboard.php',
        'super_admin' => 'dashboard.php',
        default => 'dashboard.php',
    };
}

function dental_task_context_clear_for_switch(string $fromRole, string $toRole): array
{
    $cleared = [];
    $keys = [
        'task_dentist_id',
        'dental_patient_context',
        'active_patient_context',
        'dental_active_clinical_context',
        'cashier_patient_context',
        'dental_viewed_patient_id',
        'dental_selected_visit_id',
        'dental_queue_filter',
        'clinical_workspace_focus',
    ];
    foreach ($keys as $key) {
        if (array_key_exists($key, $_SESSION)) $cleared[] = $key;
        unset($_SESSION[$key]);
    }
    $_SESSION['task_context_role'] = $toRole;
    $_SESSION['task_context_switched_at'] = date('c');
    return $cleared;
}

function dental_task_context_enforce_role_boundary(): void
{
    if (PHP_SAPI === 'cli' || !current_user()) return;
    $currentRole = active_role();
    $previousRole = trim((string)($_SESSION['task_context_role'] ?? ''));
    if ($previousRole === '') {
        // Existing sessions created before v0.9.1.0 may still contain a patient
        // selected under another Task View. Clear once when a temporary role is
        // already active, then establish the role boundary marker.
        if (!empty($_SESSION['task_role'])) {
            dental_task_context_clear_for_switch(actual_role(), $currentRole);
        } else {
            $_SESSION['task_context_role'] = $currentRole;
            $_SESSION['task_context_switched_at'] = date('c');
        }
        return;
    }
    if ($previousRole !== $currentRole) {
        dental_task_context_clear_for_switch($previousRole, $currentRole);
    }
}

dental_task_context_enforce_role_boundary();
