<?php

declare(strict_types=1);

if (!defined('DENTAL_ROOT')) {
    exit;
}

function chair_resource_schema_ready(): bool
{
    return schema_table_exists(table('clinic_chairs'))
        && schema_column_exists(table('clinic_chairs'), 'resource_kind')
        && schema_column_exists(table('clinic_chairs'), 'default_provider_user_id')
        && schema_table_exists(table('chair_session_assignments'))
        && schema_table_exists(table('chair_status_events'))
        && schema_table_exists(table('chair_visit_movements'));
}

function chair_resource_usage_labels(): array
{
    return [
        'operatory' => 'Dental operatory',
        'surgery' => 'Surgery / extraction room',
        'xray' => 'X-ray / imaging room',
        'consultation' => 'Consultation room',
        'shared_inhouse' => 'Shared in-house resource',
        'dentist_bound' => 'Legacy default operatory',
    ];
}

function chair_resource_usage_label(string $mode): string
{
    $labels = chair_resource_usage_labels();
    return $labels[$mode] ?? ucwords(str_replace('_', ' ', $mode ?: 'resource'));
}

function chair_resource_clinical_modes(): array
{
    return ['operatory','surgery','dentist_bound'];
}

function chair_resource_record_event(PDO $pdo, int $chairId, string $eventType, string $note = '', ?int $queueEntryId = null, ?int $appointmentId = null, ?int $providerId = null): void
{
    if (!schema_table_exists(table('chair_status_events'))) return;
    $stmt = $pdo->prepare('INSERT INTO `' . table('chair_status_events') . '` (chair_id,event_type,queue_entry_id,appointment_id,provider_user_id,note,created_by,created_at) VALUES (?,?,?,?,?,?,?,NOW())');
    $stmt->execute([$chairId,$eventType,$queueEntryId,$appointmentId,$providerId,$note !== '' ? mb_substr($note,0,500) : null,(int)(((array)current_user())['id'] ?? 0) ?: null]);
}

function chair_resource_fetch(PDO $pdo, int $chairId): ?array
{
    if ($chairId < 1 || !schema_table_exists(table('clinic_chairs'))) return null;
    $stmt = $pdo->prepare('SELECT * FROM `' . table('clinic_chairs') . '` WHERE id=? LIMIT 1');
    $stmt->execute([$chairId]);
    $row = $stmt->fetch();
    return $row ?: null;
}

function chair_resource_active_occupant(PDO $pdo, int $chairId, int $excludeQueueId = 0): ?array
{
    if ($chairId < 1 || !schema_table_exists(table('queue_entries')) || !schema_column_exists(table('queue_entries'), 'chair_id')) return null;
    $sql = 'SELECT q.id,q.queue_no,q.status,q.patient_id,q.chair_name,CONCAT(COALESCE(p.first_name,"")," ",COALESCE(p.last_name,"")) patient '
        . 'FROM `' . table('queue_entries') . '` q LEFT JOIN `' . table('patients') . '` p ON p.id=q.patient_id '
        . 'WHERE q.chair_id=? AND q.status IN ("seated","in_treatment")';
    $args = [$chairId];
    if ($excludeQueueId > 0) { $sql .= ' AND q.id<>?'; $args[] = $excludeQueueId; }
    $sql .= ' ORDER BY q.updated_at DESC,q.id DESC LIMIT 1';
    $stmt = $pdo->prepare($sql);
    $stmt->execute($args);
    $row = $stmt->fetch();
    return $row ?: null;
}

function chair_resource_current_occupants(PDO $pdo, int $branchId): array
{
    $queueTable = table('queue_entries');
    if ($branchId < 1 || !schema_table_exists($queueTable) || !schema_column_exists($queueTable, 'chair_id')) return [];

    // Reset/recovery copies can reach the chair manager before the latest queue
    // provider-name column has been applied. Build the SELECT from the columns
    // that actually exist so the board stays usable and System Setup can still
    // apply the pending database repair.
    $hasInhouseProviderUser = schema_column_exists($queueTable, 'inhouse_provider_user_id');
    $hasInhouseProviderName = schema_column_exists($queueTable, 'inhouse_provider_name');
    $inhouseUserSelect = $hasInhouseProviderUser ? 'q.inhouse_provider_user_id' : 'NULL AS inhouse_provider_user_id';
    $inhouseNameSelect = $hasInhouseProviderName
        ? 'q.inhouse_provider_name'
        : ($hasInhouseProviderUser && schema_table_exists(table('users')) ? 'iu.name AS inhouse_provider_name' : 'NULL AS inhouse_provider_name');
    $inhouseJoin = (!$hasInhouseProviderName && $hasInhouseProviderUser && schema_table_exists(table('users')))
        ? ' LEFT JOIN `' . table('users') . '` iu ON iu.id=q.inhouse_provider_user_id '
        : ' ';

    $stmt = $pdo->prepare(
        'SELECT q.id,q.queue_no,q.status,q.chair_id,q.chair_name,q.appointment_id,q.dentist_user_id,q.dentist_name,'
        . $inhouseUserSelect . ',' . $inhouseNameSelect . ',q.checked_in_at,q.seated_at,q.treatment_started_at,CONCAT(COALESCE(p.first_name,"")," ",COALESCE(p.last_name,"")) patient,p.patient_no '
        . 'FROM `' . $queueTable . '` q LEFT JOIN `' . table('patients') . '` p ON p.id=q.patient_id' . $inhouseJoin
        . 'WHERE q.branch_id=? AND q.status IN ("seated","in_treatment") ORDER BY q.chair_name,q.seated_at,q.treatment_started_at'
    );
    $stmt->execute([$branchId]);
    return $stmt->fetchAll();
}

