<?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();
$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']??($branches[0]['id']??0));
$branchIds=array_map(static fn(array $row):int=>(int)$row['id'],$branches);
if($branchId<1||!in_array($branchId,$branchIds,true))$branchId=(int)($branches[0]['id']??0);
$ready=inhouse_resource_schema_ready();

function inhouse_team_eligible_staff_role_sql(): string
{
    $primary = 'r.code IN ("dental_assistant","staff")';
    if (!function_exists('user_role_assignments_schema_ready') || !user_role_assignments_schema_ready()) return $primary;
    $expiry = schema_column_exists(table('user_role_assignments'),'expires_at')
        ? ' AND (ura.expires_at IS NULL OR ura.expires_at>NOW())'
        : '';
    return '(' . $primary . ' OR EXISTS('
        . 'SELECT 1 FROM `' . table('user_role_assignments') . '` ura '
        . 'JOIN `' . table('roles') . '` rr ON rr.id=ura.role_id '
        . 'WHERE ura.user_id=u.id AND ura.status="active"' . $expiry
        . ' AND rr.code IN ("dental_assistant","staff")'
        . '))';
}

function inhouse_team_valid_staff_ids(PDO $pdo,int $branchId,array $staffIds): array
{
    $staffIds=array_values(array_unique(array_filter(array_map('intval',$staffIds),static fn(int $id):bool=>$id>0)));
    if(!$staffIds)return [];
    $marks=implode(',',array_fill(0,count($staffIds),'?'));
    $stmt=$pdo->prepare('SELECT u.id FROM `' . table('users') . '` u JOIN `' . table('roles') . '` r ON r.id=u.role_id WHERE u.id IN ('.$marks.') AND u.status="active" AND (u.branch_id=? OR u.branch_id IS NULL) AND '.inhouse_team_eligible_staff_role_sql());
    $stmt->execute(array_merge($staffIds,[$branchId]));
    $valid=array_map('intval',$stmt->fetchAll(PDO::FETCH_COLUMN));sort($staffIds);sort($valid);
    if($staffIds!==$valid)throw new RuntimeException('One or more selected users are not eligible active staff for this branch.');
    return $staffIds;
}

function inhouse_team_valid_services(PDO $pdo,int $branchId,array $serviceIds): array
{
    $serviceIds=array_values(array_unique(array_filter(array_map('intval',$serviceIds),static fn(int $id):bool=>$id>0)));
    if(!$serviceIds)throw new RuntimeException('Select at least one in-house service.');
    $marks=implode(',',array_fill(0,count($serviceIds),'?'));
    $stmt=$pdo->prepare('SELECT id,name FROM `' . table('service_catalog') . '` WHERE id IN ('.$marks.') AND is_active=1 AND provider_type="inhouse" AND (branch_id=? OR branch_id IS NULL)');
    $stmt->execute(array_merge($serviceIds,[$branchId]));
    $rows=$stmt->fetchAll();$valid=array_map(static fn(array $row):int=>(int)$row['id'],$rows);sort($serviceIds);sort($valid);
    if($serviceIds!==$valid)throw new RuntimeException('One or more selected services are inactive or unavailable for this branch.');
    return $rows;
}

function inhouse_team_matching_services(PDO $pdo,int $branchId,string $query,string $assignmentFilter,string $chairFilter): array
{
    $assignmentFilter=in_array($assignmentFilter,['','assigned','fallback'],true)?$assignmentFilter:'';
    $chairFilter=in_array($chairFilter,['','required','not_required'],true)?$chairFilter:'';
    $where=['s.is_active=1','s.provider_type="inhouse"','(s.branch_id=? OR s.branch_id IS NULL)'];
    $args=[$branchId];
    $query=trim($query);
    if($query!==''){
        $where[]='(s.name LIKE ? OR s.description LIKE ? OR s.provider_role_code LIKE ?)';
        $term=module_like_term($query);array_push($args,$term,$term,$term);
    }
    if($assignmentFilter==='assigned'){
        $where[]='EXISTS(SELECT 1 FROM `' . table('inhouse_service_staff') . '` iss WHERE iss.service_id=s.id AND iss.branch_id=? AND iss.is_active=1)';
        $args[]=$branchId;
    }elseif($assignmentFilter==='fallback'){
        $where[]='NOT EXISTS(SELECT 1 FROM `' . table('inhouse_service_staff') . '` iss WHERE iss.service_id=s.id AND iss.branch_id=? AND iss.is_active=1)';
        $args[]=$branchId;
    }
    if($chairFilter==='required')$where[]='s.requires_chair=1';
    elseif($chairFilter==='not_required')$where[]='s.requires_chair=0';
    $stmt=$pdo->prepare('SELECT s.id,s.name FROM `' . table('service_catalog') . '` s WHERE '.implode(' AND ',$where).' ORDER BY s.name');
    $stmt->execute($args);
    return $stmt->fetchAll();
}

