<?php

declare(strict_types=1);

require DENTAL_ROOT . '/app/bootstrap.php';
require_login();
require_roles(['super_admin','clinic_admin']);
require DENTAL_ROOT . '/app/layout.php';
require DENTAL_ROOT . '/app/module_helpers.php';

$pdo = db();
$error = '';
$feeReady = schema_column_exists(table('service_catalog'), 'standard_fee');
$feeIntegrityReady = schema_column_exists(table('service_catalog'), 'fee_status');
$privilegeReady = schema_column_exists(table('service_catalog'), 'required_privilege_code');
$bookingScopeReady = schema_column_exists(table('service_catalog'), 'booking_scope');
$bookingScopeOptions = [
    'public' => 'Publicly requestable',
    'reception' => 'Reception-bookable',
    'dentist_order' => 'Dentist-order only',
    'clinical_intake' => 'Clinical intake only',
    'inhouse_only' => 'In-house staff only',
];
$privilegeRows = schema_table_exists(table('clinical_privileges'))
    ? $pdo->query('SELECT code,name,category FROM `' . table('clinical_privileges') . '` WHERE is_active=1 ORDER BY category,name')->fetchAll()
    : [];
$branches = $pdo->query('SELECT id,name FROM `' . table('branches') . '` WHERE is_active=1 ORDER BY name')->fetchAll();

