<?php

declare(strict_types=1);
require DENTAL_ROOT . '/app/bootstrap.php';
require_login();
require_roles(['super_admin','clinic_admin','dentist']);
require DENTAL_ROOT . '/app/layout.php';

$pdo = db();
$isDentist = active_role_is('dentist');
$branches = $pdo->query('SELECT id,name FROM `' . table('branches') . '` WHERE is_active=1 ORDER BY name')->fetchAll();
$branchId = (int) ($_GET['branch_id'] ?? $_POST['branch_id'] ?? current_user()['branch_id'] ?? ($branches[0]['id'] ?? 0));
$dentists = active_dentists($branchId ?: null);
$doctorId = $isDentist ? (int) current_user()['id'] : (int) ($_GET['doctor_id'] ?? $_POST['doctor_id'] ?? ($dentists[0]['id'] ?? 0));
if (!$isDentist) {
    $availableDoctorIds = array_map(static fn(array $row): int => (int) $row['id'], $dentists);
    if (!in_array($doctorId,$availableDoctorIds,true)) $doctorId = (int) ($availableDoctorIds[0] ?? 0);
}
$doctorName = '';
foreach ($dentists as $dentist) if ((int) $dentist['id'] === $doctorId) $doctorName = (string) $dentist['name'];
$days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
$weekOrder = [1,2,3,4,5,6,0];
$canEditAvailability = is_admin() || ($isDentist && $doctorId === (int) current_user()['id']);
$error = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    try {
        verify_csrf();
        if (!$canEditAvailability) {
            http_response_code(403);
            exit('This doctor schedule is read-only. Switch to the Administrator role or an assigned Dentist role.');
        }
        if ($branchId < 1 || $doctorId < 1) throw new RuntimeException('Select a clinic branch and dentist.');
        if ($isDentist && $doctorId !== (int) current_user()['id']) throw new RuntimeException('You may only edit your own availability.');
        $action = (string) ($_POST['action'] ?? 'add_rule');

        if ($action === 'add_rule') {
            $day = (int) ($_POST['day_of_week'] ?? -1);
            $start = trim((string) ($_POST['start_time'] ?? ''));
            $end = trim((string) ($_POST['end_time'] ?? ''));
            $from = (string) ($_POST['effective_from'] ?? date('Y-m-d'));
            $until = trim((string) ($_POST['effective_until'] ?? ''));
            if ($day < 0 || $day > 6 || $start === '' || $end === '' || time_minutes($end) <= time_minutes($start)) throw new RuntimeException('Enter a valid day and time range.');
            $hourQuery = $pdo->prepare('SELECT * FROM `' . table('branch_operating_hours') . '` WHERE branch_id=? AND day_of_week=? LIMIT 1');
            $hourQuery->execute([$branchId,$day]);
            $branchHours = $hourQuery->fetch();
            if (!$branchHours || !(bool) $branchHours['is_open']) throw new RuntimeException($days[$day] . ' is closed for this branch.');
            if (time_minutes($start) < time_minutes((string) $branchHours['open_time']) || time_minutes($end) > time_minutes((string) $branchHours['close_time'])) {
                throw new RuntimeException('Doctor availability must remain within ' . date('g:i A',strtotime((string) $branchHours['open_time'])) . '–' . date('g:i A',strtotime((string) $branchHours['close_time'])) . '.');
            }
            if (strtotime($from) === false || ($until !== '' && strtotime($until) < strtotime($from))) throw new RuntimeException('Enter valid effective dates.');
            $overlap = $pdo->prepare('SELECT COUNT(*) FROM `' . table('doctor_availability_rules') . '` WHERE doctor_user_id=? AND branch_id=? AND day_of_week=? AND status<>"inactive" AND start_time<? AND end_time>? AND effective_from<=? AND (effective_until IS NULL OR effective_until>=?)');
            $overlap->execute([$doctorId,$branchId,$day,$end,$start,$until !== '' ? $until : '9999-12-31',$from]);
            if ((int) $overlap->fetchColumn() > 0) throw new RuntimeException('This time overlaps another active availability block.');
            $pdo->prepare('INSERT INTO `' . table('doctor_availability_rules') . '` (doctor_user_id,branch_id,day_of_week,start_time,end_time,effective_from,effective_until,status,created_by,approved_by,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,NOW())')
                ->execute([$doctorId,$branchId,$day,$start,$end,$from,$until ?: null,'active',current_user()['id'],is_admin() ? current_user()['id'] : null]);
            audit('doctor_availability_rule_created','doctor',$doctorId,['day'=>$day,'start'=>$start,'end'=>$end]);
            flash('success','Availability block saved.');
        } elseif ($action === 'delete_rule') {
            $id = (int) ($_POST['rule_id'] ?? 0);
            $pdo->prepare('UPDATE `' . table('doctor_availability_rules') . '` SET status="inactive",updated_at=NOW() WHERE id=? AND doctor_user_id=? AND branch_id=?')->execute([$id,$doctorId,$branchId]);
            audit('doctor_availability_rule_disabled','doctor',$doctorId,['rule_id'=>$id]);
            flash('success','Availability block removed. Existing appointments were preserved.');
        } elseif ($action === 'add_exception') {
            $date = (string) ($_POST['exception_date'] ?? '');
            $type = (string) ($_POST['exception_type'] ?? 'unavailable');
            $allDay = isset($_POST['all_day']);
            $start = trim((string) ($_POST['exception_start'] ?? ''));
            $end = trim((string) ($_POST['exception_end'] ?? ''));
            if (strtotime($date) === false) throw new RuntimeException('Select a valid exception date.');
            if (!in_array($type,['unavailable','special_availability','leave','break','training','closure'],true)) throw new RuntimeException('Invalid exception type.');
            $dateHours = branch_hours_for_date($branchId,$date);
            if ($type === 'special_availability' && !$dateHours) throw new RuntimeException('The clinic is closed on this date. Add a branch special opening first.');
            if (!$allDay) {
                if ($start === '' || $end === '' || time_minutes($end) <= time_minutes($start)) throw new RuntimeException('Enter a valid exception time.');
                if ($dateHours && (time_minutes($start) < time_minutes($dateHours['open_time']) || time_minutes($end) > time_minutes($dateHours['close_time']))) throw new RuntimeException('The exception time must remain inside clinic operating hours.');
            }
            $pdo->prepare('INSERT INTO `' . table('doctor_availability_exceptions') . '` (doctor_user_id,branch_id,exception_date,exception_type,start_time,end_time,all_day,reason,status,created_by,approved_by,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,NOW())')
                ->execute([$doctorId,$branchId,$date,$type,$allDay ? null : $start,$allDay ? null : $end,$allDay ? 1 : 0,trim((string) ($_POST['reason'] ?? '')) ?: null,'active',current_user()['id'],is_admin() ? current_user()['id'] : null]);
            audit('doctor_availability_exception_created','doctor',$doctorId,['date'=>$date,'type'=>$type]);
            flash('success','Availability exception saved.');
        } elseif ($action === 'delete_exception') {
            $id = (int) ($_POST['exception_id'] ?? 0);
            $pdo->prepare('UPDATE `' . table('doctor_availability_exceptions') . '` SET status="inactive",updated_at=NOW() WHERE id=? AND doctor_user_id=? AND branch_id=?')->execute([$id,$doctorId,$branchId]);
            audit('doctor_availability_exception_disabled','doctor',$doctorId,['exception_id'=>$id]);
            flash('success','Exception removed.');
        }
        header('Location: availability.php?branch_id=' . $branchId . '&doctor_id=' . $doctorId);
        exit;
    } catch (Throwable $exception) {
        $error = $exception->getMessage();
    }
}