function chair_resource_active_session_for_doctor(PDO $pdo, int $doctorId, int $branchId, ?string $startAt = null, ?string $endAt = null): ?array
{
    if ($doctorId < 1 || $branchId < 1 || !schema_table_exists(table('chair_session_assignments'))) return null;
    $startAt = $startAt ?: date('Y-m-d H:i:s');
    $endAt = $endAt ?: $startAt;
    $stmt = $pdo->prepare(
        'SELECT csa.*,c.status chair_status,c.usage_mode,c.resource_kind '
        . 'FROM `' . table('chair_session_assignments') . '` csa '
        . 'LEFT JOIN `' . table('clinic_chairs') . '` c ON c.id=csa.chair_id '
        . 'WHERE csa.branch_id=? AND csa.dentist_user_id=? AND csa.status="active" '
        . 'AND csa.starts_at < ? AND csa.ends_at > ? '
        . 'ORDER BY csa.starts_at DESC,csa.id DESC LIMIT 1'
    );
    $stmt->execute([$branchId,$doctorId,$endAt,$startAt]);
    $row = $stmt->fetch();
    return $row ?: null;
}

function chair_resource_resolve_for_doctor(int $doctorId, int $branchId, ?string $startAt = null, ?string $endAt = null): array
{
    $result = [
        'doctor_id' => $doctorId,
        'branch_id' => $branchId,
        'chair_id' => 0,
        'chair_name' => null,
        'valid' => false,
        'issue' => 'No available operatory is assigned for this Dentist in the selected time.',
        'source' => 'none',
    ];
    if ($doctorId < 1 || $branchId < 1) return $result;
    $pdo = db();

    $session = chair_resource_active_session_for_doctor($pdo, $doctorId, $branchId, $startAt, $endAt);
    if ($session) {
        $chairName = normalize_chair_name((string)($session['chair_name'] ?? ''));
        $mode = (string)($session['usage_mode'] ?? $session['resource_kind'] ?? 'operatory');
        $result['chair_id'] = (int)($session['chair_id'] ?? 0);
        $result['chair_name'] = $chairName ?: null;
        $result['source'] = 'session_assignment';
        if ($result['chair_id'] < 1 || $chairName === '') return $result;
        if (($session['chair_status'] ?? '') !== 'available') {
            $result['issue'] = 'The session operatory is currently ' . str_replace('_',' ',(string)($session['chair_status'] ?: 'unavailable')) . '.';
            return $result;
        }
        if (!in_array($mode, chair_resource_clinical_modes(), true)) {
            $result['issue'] = 'The assigned resource is configured as ' . chair_resource_usage_label($mode) . ', not as a dentist treatment operatory.';
            return $result;
        }
        $result['valid'] = true;
        $result['issue'] = '';
        return $result;
    }

    if (function_exists('doctor_chair_binding')) {
        $fallback = doctor_chair_binding($doctorId, $branchId);
        if (!empty($fallback['valid'])) {
            $fallback['source'] = $fallback['source'] ?? 'default_provider';
        }
        return $fallback;
    }
    return $result;
}