if($_SERVER['REQUEST_METHOD']==='POST'){
    try{
        verify_csrf();
        if(!$ready)throw new RuntimeException('Apply Version 0.5.8.4 before assigning in-house care teams.');
        $action=(string)($_POST['action']??'');
        $supported=['save_assignments','bulk_apply_scope','bulk_clear_scope','bulk_assign','bulk_clear','bulk_assign_all','bulk_clear_all'];
        if(!in_array($action,$supported,true))throw new RuntimeException('Unsupported in-house team action.');

        $clear=in_array($action,['bulk_clear_scope','bulk_clear','bulk_clear_all'],true);
        if($action==='save_assignments'){
            $scope='single';
            $services=inhouse_team_valid_services($pdo,$branchId,[(int)($_POST['service_id']??0)]);
        }else{
            $scope=(string)($_POST['bulk_scope']??'selected');
            if(in_array($action,['bulk_assign_all','bulk_clear_all'],true))$scope='filtered';
            elseif(in_array($action,['bulk_assign','bulk_clear'],true))$scope='selected';
            if(!in_array($scope,['selected','filtered','branch'],true))$scope='selected';

            if($scope==='branch'){
                $services=inhouse_team_matching_services($pdo,$branchId,'','','');
            }elseif($scope==='filtered'){
                $services=inhouse_team_matching_services(
                    $pdo,
                    $branchId,
                    (string)($_POST['bulk_q']??''),
                    (string)($_POST['bulk_assignment']??''),
                    (string)($_POST['bulk_chair']??'')
                );
            }else{
                $services=inhouse_team_valid_services($pdo,$branchId,(array)($_POST['service_ids']??[]));
            }
        }
        if(!$services)throw new RuntimeException('No active in-house services are available in the selected scope.');

        $staffIds=$clear?[]:inhouse_team_valid_staff_ids($pdo,$branchId,(array)($_POST['staff_ids']??[]));
        if(!$clear&&!$staffIds)throw new RuntimeException('Select at least one eligible Dental Assistant or General Staff account.');

        $pdo->beginTransaction();
        $delete=$pdo->prepare('DELETE FROM `' . table('inhouse_service_staff') . '` WHERE branch_id=? AND service_id=?');
        $insert=$pdo->prepare('INSERT INTO `' . table('inhouse_service_staff') . '` (branch_id,service_id,user_id,is_active,created_by,created_at) VALUES (?,?,?,1,?,NOW())');
        foreach($services as $service){
            $serviceId=(int)$service['id'];
            $delete->execute([$branchId,$serviceId]);
            foreach($staffIds as $staffId)$insert->execute([$branchId,$serviceId,$staffId,(int)current_user()['id']]);
            audit('inhouse_service_team_updated','service',$serviceId,[
                'branch_id'=>$branchId,
                'service_name'=>(string)$service['name'],
                'staff_ids'=>$staffIds,
                'scope'=>$scope??'single',
                'bulk'=>count($services)>1,
            ]);
        }
        $pdo->commit();
        $count=count($services);
        flash('success',$clear
            ? $count.' service'.($count===1?'':'s').' returned to fallback-role staffing.'
            : 'Assigned the selected team to '.$count.' service'.($count===1?'':'s').'.');
        $return=['branch_id'=>$branchId];
        foreach(['bulk_q'=>'q','bulk_assignment'=>'assignment','bulk_chair'=>'chair'] as $postKey=>$queryKey){
            $value=trim((string)($_POST[$postKey]??''));if($value!=='')$return[$queryKey]=$value;
        }
        header('Location: inhouse_team.php?'.http_build_query($return));exit;
    }catch(Throwable $e){
        if($pdo->inTransaction())$pdo->rollBack();
        flash('error',$e->getMessage());
        header('Location: inhouse_team.php?branch_id='.$branchId);exit;
    }
}