function service_fee_input(): array
{
    $mode = (string)($_POST['fee_status'] ?? 'unconfigured');
    if (!in_array($mode, ['unconfigured','billable','no_charge'], true)) $mode = 'unconfigured';
    $fee = max(0, round((float)($_POST['standard_fee'] ?? 0), 2));
    $reason = trim((string)($_POST['no_charge_reason'] ?? ''));
    if ($mode === 'billable' && $fee <= 0) throw new RuntimeException('A billable service requires a positive standard fee.');
    if ($mode === 'no_charge' && mb_strlen($reason) < 5) throw new RuntimeException('Explain why this service is intentionally no-charge.');
    if ($mode !== 'billable') $fee = 0.0;
    if ($mode !== 'no_charge') $reason = '';
    return [$mode, $fee, $reason];
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    try {
        verify_csrf();
        $action = (string)($_POST['action'] ?? 'save');
        if ($action === 'save') {
            $name = trim((string)($_POST['name'] ?? ''));
            $duration = (int)($_POST['duration_minutes'] ?? 30);
            $prep = max(0, (int)($_POST['preparation_minutes'] ?? 0));
            $cleanup = max(0, (int)($_POST['cleanup_minutes'] ?? 0));
            $providerType = (string)($_POST['provider_type'] ?? 'dentist');
            $providerRole = trim((string)($_POST['provider_role_code'] ?? '')) ?: null;
            $requiredPrivilege = $providerType === 'dentist' ? (trim((string)($_POST['required_privilege_code'] ?? '')) ?: 'consultation') : null;
            $capacity = max(1, min(50, (int)($_POST['slot_capacity'] ?? 1)));
            $bookingScope = (string)($_POST['booking_scope'] ?? 'public');
            if (!array_key_exists($bookingScope, $bookingScopeOptions)) throw new RuntimeException('Select a valid booking scope.');
            $isPublic = $bookingScope === 'public' ? 1 : 0;
            $requiresChair = $providerType === 'dentist' ? 1 : (isset($_POST['requires_chair']) ? 1 : 0);
            if ($name === '' || $duration < 5 || $duration > 480) throw new RuntimeException('Enter a service name and a duration from 5 to 480 minutes.');
            if (!in_array($providerType, ['dentist','inhouse'], true)) throw new RuntimeException('Select a valid provider model.');
            if ($providerType === 'dentist') {
                $providerRole = 'dentist';
                $capacity = 1;
                $requiresChair = 1;
            } else {
                $requiredPrivilege = null;
            }
            [$feeStatus, $standardFee, $noChargeReason] = service_fee_input();
            if (!$feeIntegrityReady) {
                $feeStatus = $standardFee > 0 ? 'billable' : 'unconfigured';
                $noChargeReason = '';
            }

            if ($feeIntegrityReady && $privilegeReady && $bookingScopeReady) {
                $pdo->prepare(
                    'INSERT INTO `' . table('service_catalog') . '` '
                    . '(branch_id,name,description,duration_minutes,standard_fee,fee_status,no_charge_reason,fee_authorized_by,fee_authorized_at,preparation_minutes,cleanup_minutes,provider_type,provider_role_code,required_privilege_code,slot_capacity,requires_chair,is_public,booking_scope,is_active,created_at) '
                    . 'VALUES (?,?,?,?,?,?,?,?,NOW(),?,?,?,?,?,?,?,?,?,1,NOW())'
                )->execute([
                    (int)($_POST['branch_id'] ?? 0) ?: null, $name, trim((string)($_POST['description'] ?? '')) ?: null,
                    $duration, $standardFee, $feeStatus, $noChargeReason ?: null, (int)(current_user()['id'] ?? 0),
                    $prep, $cleanup, $providerType, $providerRole, $requiredPrivilege, $capacity, $requiresChair,
                    $isPublic, $bookingScope,
                ]);
            } elseif ($feeReady && $privilegeReady && $bookingScopeReady) {
                $pdo->prepare(
                    'INSERT INTO `' . table('service_catalog') . '` '
                    . '(branch_id,name,description,duration_minutes,standard_fee,preparation_minutes,cleanup_minutes,provider_type,provider_role_code,required_privilege_code,slot_capacity,requires_chair,is_public,booking_scope,is_active,created_at) '
                    . 'VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,1,NOW())'
                )->execute([
                    (int)($_POST['branch_id'] ?? 0) ?: null, $name, trim((string)($_POST['description'] ?? '')) ?: null,
                    $duration, $standardFee, $prep, $cleanup, $providerType, $providerRole, $requiredPrivilege,
                    $capacity, $requiresChair, $isPublic, $bookingScope,
                ]);
            } else {
                throw new RuntimeException('Apply the pending database update before adding services.');
            }
            $id = (int)$pdo->lastInsertId();
            audit('service_created', 'service', $id, ['name'=>$name,'provider_type'=>$providerType,'fee_status'=>$feeStatus,'standard_fee'=>$standardFee,'booking_scope'=>$bookingScope]);
            flash('success', $feeStatus === 'unconfigured'
                ? 'Service added, but treatment finalization remains blocked until its fee is configured.'
                : 'Service and approved billing policy saved.');
        } elseif ($action === 'update_details') {
            $id = (int)($_POST['id'] ?? 0);
            $name = trim((string)($_POST['name'] ?? ''));
            $description = trim((string)($_POST['description'] ?? ''));
            $duration = (int)($_POST['duration_minutes'] ?? 30);
            $prep = max(0, (int)($_POST['preparation_minutes'] ?? 0));
            $cleanup = max(0, (int)($_POST['cleanup_minutes'] ?? 0));
            $branchInput = (int)($_POST['branch_id'] ?? 0);
            $branchValue = $branchInput > 0 ? $branchInput : null;
            if ($id < 1) throw new RuntimeException('Select a service to edit.');
            if ($name === '' || $duration < 5 || $duration > 480) throw new RuntimeException('Enter a service name and a duration from 5 to 480 minutes.');
            if ($prep > 120 || $cleanup > 120) throw new RuntimeException('Preparation and cleanup buffers cannot exceed 120 minutes each.');
            if ($branchValue !== null) {
                $branchCheck = $pdo->prepare('SELECT COUNT(*) FROM `' . table('branches') . '` WHERE id=? AND is_active=1');
                $branchCheck->execute([$branchValue]);
                if ((int)$branchCheck->fetchColumn() < 1) throw new RuntimeException('Selected branch is not active.');
            }
            $oldStmt = $pdo->prepare('SELECT * FROM `' . table('service_catalog') . '` WHERE id=? LIMIT 1');
            $oldStmt->execute([$id]);
            $old = $oldStmt->fetch();
            if (!$old) throw new RuntimeException('Service not found.');
            $pdo->prepare('UPDATE `' . table('service_catalog') . '` SET branch_id=?,name=?,description=?,duration_minutes=?,preparation_minutes=?,cleanup_minutes=?,updated_at=NOW() WHERE id=?')
                ->execute([$branchValue,$name,$description !== '' ? $description : null,$duration,$prep,$cleanup,$id]);
            audit('service_details_updated', 'service', $id, ['name'=>$name,'duration_minutes'=>$duration,'branch_id'=>$branchValue], $old);
            flash('success','Service details updated. Existing appointments, invoices, and historical records were preserved.');
        } elseif ($action === 'update_fee') {
            if (!$feeIntegrityReady) throw new RuntimeException('Apply Version 0.5.9.8.15 before setting the clinical billing policy.');
            $id = (int)($_POST['id'] ?? 0);
            [$feeStatus, $fee, $reason] = service_fee_input();
            $pdo->prepare(
                'UPDATE `' . table('service_catalog') . '` SET standard_fee=?,fee_status=?,no_charge_reason=?,fee_authorized_by=?,fee_authorized_at=NOW(),updated_at=NOW() WHERE id=?'
            )->execute([$fee, $feeStatus, $reason ?: null, (int)(current_user()['id'] ?? 0), $id]);
            audit('service_fee_policy_updated', 'service', $id, ['fee_status'=>$feeStatus,'standard_fee'=>$fee,'no_charge_reason'=>$reason ?: null]);
            flash('success', $feeStatus === 'billable' ? 'Approved standard fee updated.' : ($feeStatus === 'no_charge' ? 'No-charge authorization saved.' : 'Fee marked unconfigured; related treatment cannot be finalized.'));
        } elseif ($action === 'update_scope') {
            if (!$bookingScopeReady) throw new RuntimeException('Apply Version 0.5.9.8.32 before editing booking scope.');
            $id = (int)($_POST['id'] ?? 0);
            $bookingScope = (string)($_POST['booking_scope'] ?? 'reception');
            if (!array_key_exists($bookingScope, $bookingScopeOptions)) throw new RuntimeException('Select a valid booking scope.');
            $isPublic = $bookingScope === 'public' ? 1 : 0;
            $pdo->prepare('UPDATE `' . table('service_catalog') . '` SET booking_scope=?,is_public=?,updated_at=NOW() WHERE id=?')->execute([$bookingScope,$isPublic,$id]);
            audit('service_booking_scope_updated','service',$id,['booking_scope'=>$bookingScope,'is_public'=>$isPublic]);
            flash('success','Service booking scope updated.');
        } elseif ($action === 'toggle') {
            $id = (int)($_POST['id'] ?? 0);
            $pdo->prepare('UPDATE `' . table('service_catalog') . '` SET is_active=IF(is_active=1,0,1),updated_at=NOW() WHERE id=?')->execute([$id]);
            audit('service_toggled', 'service', $id);
            flash('success', 'Service status changed.');
        } elseif ($action === 'update_provider') {
            $id = (int)($_POST['id'] ?? 0);
            $providerType = (string)($_POST['provider_type'] ?? 'dentist');
            $capacity = max(1, min(50, (int)($_POST['slot_capacity'] ?? 1)));
            $providerRole = trim((string)($_POST['provider_role_code'] ?? '')) ?: null;
            $requiredPrivilege = $providerType === 'dentist' ? (trim((string)($_POST['required_privilege_code'] ?? '')) ?: 'consultation') : null;
            if (!in_array($providerType, ['dentist','inhouse'], true)) throw new RuntimeException('Select a valid provider model.');
            $requiresChair = $providerType === 'dentist' ? 1 : (isset($_POST['requires_chair']) ? 1 : 0);
            if ($providerType === 'dentist') {
                $capacity = 1;
                $providerRole = 'dentist';
            } else {
                $requiredPrivilege = null;
            }
            if ($privilegeReady) {
                $pdo->prepare('UPDATE `' . table('service_catalog') . '` SET provider_type=?,provider_role_code=?,required_privilege_code=?,slot_capacity=?,requires_chair=?,updated_at=NOW() WHERE id=?')
                    ->execute([$providerType,$providerRole,$requiredPrivilege,$capacity,$requiresChair,$id]);
            } else {
                $pdo->prepare('UPDATE `' . table('service_catalog') . '` SET provider_type=?,provider_role_code=?,slot_capacity=?,requires_chair=?,updated_at=NOW() WHERE id=?')
                    ->execute([$providerType,$providerRole,$capacity,$requiresChair,$id]);
            }
            audit('service_provider_model_updated', 'service', $id, ['provider_type'=>$providerType,'slot_capacity'=>$capacity,'requires_chair'=>$requiresChair]);
            flash('success', 'Service provider model updated. Existing appointments are not reassigned automatically.');
        } elseif ($action === 'bulk_status') {
            $ids=array_values(array_unique(array_filter(array_map('intval',(array)($_POST['service_ids']??[])))));
            $status=(string)($_POST['bulk_status']??'');
            if(!$ids) throw new RuntimeException('Select at least one service.');
            if(!in_array($status,['active','inactive'],true)) throw new RuntimeException('Select a valid service status.');
            $marks=implode(',',array_fill(0,count($ids),'?'));
            $pdo->prepare('UPDATE `' . table('service_catalog') . '` SET is_active=?,updated_at=NOW() WHERE id IN ('.$marks.')')->execute(array_merge([$status==='active'?1:0],$ids));
            foreach($ids as $serviceId) audit('service_bulk_status_updated','service',$serviceId,['status'=>$status]);
            flash('success',count($ids).' service'.(count($ids)===1?'':'s').' updated.');
        } else {
            throw new RuntimeException('Unsupported service action.');
        }
        header('Location: services.php');
        exit;
    } catch (Throwable $exception) {
        $error = $exception->getMessage();
    }
}