$hours = [];
$stmt = $pdo->prepare('SELECT * FROM `' . table('branch_operating_hours') . '` WHERE branch_id=?');
$stmt->execute([$branchId]);
foreach ($stmt->fetchAll() as $row) $hours[(int) $row['day_of_week']] = $row;

$stmt = $pdo->prepare('SELECT * FROM `' . table('doctor_availability_rules') . '` WHERE doctor_user_id=? AND branch_id=? AND status<>"inactive" ORDER BY day_of_week,start_time');
$stmt->execute([$doctorId,$branchId]);
$rules = $stmt->fetchAll();
$rulesByDay = array_fill(0,7,[]);
foreach ($rules as $rule) $rulesByDay[(int) $rule['day_of_week']][] = $rule;

$stmt = $pdo->prepare('SELECT * FROM `' . table('doctor_availability_exceptions') . '` WHERE doctor_user_id=? AND branch_id=? AND exception_date>=CURDATE() AND status<>"inactive" ORDER BY exception_date,start_time');
$stmt->execute([$doctorId,$branchId]);
$exceptions = $stmt->fetchAll();

$hoursJson = [];
foreach ($hours as $day => $row) $hoursJson[$day] = ['open'=>(bool) $row['is_open'],'start'=>substr((string) $row['open_time'],0,5),'end'=>substr((string) $row['close_time'],0,5)];