$state=module_management_state();$q=$state['query'];$assignmentFilter=module_safe_status_filter('assignment',['','assigned','fallback']);$chairFilter=module_safe_status_filter('chair',['','required','not_required']);
$staff=[];$sharedChairCount=0;$futureMissing=0;$total=0;$branchServiceTotal=0;$services=[];$selectedService=null;$selectedStaff=[];$assignments=[];
if($branchId>0&&$ready){
    $staffStmt=$pdo->prepare('SELECT DISTINCT u.id,u.name,u.email,u.branch_id,r.code role_code,r.name role_name FROM `' . table('users') . '` u JOIN `' . table('roles') . '` r ON r.id=u.role_id WHERE u.status="active" AND (u.branch_id=? OR u.branch_id IS NULL) AND '.inhouse_team_eligible_staff_role_sql().' ORDER BY r.name,u.name');$staffStmt->execute([$branchId]);$staff=$staffStmt->fetchAll();
    $branchServiceTotal=count(inhouse_team_matching_services($pdo,$branchId,'','',''));
    $chairStmt=$pdo->prepare('SELECT COUNT(*) FROM `' . table('clinic_chairs') . '` WHERE branch_id=? AND usage_mode="shared_inhouse" AND status="available"');$chairStmt->execute([$branchId]);$sharedChairCount=(int)$chairStmt->fetchColumn();
    $missingStmt=$pdo->prepare('SELECT COUNT(*) FROM `' . table('appointments') . '` WHERE branch_id=? AND provider_type="inhouse" AND start_at>=NOW() AND status NOT IN ("cancelled","no_show") AND (inhouse_provider_user_id IS NULL OR inhouse_provider_user_id=0)');$missingStmt->execute([$branchId]);$futureMissing=(int)$missingStmt->fetchColumn();

    $where=['s.is_active=1','s.provider_type="inhouse"','(s.branch_id=? OR s.branch_id IS NULL)'];$args=[$branchId];
    if($q!==''){$where[]='(s.name LIKE ? OR s.description LIKE ? OR s.provider_role_code LIKE ?)';$term=module_like_term($q);array_push($args,$term,$term,$term);}
    if($assignmentFilter==='assigned')$where[]='EXISTS(SELECT 1 FROM `' . table('inhouse_service_staff') . '` iss WHERE iss.service_id=s.id AND iss.branch_id=? AND iss.is_active=1)';
    elseif($assignmentFilter==='fallback')$where[]='NOT EXISTS(SELECT 1 FROM `' . table('inhouse_service_staff') . '` iss WHERE iss.service_id=s.id AND iss.branch_id=? AND iss.is_active=1)';
    if($assignmentFilter!=='')$args[]=$branchId;
    if($chairFilter==='required')$where[]='s.requires_chair=1';elseif($chairFilter==='not_required')$where[]='s.requires_chair=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'];
    $sql='SELECT s.id,s.name,s.description,s.duration_minutes,s.provider_role_code,s.slot_capacity,s.requires_chair,s.branch_id,(SELECT COUNT(*) FROM `' . table('inhouse_service_staff') . '` iss WHERE iss.service_id=s.id AND iss.branch_id=? AND iss.is_active=1) assigned_count FROM `' . table('service_catalog') . '` s WHERE '.$whereSql.' ORDER BY s.name LIMIT '.$state['per_page'].' OFFSET '.$state['offset'];
    $stmt=$pdo->prepare($sql);$stmt->execute(array_merge([$branchId],$args));$services=$stmt->fetchAll();
    if($state['manage_id']>0){
        $stmt=$pdo->prepare('SELECT s.* FROM `' . table('service_catalog') . '` s WHERE s.id=? AND s.is_active=1 AND s.provider_type="inhouse" AND (s.branch_id=? OR s.branch_id IS NULL) LIMIT 1');$stmt->execute([$state['manage_id'],$branchId]);$selectedService=$stmt->fetch()?:null;
        if($selectedService){$stmt=$pdo->prepare('SELECT user_id FROM `' . table('inhouse_service_staff') . '` WHERE branch_id=? AND service_id=? AND is_active=1');$stmt->execute([$branchId,(int)$selectedService['id']]);$selectedStaff=array_map('intval',$stmt->fetchAll(PDO::FETCH_COLUMN));}
    }
}