$providerSelect = schema_column_exists(table('service_catalog'), 'provider_type')
    ? 's.provider_type,s.provider_role_code,s.slot_capacity,s.requires_chair' . ($privilegeReady ? ',s.required_privilege_code' : ',NULL required_privilege_code')
    : '"dentist" provider_type,"dentist" provider_role_code,1 slot_capacity,1 requires_chair,NULL required_privilege_code';
$state=module_management_state();$q=$state['query'];
$providerFilter=module_safe_status_filter('provider',['','dentist','inhouse']);
$feeFilter=module_safe_status_filter('fee',['','billable','no_charge','unconfigured']);
$statusFilter=module_safe_status_filter('status',['','active','inactive']);
$branchFilter=max(0,(int)($_GET['branch_id']??0));
$where=['1=1'];$args=[];
if($q!==''){$term=module_like_term($q);$where[]='(s.name LIKE ? OR s.description LIKE ? OR s.provider_role_code LIKE ?)';array_push($args,$term,$term,$term);}
if($providerFilter!==''){$where[]='s.provider_type=?';$args[]=$providerFilter;}
if($statusFilter!==''){$where[]='s.is_active=?';$args[]=$statusFilter==='active'?1:0;}
if($branchFilter>0){$where[]='s.branch_id=?';$args[]=$branchFilter;}
if($feeFilter!==''){
    if($feeIntegrityReady){$where[]='COALESCE(s.fee_status,"unconfigured")=?';$args[]=$feeFilter;}
    elseif($feeFilter==='billable')$where[]='COALESCE(s.standard_fee,0)>0';
    elseif($feeFilter==='unconfigured')$where[]='COALESCE(s.standard_fee,0)<=0';
    else $where[]='1=0';
}
$whereSql=implode(' AND ',$where);
$count=$pdo->prepare('SELECT COUNT(*) FROM `' . table('service_catalog') . '` s WHERE '.$whereSql);$count->execute($args);$total=(int)$count->fetchColumn();
$pages=max(1,(int)ceil($total/$state['per_page']));$state['page']=min($state['page'],$pages);$state['offset']=($state['page']-1)*$state['per_page'];
$stmt=$pdo->prepare('SELECT s.*,' . $providerSelect . ',b.name branch_name FROM `' . table('service_catalog') . '` s LEFT JOIN `' . table('branches') . '` b ON b.id=s.branch_id WHERE '.$whereSql.' ORDER BY s.is_active DESC,s.provider_type,s.name LIMIT '.$state['per_page'].' OFFSET '.$state['offset']);$stmt->execute($args);$rows=$stmt->fetchAll();
$selectedService=null;
if($state['manage_id']>0){$stmt=$pdo->prepare('SELECT s.*,' . $providerSelect . ',b.name branch_name FROM `' . table('service_catalog') . '` s LEFT JOIN `' . table('branches') . '` b ON b.id=s.branch_id WHERE s.id=? LIMIT 1');$stmt->execute([$state['manage_id']]);$selectedService=$stmt->fetch()?:null;}