render_header($isDentist ? 'My Weekly Schedule' : 'Doctor Weekly Schedule');
?>
<?php if ($error): ?><div class="flash error"><?=e($error)?></div><?php endif; ?>
<div class="toolbar">
    <div><strong><?=e($doctorName ?: 'Select a dentist')?></strong><span class="muted">Click a day tile to prepare a new availability block. Clinic hours remain the maximum allowed schedule.</span></div>
    <?php if (is_admin()): ?><a class="btn ghost" href="operation_hours.php?branch_id=<?=$branchId?>">Operation hours</a><?php endif; ?>
</div>
<form method="get" action="availability.php" class="card compact-filter schedule-filter" data-auto-submit>
    <label>Branch<select name="branch_id"><?php foreach ($branches as $branch): ?><option value="<?=$branch['id']?>" <?=$branchId === (int) $branch['id'] ? 'selected' : ''?>><?=e($branch['name'])?></option><?php endforeach; ?></select></label>
    <?php if (!$isDentist): ?>
        <label>Search dentist<input type="search" data-select-search="doctor-schedule-filter" placeholder="Type dentist name" autocomplete="off"></label>
        <label>Dentist<select id="doctor-schedule-filter" name="doctor_id"><?php foreach ($dentists as $dentist): ?><option value="<?=$dentist['id']?>" <?=$doctorId === (int) $dentist['id'] ? 'selected' : ''?>><?=e($dentist['name'])?></option><?php endforeach; ?></select></label>
    <?php endif; ?>
</form>

<section class="card weekly-schedule-card">
    <div class="card-head"><div><h2>Recurring weekly calendar</h2><p>Each tile shows the doctor’s published availability for that weekday.</p></div><span class="badge"><?=count($rules)?> block<?=count($rules) === 1 ? '' : 's'?></span></div>
    <div class="weekly-schedule-grid">
        <?php foreach ($weekOrder as $dayIndex): $branchDay = $hours[$dayIndex] ?? null; ?>
            <article class="weekly-day-tile <?=!$branchDay || !(bool) $branchDay['is_open'] ? 'closed' : ''?>" data-availability-day-preset="<?=$dayIndex?>" tabindex="0">
                <header><strong><?=e($days[$dayIndex])?></strong><small><?php if ($branchDay && (bool) $branchDay['is_open']): ?><?=e(date('g:i A',strtotime((string) $branchDay['open_time'])) . '–' . date('g:i A',strtotime((string) $branchDay['close_time'])))?><?php else: ?>Clinic closed<?php endif; ?></small></header>
                <div class="weekly-day-blocks">
                    <?php foreach ($rulesByDay[$dayIndex] as $rule): ?>
                        <div class="availability-tile">
                            <div><strong><?=e(date('g:i A',strtotime((string) $rule['start_time'])) . '–' . date('g:i A',strtotime((string) $rule['end_time'])))?></strong><small><?=e(date('M j, Y',strtotime((string) $rule['effective_from'])))?><?= $rule['effective_until'] ? ' to ' . e(date('M j, Y',strtotime((string) $rule['effective_until']))) : ' onward'?></small></div>
                            <?php if ($canEditAvailability): ?><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="delete_rule"><input type="hidden" name="branch_id" value="<?=$branchId?>"><input type="hidden" name="doctor_id" value="<?=$doctorId?>"><input type="hidden" name="rule_id" value="<?=$rule['id']?>"><button class="icon-text-button" type="submit" aria-label="Remove this availability block">×</button></form><?php endif; ?>
                        </div>
                    <?php endforeach; ?>
                    <?php if (!$rulesByDay[$dayIndex]): ?><span class="empty-schedule-slot"><?= $branchDay && (bool) $branchDay['is_open'] ? 'No doctor hours' : 'Unavailable' ?></span><?php endif; ?>
                </div>
            </article>
        <?php endforeach; ?>
    </div>