render_header('In-house Care Team');
?>
<div class="management-workspace">
<div class="management-toolbar"><div><strong>In-house service accountability</strong><span class="muted">Services inherit their fallback role unless an explicit care team is assigned. Manage one service at a time or apply the same team to selected services.</span></div><div class="inline-actions"><a class="btn ghost" href="services.php">Dental Services</a><a class="btn ghost" href="chairs.php?branch_id=<?=$branchId?>">Chairs &amp; Resources</a></div></div>
<?php if(!$ready):?><section class="card"><h2>Database update required</h2><p>Version 0.5.8.4 must be applied before assigning in-house care teams.</p><?php if(actual_role()==='super_admin'):?><a class="btn primary" href="system_setup.php?tab=updates">Open System Control updates</a><?php else:?><p class="muted">Ask the Superuser to apply the pending update.</p><?php endif;?></section>
<?php elseif(!$branches):?><section class="card"><h2>No active branch</h2><p>Create or activate a clinic branch before assigning service teams.</p></section>
<?php else:?>
<form method="get" class="card management-filters"><label>Search services<input type="search" name="q" value="<?=e($q)?>" placeholder="Service name, description, or fallback role"></label><label>Branch<select name="branch_id"><?php foreach($branches as $branch):?><option value="<?=(int)$branch['id']?>" <?=$branchId===(int)$branch['id']?'selected':''?>><?=e($branch['name'])?></option><?php endforeach;?></select></label><label>Assignment<select name="assignment"><option value="">All</option><option value="assigned" <?=$assignmentFilter==='assigned'?'selected':''?>>Explicit team</option><option value="fallback" <?=$assignmentFilter==='fallback'?'selected':''?>>Fallback role only</option></select></label><label>Chair<select name="chair"><option value="">All</option><option value="required" <?=$chairFilter==='required'?'selected':''?>>Chair required</option><option value="not_required" <?=$chairFilter==='not_required'?'selected':''?>>No chair</option></select></label><div class="filter-actions"><button class="btn primary">Filter</button><a class="btn ghost" href="inhouse_team.php?branch_id=<?=$branchId?>">Reset</a></div></form>
<section class="stats mini-stats"><?php stat_card('In-house services',$total,'Matching this view');stat_card('Eligible staff',count($staff),'Active staff pool');stat_card('Shared chairs',$sharedChairCount,$sharedChairCount?'Available resources':'Chair-required services blocked');stat_card('Legacy unassigned',$futureMissing,$futureMissing?'Future appointments need review':'No missing provider');?></section>
<?php if($futureMissing):?><div class="alert warning"><strong><?=$futureMissing?> future in-house appointment<?= $futureMissing===1?'':'s' ?> still lack<?= $futureMissing===1?'s':'' ?> a responsible staff member.</strong> New and rescheduled bookings will be assigned automatically.</div><?php endif;?>
<form method="post" class="card management-table-card" data-bulk-form>
<input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="branch_id" value="<?=$branchId?>"><input type="hidden" name="bulk_q" value="<?=e($q)?>"><input type="hidden" name="bulk_assignment" value="<?=e($assignmentFilter)?>"><input type="hidden" name="bulk_chair" value="<?=e($chairFilter)?>">
<div class="card-head"><div><h2>Service staffing policies</h2><p>Choose a team once, choose the scope, and apply it in one action.</p></div><?php module_render_list_count($total,'services');?></div>
<section class="card inset-card staffing-bulk-panel">
    <div class="card-head"><div><h3>Bulk team assignment</h3><p>No pop-up and no page-by-page assignment. This action can update every active in-house service in the selected branch.</p></div></div>
    <div class="form-grid">
        <label>Apply to
            <select name="bulk_scope">
                <option value="branch">All active in-house services in this branch (<?=$branchServiceTotal?>)</option>
                <option value="filtered">All services matching the current filters (<?=$total?>)</option>
                <option value="selected">Only checked services on this page</option>
            </select>
        </label>
        <fieldset class="wide"><legend>Responsible Dental Assistant / General Staff team</legend>
            <div class="management-compact-list"><?php foreach($staff as $member):?><label class="permission-row"><input type="checkbox" name="staff_ids[]" value="<?=(int)$member['id']?>"><span><strong><?=e($member['name'])?></strong><small><?=e($member['role_name'])?><?=empty($member['branch_id'])?' · all branches':''?></small></span></label><?php endforeach;?><?php if(!$staff):?><p class="muted">No active Dental Assistant or General Staff account is eligible for this branch.</p><?php endif;?></div>
        </fieldset>
    </div>
    <div class="inline-actions">
        <button class="btn primary" name="action" value="bulk_apply_scope" <?=(!$staff||$branchServiceTotal<1)?'disabled':''?>>Assign team to selected scope</button>
        <button class="btn ghost" name="action" value="bulk_clear_scope" data-confirm="Remove explicit teams from the selected scope and return those services to fallback-role staffing?" <?=$branchServiceTotal<1?'disabled':''?>>Use fallback roles for selected scope</button>
    </div>
    <p class="muted"><small>Staff with an active Dental Assistant or General Staff role are included even when that role is a secondary assignment.</small></p>