render_header('Dental Services');
?>
<div class="management-workspace">
<?php if ($error): ?><div class="flash error"><?=e($error)?></div><?php endif; ?>
<div class="management-toolbar"><div><strong>Service catalog</strong><span class="muted">Every clinical service must have a positive approved fee or an explicit no-charge authorization. Detailed forms open only for the selected service.</span></div><div class="button-row"><a class="btn ghost" href="inhouse_team.php">In-house Care Team</a><button class="btn primary" data-open="service-form">Add service</button></div></div>
<?php if (!$feeIntegrityReady || !$bookingScopeReady): ?><div class="alert warning"><strong>Update required.</strong> Apply all pending System Setup updates, including Version 0.5.9.8.32, before adding or changing service booking access.</div><?php endif; ?>
<div class="alert"><strong>Billing rule:</strong> Dentists select these services during treatment. The approved fee snapshot is sent to Cashier automatically.</div>
<form method="get" class="card management-filters"><label>Search services<input type="search" name="q" value="<?=e($q)?>" placeholder="Name, description, or fallback role"></label><label>Provider<select name="provider"><option value="">All</option><option value="dentist" <?=$providerFilter==='dentist'?'selected':''?>>Dentist</option><option value="inhouse" <?=$providerFilter==='inhouse'?'selected':''?>>In-house team</option></select></label><label>Billing policy<select name="fee"><option value="">All</option><option value="billable" <?=$feeFilter==='billable'?'selected':''?>>Billable</option><option value="no_charge" <?=$feeFilter==='no_charge'?'selected':''?>>Authorized no-charge</option><option value="unconfigured" <?=$feeFilter==='unconfigured'?'selected':''?>>Fee incomplete</option></select></label><label>Status<select name="status"><option value="">All</option><option value="active" <?=$statusFilter==='active'?'selected':''?>>Active</option><option value="inactive" <?=$statusFilter==='inactive'?'selected':''?>>Inactive</option></select></label><label>Branch<select name="branch_id"><option value="">All branches</option><?php foreach($branches as $branch):?><option value="<?=(int)$branch['id']?>" <?=$branchFilter===(int)$branch['id']?'selected':''?>><?=e($branch['name'])?></option><?php endforeach;?></select></label><div class="filter-actions"><button class="btn primary">Filter</button><a class="btn ghost" href="services.php">Reset</a></div></form>
<form method="post" class="card management-table-card" data-bulk-form><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="bulk_status"><div class="card-head"><div><h2>Services</h2><p>One row per service; one management panel for the selected record.</p></div><?php module_render_list_count($total,'services');?></div><div class="management-bulk-bar" data-bulk-bar hidden><strong><span data-selected-count>0</span> selected</strong><div class="management-bulk-actions"><select name="bulk_status"><option value="active">Enable selected</option><option value="inactive">Disable selected</option></select><button class="btn ghost" data-requires-selection>Apply</button></div></div><?php module_render_server_pagination($total,$state['page'],$state['per_page'],'page','per_page','services');?><div class="table-wrap"><table><thead><tr><th class="management-checkbox"><input type="checkbox" data-select-all="input[data-row-select]"></th><th>Service</th><th>Branch</th><th>Provider</th><th>Duration</th><th>Billing</th><th>Capacity / chair</th><th>Booking scope</th><th>Status</th><th></th></tr></thead><tbody>
<?php foreach($rows as $row):$inhouse=($row['provider_type']??'dentist')==='inhouse';$feeStatus=$feeIntegrityReady?(string)($row['fee_status']??'unconfigured'):((float)($row['standard_fee']??0)>0?'billable':'unconfigured');?><tr><td class="management-checkbox"><input type="checkbox" name="service_ids[]" value="<?=(int)$row['id']?>" data-row-select></td><td><strong><?=e($row['name'])?></strong><small><?=e((string)$row['description'])?></small></td><td><?=e($row['branch_name']??'All branches')?></td><td><span class="badge <?=$inhouse?'success':''?>"><?=$inhouse?'In-house team':'Dentist'?></span><small><?=$inhouse?e(ucwords(str_replace('_',' ',(string)($row['provider_role_code']?:'staff')))):'Privilege: '.e(ucwords(str_replace('_',' ',(string)($row['required_privilege_code']?:'consultation'))))?></small></td><td><?=(int)$row['duration_minutes']?> min<small><?=(int)$row['preparation_minutes']?> before · <?=(int)$row['cleanup_minutes']?> after</small></td><td><?php if($feeStatus==='billable'):?><span class="badge success">Billable</span><strong>₱<?=number_format((float)$row['standard_fee'],2)?></strong><?php elseif($feeStatus==='no_charge'):?><span class="badge">No-charge</span><small><?=e((string)($row['no_charge_reason']??''))?></small><?php else:?><span class="badge danger">Fee incomplete</span><small>Finalization blocked</small><?php endif;?></td><td><?=$inhouse?(int)$row['slot_capacity'].' concurrent':'1 Dentist'?><small><?=$row['requires_chair']?'Chair required':'No chair'?></small></td><td><span class="badge"><?=e($bookingScopeOptions[(string)($row['booking_scope']??((int)$row['is_public']===1?'public':'reception'))]??'Reception-bookable')?></span><small><?=((int)$row['is_public']===1?'Visible on public forms':'Hidden from public forms')?></small></td><td><span class="badge"><?=$row['is_active']?'Active':'Inactive'?></span></td><td class="management-action-cell"><a class="btn ghost compact" href="<?=e(module_management_url(['manage_id'=>(int)$row['id']]))?>">Manage</a></td></tr><?php endforeach;?><?php if(!$rows):?><tr><td colspan="10" class="management-empty">No services match this view.</td></tr><?php endif;?></tbody></table></div><?php module_render_server_pagination($total,$state['page'],$state['per_page'],'page','per_page','services');?></form>
<?php if($selectedService):$inhouse=($selectedService['provider_type']??'dentist')==='inhouse';$feeStatus=$feeIntegrityReady?(string)($selectedService['fee_status']??'unconfigured'):((float)($selectedService['standard_fee']??0)>0?'billable':'unconfigured');?><dialog id="manage-service" class="management-dialog" data-auto-open-dialog="manage-service"><div class="management-dialog-body"><button type="button" class="dialog-close" data-close>×</button><h2><?=e((string)$selectedService['name'])?></h2><div class="management-summary"><div><span>Branch</span><strong><?=e((string)($selectedService['branch_name']??'All branches'))?></strong></div><div><span>Duration</span><strong><?=(int)$selectedService['duration_minutes']?> minutes</strong></div><div><span>Status</span><strong><?=$selectedService['is_active']?'Active':'Inactive'?></strong></div></div><h3>Service details</h3><form method="post" class="form-grid"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="update_details"><input type="hidden" name="id" value="<?=(int)$selectedService['id']?>"><label class="wide">Service name<input name="name" maxlength="150" value="<?=e((string)$selectedService['name'])?>" required></label><label>Branch<select name="branch_id"><option value="">All branches</option><?php foreach($branches as $branch):?><option value="<?=(int)$branch['id']?>" <?=((int)($selectedService['branch_id']??0)===(int)$branch['id'])?'selected':''?>><?=e((string)$branch['name'])?></option><?php endforeach;?></select></label><label>Duration minutes<input type="number" name="duration_minutes" min="5" max="480" step="5" value="<?=(int)$selectedService['duration_minutes']?>" required></label><label>Preparation buffer<input type="number" name="preparation_minutes" min="0" max="120" step="5" value="<?=(int)$selectedService['preparation_minutes']?>"></label><label>Cleanup buffer<input type="number" name="cleanup_minutes" min="0" max="120" step="5" value="<?=(int)$selectedService['cleanup_minutes']?>"></label><label class="wide">Description<textarea name="description"><?=e((string)($selectedService['description']??''))?></textarea></label><button class="btn primary">Save service details</button></form><hr><h3>Approved billing policy</h3><form method="post" class="form-grid"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="update_fee"><input type="hidden" name="id" value="<?=(int)$selectedService['id']?>"><label>Policy<select name="fee_status"><option value="billable" <?=$feeStatus==='billable'?'selected':''?>>Billable — approved fee</option><option value="no_charge" <?=$feeStatus==='no_charge'?'selected':''?>>Intentionally no-charge</option><option value="unconfigured" <?=$feeStatus==='unconfigured'?'selected':''?>>Fee incomplete</option></select></label><label>Approved fee<input type="number" name="standard_fee" min="0" step="0.01" value="<?=e(number_format((float)($selectedService['standard_fee']??0),2,'.',''))?>"></label><label class="wide">No-charge reason<textarea name="no_charge_reason"><?=e((string)($selectedService['no_charge_reason']??''))?></textarea></label><button class="btn primary" <?=$feeIntegrityReady?'':'disabled'?>>Save billing policy</button></form><hr><h3>Booking access</h3><form method="post" class="form-grid"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="update_scope"><input type="hidden" name="id" value="<?=(int)$selectedService['id']?>"><label>Booking scope<select name="booking_scope"><?php foreach($bookingScopeOptions as $scopeKey=>$scopeLabel):?><option value="<?=e($scopeKey)?>" <?=($selectedService['booking_scope']??((int)$selectedService['is_public']===1?'public':'reception'))===$scopeKey?'selected':''?>><?=e($scopeLabel)?></option><?php endforeach;?></select></label><p class="wide muted">Public scope is displayed on public appointment forms. Every other scope is automatically hidden from public booking.</p><button class="btn primary" <?=$bookingScopeReady?'':'disabled'?>>Save booking access</button></form><hr><h3>Provider and resource model</h3><form method="post" class="form-grid"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="update_provider"><input type="hidden" name="id" value="<?=(int)$selectedService['id']?>"><label>Provider<select name="provider_type"><option value="dentist" <?=$inhouse?'':'selected'?>>Dentist required</option><option value="inhouse" <?=$inhouse?'selected':''?>>In-house clinic team</option></select></label><?php if($privilegeReady):?><label>Required clinical privilege<select name="required_privilege_code"><option value="consultation">Consultation</option><?php foreach($privilegeRows as $privilege):?><option value="<?=e((string)$privilege['code'])?>" <?=($selectedService['required_privilege_code']??'consultation')===$privilege['code']?'selected':''?>><?=e((string)$privilege['category'].' · '.$privilege['name'])?></option><?php endforeach;?></select></label><?php endif;?><label>Fallback staff role code<input name="provider_role_code" value="<?=e((string)$selectedService['provider_role_code'])?>"></label><label>Concurrent capacity<input type="number" name="slot_capacity" min="1" max="50" value="<?=(int)$selectedService['slot_capacity']?>"></label><label class="wide check-label"><input type="checkbox" name="requires_chair" value="1" <?=$selectedService['requires_chair']?'checked':''?>><span>Requires a treatment chair</span></label><button class="btn primary">Save provider model</button></form><form method="post"><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="toggle"><input type="hidden" name="id" value="<?=(int)$selectedService['id']?>"><button class="btn ghost"><?=$selectedService['is_active']?'Disable service':'Enable service'?></button> <a class="btn ghost" href="<?=e(module_management_url(['manage_id'=>null]))?>">Close</a></form></div></dialog><?php endif;?>
<dialog id="service-form" class="wide-dialog"><form method="post" class="form-grid"><button type="button" class="dialog-close" data-close>×</button><h2 class="wide">Add service</h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="save"><label class="wide">Service name<input name="name" maxlength="150" required></label><label>Branch<select name="branch_id"><option value="">All branches</option><?php foreach($branches as $branch):?><option value="<?=(int)$branch['id']?>"><?=e($branch['name'])?></option><?php endforeach;?></select></label><label>Provider model<select name="provider_type" required><option value="dentist">Dentist required</option><option value="inhouse">In-house clinic team</option></select></label><label>Booking scope<select name="booking_scope" required><?php foreach($bookingScopeOptions as $scopeKey=>$scopeLabel):?><option value="<?=e($scopeKey)?>"><?=e($scopeLabel)?></option><?php endforeach;?></select></label><?php if($privilegeReady):?><label>Required clinical privilege<select name="required_privilege_code"><option value="consultation">Consultation</option><?php foreach($privilegeRows as $privilege):?><option value="<?=e((string)$privilege['code'])?>"><?=e((string)$privilege['category'].' · '.$privilege['name'])?></option><?php endforeach;?></select></label><?php endif;?><label>Fallback staff role code<input name="provider_role_code" maxlength="40"></label><label>Concurrent capacity<input type="number" name="slot_capacity" min="1" max="50" value="1"></label><label>Duration<input type="number" name="duration_minutes" min="5" max="480" step="5" value="30" required></label><label>Billing policy<select name="fee_status"><option value="billable">Billable — approved fee</option><option value="no_charge">Intentionally no-charge</option><option value="unconfigured">Configure later — blocks finalization</option></select></label><label>Approved standard fee<input type="number" name="standard_fee" min="0" step="0.01" value="0.00"></label><label class="wide">No-charge reason<textarea name="no_charge_reason"></textarea></label><label>Preparation buffer<input type="number" name="preparation_minutes" min="0" max="120" step="5" value="0"></label><label>Cleanup buffer<input type="number" name="cleanup_minutes" min="0" max="120" step="5" value="0"></label><label class="wide">Description<textarea name="description"></textarea></label><label class="wide check-label"><input type="checkbox" name="requires_chair" value="1" checked><span>Requires a treatment chair</span></label><p class="wide muted">Choose Publicly requestable to show this service on public appointment forms.</p><button class="btn primary wide">Add service</button></form></dialog></div>
<?php render_footer();