</section>

<?php if ($canEditAvailability): ?>
<div class="grid two">
    <form method="post" class="card form-grid" data-availability-form data-hours='<?=e(json_encode($hoursJson))?>'>
        <input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="add_rule"><input type="hidden" name="branch_id" value="<?=$branchId?>"><input type="hidden" name="doctor_id" value="<?=$doctorId?>">
        <h2 class="wide">Add weekly availability</h2>
        <label>Day<select name="day_of_week" data-availability-day required><?php foreach ($days as $index => $day): $branchDay = $hours[$index] ?? null; ?><option value="<?=$index?>" <?=(!$branchDay || !$branchDay['is_open']) ? 'disabled' : ''?>><?=e($day)?><?=($branchDay && $branchDay['is_open']) ? ' · ' . e(date('g:i A',strtotime((string) $branchDay['open_time'])) . '–' . date('g:i A',strtotime((string) $branchDay['close_time']))) : ' · Closed'?></option><?php endforeach; ?></select></label>
        <label>Start<input type="time" name="start_time" data-availability-start required></label>
        <label>End<input type="time" name="end_time" data-availability-end required></label>
        <label>Effective from<input type="date" name="effective_from" value="<?=date('Y-m-d')?>" required></label>
        <label>Effective until<input type="date" name="effective_until"></label>
        <div class="wide public-notice" data-availability-note>Select a clinic day to see its allowed time range.</div>
        <button class="btn primary" type="submit">Add availability block</button>
    </form>
    <form method="post" class="card form-grid">
        <input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="add_exception"><input type="hidden" name="branch_id" value="<?=$branchId?>"><input type="hidden" name="doctor_id" value="<?=$doctorId?>">
        <h2 class="wide">Leave, break, or special availability</h2>
        <label>Date<input type="date" name="exception_date" min="<?=date('Y-m-d')?>" required></label>
        <label>Type<select name="exception_type"><option value="unavailable">Unavailable</option><option value="leave">Leave</option><option value="break">Break</option><option value="training">Training</option><option value="closure">Closure</option><option value="special_availability">Special availability</option></select></label>
        <label class="check-label"><input type="checkbox" name="all_day" value="1" data-all-day><span>All day</span></label>
        <label>Start<input type="time" name="exception_start" data-exception-part></label>
        <label>End<input type="time" name="exception_end" data-exception-part></label>
        <label class="wide">Reason<input name="reason" maxlength="255"></label>
        <button class="btn primary" type="submit">Save exception</button>
    </form>
</div>
<?php endif; ?>

<section class="card">
    <div class="card-head"><div><h2>Upcoming exceptions</h2><p>Leave, breaks, training, closure, and special availability override the recurring calendar.</p></div></div>
    <div class="table-wrap"><table><thead><tr><th>Date</th><th>Type</th><th>Time</th><th></th></tr></thead><tbody>
        <?php foreach ($exceptions as $exception): ?><tr><td><?=e(date('M j, Y',strtotime((string) $exception['exception_date'])))?></td><td><?=e(ucwords(str_replace('_',' ',(string) $exception['exception_type'])))?><br><small><?=e((string) $exception['reason'])?></small></td><td><?=$exception['all_day'] ? 'All day' : e(date('g:i A',strtotime((string) $exception['start_time'])) . '–' . date('g:i A',strtotime((string) $exception['end_time'])))?></td><td><?php if ($canEditAvailability): ?><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="delete_exception"><input type="hidden" name="branch_id" value="<?=$branchId?>"><input type="hidden" name="doctor_id" value="<?=$doctorId?>"><input type="hidden" name="exception_id" value="<?=$exception['id']?>"><button class="btn ghost" type="submit">Remove</button></form><?php endif; ?></td></tr><?php endforeach; ?>
        <?php if (!$exceptions): ?><tr><td colspan="4" class="empty-cell">No upcoming exceptions.</td></tr><?php endif; ?>
    </tbody></table></div>
</section>
<?php render_footer(); ?>