function chair_resource_move_queue_to_chair(PDO $pdo, int $queueId, int $targetChairId, string $reason): void
{
    if ($queueId < 1 || $targetChairId < 1) throw new RuntimeException('Select the active visit and target chair.');
    $reason = trim($reason);
    if (mb_strlen($reason) < 5) throw new RuntimeException('Add a short reason for moving the patient to another chair.');
    $chair = chair_resource_fetch($pdo, $targetChairId);
    if (!$chair) throw new RuntimeException('Target chair not found.');
    if (($chair['status'] ?? '') !== 'available') throw new RuntimeException('Target chair is not available.');
    $mode = (string)($chair['usage_mode'] ?? $chair['resource_kind'] ?? 'operatory');
    if (!in_array($mode, ['operatory','surgery','dentist_bound','shared_inhouse','consultation','xray'], true)) throw new RuntimeException('Target chair/resource type is not usable.');

    $pdo->beginTransaction();
    $stmt = $pdo->prepare('SELECT * FROM `' . table('queue_entries') . '` WHERE id=? AND branch_id=? AND status IN ("seated","in_treatment") FOR UPDATE');
    $stmt->execute([$queueId,(int)$chair['branch_id']]);
    $queue = $stmt->fetch();
    if (!$queue) throw new RuntimeException('Active seated/treatment visit not found for this branch.');
    $occupied = chair_resource_active_occupant($pdo, $targetChairId, $queueId);
    if ($occupied) throw new RuntimeException('Target chair is already occupied by ' . trim((string)($occupied['patient'] ?? 'another patient')) . '.');
    $oldChairId = (int)($queue['chair_id'] ?? 0);
    $oldChairName = (string)($queue['chair_name'] ?? '');
    $pdo->prepare('UPDATE `' . table('queue_entries') . '` SET chair_id=?,chair_name=?,updated_at=NOW() WHERE id=?')->execute([$targetChairId,(string)$chair['chair_name'],$queueId]);
    if (schema_table_exists(table('chair_visit_movements'))) {
        $pdo->prepare('INSERT INTO `' . table('chair_visit_movements') . '` (queue_entry_id,appointment_id,patient_id,from_chair_id,from_chair_name,to_chair_id,to_chair_name,reason,moved_by,moved_at) VALUES (?,?,?,?,?,?,?,?,?,NOW())')
            ->execute([$queueId,(int)($queue['appointment_id'] ?? 0) ?: null,(int)($queue['patient_id'] ?? 0) ?: null,$oldChairId ?: null,$oldChairName ?: null,$targetChairId,(string)$chair['chair_name'],mb_substr($reason,0,500),(int)(((array)current_user())['id'] ?? 0) ?: null]);
    }
    chair_resource_record_event($pdo,$targetChairId,'visit_moved_in',$reason,$queueId,(int)($queue['appointment_id'] ?? 0) ?: null,(int)($queue['dentist_user_id'] ?? 0) ?: null);
    if ($oldChairId > 0) chair_resource_record_event($pdo,$oldChairId,'visit_moved_out',$reason,$queueId,(int)($queue['appointment_id'] ?? 0) ?: null,(int)($queue['dentist_user_id'] ?? 0) ?: null);
    audit('queue_chair_moved','queue_entry',$queueId,['from_chair_id'=>$oldChairId,'to_chair_id'=>$targetChairId,'reason'=>$reason]);
    $pdo->commit();
}

function chair_resource_release_queue(PDO $pdo, int $queueId, string $reason): void
{
    $reason = trim($reason);
    if ($queueId < 1) throw new RuntimeException('Select an active visit to release.');
    if (mb_strlen($reason) < 5) throw new RuntimeException('Add a short reason for releasing the chair.');
    $pdo->beginTransaction();
    $stmt = $pdo->prepare('SELECT * FROM `' . table('queue_entries') . '` WHERE id=? AND status IN ("seated","in_treatment") FOR UPDATE');
    $stmt->execute([$queueId]);
    $queue = $stmt->fetch();
    if (!$queue) throw new RuntimeException('Active seated/treatment visit not found.');
    $oldChairId = (int)($queue['chair_id'] ?? 0);
    $oldChairName = (string)($queue['chair_name'] ?? '');
    if ($oldChairId < 1 && $oldChairName === '') throw new RuntimeException('This visit is not occupying a chair.');
    $pdo->prepare('UPDATE `' . table('queue_entries') . '` SET chair_id=NULL,chair_name=NULL,seated_at=NULL,updated_at=NOW() WHERE id=?')->execute([$queueId]);
    if (schema_table_exists(table('chair_visit_movements'))) {
        $pdo->prepare('INSERT INTO `' . table('chair_visit_movements') . '` (queue_entry_id,appointment_id,patient_id,from_chair_id,from_chair_name,to_chair_id,to_chair_name,reason,moved_by,moved_at) VALUES (?,?,?,?,?,?,?,?,?,NOW())')
            ->execute([$queueId,(int)($queue['appointment_id'] ?? 0) ?: null,(int)($queue['patient_id'] ?? 0) ?: null,$oldChairId ?: null,$oldChairName ?: null,null,null,mb_substr($reason,0,500),(int)(((array)current_user())['id'] ?? 0) ?: null]);
    }
    if ($oldChairId > 0) chair_resource_record_event($pdo,$oldChairId,'released',$reason,$queueId,(int)($queue['appointment_id'] ?? 0) ?: null,(int)($queue['dentist_user_id'] ?? 0) ?: null);
    audit('queue_chair_released','queue_entry',$queueId,['chair_id'=>$oldChairId,'chair_name'=>$oldChairName,'reason'=>$reason]);
    $pdo->commit();
}