</section>
<div class="management-bulk-bar" data-bulk-bar hidden><strong><span data-selected-count>0</span> checked on this page</strong><span class="muted">Choose “Only checked services” above to use this selection.</span></div>
<?php module_render_server_pagination($total,$state['page'],$state['per_page'],'page','per_page','services');?><div class="table-wrap" data-no-pagination><table data-no-pagination="true"><thead><tr><th class="management-checkbox"><input type="checkbox" data-select-all="input[data-row-select]"></th><th>Service</th><th>Fallback rule</th><th>Assigned</th><th>Capacity</th><th>Chair</th><th></th></tr></thead><tbody><?php foreach($services as $service):$blocked=!empty($service['requires_chair'])&&$sharedChairCount<1;?><tr><td class="management-checkbox"><input type="checkbox" name="service_ids[]" value="<?=(int)$service['id']?>" data-row-select></td><td><strong><?=e($service['name'])?></strong><small><?=e((string)($service['description']?:$service['duration_minutes'].'-minute service'))?></small></td><td><?=e(ucwords(str_replace('_',' ',(string)($service['provider_role_code']?:'dental assistant / staff'))))?></td><td><span class="badge <?=((int)$service['assigned_count']>0)?'success':''?>"><?=(int)$service['assigned_count']?> staff</span><small><?=((int)$service['assigned_count']>0)?'Explicit team':'Fallback role'?></small></td><td><?=(int)$service['slot_capacity']?> concurrent</td><td><span class="badge <?=$blocked?'danger':'success'?>"><?=$service['requires_chair']?($blocked?'Unavailable':'Shared chair'):'Not required'?></span></td><td class="management-action-cell"><a class="btn ghost compact" href="<?=e(module_management_url(['manage_id'=>(int)$service['id']]))?>">Manage</a></td></tr><?php endforeach;?><?php if(!$services):?><tr><td colspan="7" class="management-empty">No in-house 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):?><dialog id="manage-service" class="management-dialog" data-auto-open-dialog="manage-service"><form method="post" class="stack-form"><button type="button" class="dialog-close" data-close>×</button><h2><?=e((string)$selectedService['name'])?></h2><input type="hidden" name="csrf" value="<?=e(csrf_token())?>"><input type="hidden" name="action" value="save_assignments"><input type="hidden" name="branch_id" value="<?=$branchId?>"><input type="hidden" name="service_id" value="<?=(int)$selectedService['id']?>"><div class="management-summary"><div><span>Fallback role</span><strong><?=e(ucwords(str_replace('_',' ',(string)($selectedService['provider_role_code']?:'dental assistant / staff'))))?></strong></div><div><span>Capacity</span><strong><?=(int)$selectedService['slot_capacity']?> concurrent</strong></div><div><span>Chair</span><strong><?=$selectedService['requires_chair']?'Required':'Not required'?></strong></div></div><fieldset><legend>Explicit responsible staff</legend><div class="management-compact-list"><?php foreach($staff as $member):?><label class="permission-row"><input type="checkbox" name="staff_ids[]" value="<?=(int)$member['id']?>" <?=in_array((int)$member['id'],$selectedStaff,true)?'checked':''?>><span><strong><?=e($member['name'])?></strong><small><?=e($member['role_name'])?><?=empty($member['branch_id'])?' · all branches':''?></small></span></label><?php endforeach;?><?php if(!$staff):?><p class="muted">No eligible active staff are available.</p><?php endif;?></div></fieldset><button class="btn primary">Save care team</button><a class="btn ghost" href="<?=e(module_management_url(['manage_id'=>null]))?>">Close</a></form></dialog><?php endif;?>
<?php endif;?></div>
<?php render_footer();
