<?php

/**
 * Shared helpers for working with SSO storage tables.
 */

if (!function_exists('get_nagiosxi_db_type')) {
    function get_nagiosxi_db_type()
    {
        global $cfg;

        $db_info = grab_array_var($cfg['db_info'], 'nagiosxi', array());
        $type = strtolower(grab_array_var($db_info, 'dbtype', 'mysql'));

        if ($type === 'mysqli') {
            $type = 'mysql';
        }

        return $type;
    }
}

if (!function_exists('sso_tables_exist')) {
    function sso_tables_exist()
    {
        global $db_tables;

        if (!isset($db_tables[DB_NAGIOSXI]['sso_mappings']) || !isset($db_tables[DB_NAGIOSXI]['sso_group_config'])) {
            return false;
        }

        $tables = array(
            $db_tables[DB_NAGIOSXI]['sso_mappings'],
            $db_tables[DB_NAGIOSXI]['sso_group_config'],
        );

        foreach ($tables as $table) {
            $sql = "SELECT 1 FROM {$table} LIMIT 1";
            $rs = exec_sql_query(DB_NAGIOSXI, $sql, false, false);

            if (!$rs) {
                return false;
            }
        }

        return true;
    }
}

if (!function_exists('has_configured_sso_users')) {
    function has_configured_sso_users()
    {
        global $db_tables;

        if (!isset($db_tables[DB_NAGIOSXI]['sso_mappings'])) {
            return false;
        }

        $table = $db_tables[DB_NAGIOSXI]['sso_mappings'];
        $sql = "SELECT COUNT(*) as cnt FROM {$table} LIMIT 1";
        $rs = exec_sql_query(DB_NAGIOSXI, $sql, true, false);
        if (!$rs || $rs->EOF) {
            return false;
        }
        return (int)$rs->fields['cnt'] > 0;
    }
}

if (!function_exists('get_sso_mapping')) {
    function get_sso_mapping($object_id, $client_id)
    {
        global $db_tables;

        if (empty($object_id) || empty($client_id)) {
            return null;
        }

        $table = $db_tables[DB_NAGIOSXI]['sso_mappings'];
        $object_id_sql = escape_sql_param($object_id, DB_NAGIOSXI);
        $client_id_sql = escape_sql_param($client_id, DB_NAGIOSXI);
        $db_type = get_nagiosxi_db_type();
        $quote = ($db_type === 'pgsql') ? '' : '`';

        $sql = ($db_type === 'pgsql'
            ? "SELECT * FROM {$table} WHERE object_id = '{$object_id_sql}' AND client_id = '{$client_id_sql}' LIMIT 1"
            : "SELECT * FROM `{$table}` WHERE `object_id` = '{$object_id_sql}' AND `client_id` = '{$client_id_sql}' LIMIT 1");
        $rs = exec_sql_query(DB_NAGIOSXI, $sql, true, false);

        if ($rs && $rs->RecordCount() > 0) {
            return $rs->fields;
        }

        return null;
    }
}

if (!function_exists('create_sso_mapping')) {
    function create_sso_mapping(array $data)
    {
        global $db_tables;

        $required = array('object_id', 'client_id', 'user_id', 'tenant_id');
        foreach ($required as $field) {
            if (!isset($data[$field]) || $data[$field] === '') {
                return false;
            }
        }

        $existing = get_sso_mapping($data['object_id'], $data['client_id']);
        if ($existing) {
            $updateData = $data;
            unset($updateData['object_id'], $updateData['client_id']);
            return update_sso_mapping($data['object_id'], $data['client_id'], $updateData);
        }

        $table = $db_tables[DB_NAGIOSXI]['sso_mappings'];
        $db_type = get_nagiosxi_db_type();
        $object_id = escape_sql_param($data['object_id'], DB_NAGIOSXI);
        $client_id = escape_sql_param($data['client_id'], DB_NAGIOSXI);
        $tenant_id = escape_sql_param($data['tenant_id'], DB_NAGIOSXI);
        $user_id = (int)$data['user_id'];
        $source = escape_sql_param(grab_array_var($data, 'source', 'individual'), DB_NAGIOSXI);
        $priority = escape_sql_param(grab_array_var($data, 'priority', 'individual'), DB_NAGIOSXI);
        $source_group_id = grab_array_var($data, 'source_group_id');
        $source_group_id_sql = is_null($source_group_id) ? 'NULL' : "'" . escape_sql_param($source_group_id, DB_NAGIOSXI) . "'";
        $created_via_sso = (int)grab_array_var($data, 'created_via_sso', 0);
        $timestamp_func = ($db_type === 'pgsql') ? 'CURRENT_TIMESTAMP' : 'NOW()';

        $sql = ($db_type === 'pgsql'
            ? "INSERT INTO {$table} (object_id, client_id, user_id, tenant_id, source, priority, source_group_id, created_via_sso, created_at, updated_at)\n"
              . "VALUES ('{$object_id}', '{$client_id}', {$user_id}, '{$tenant_id}', '{$source}', '{$priority}', {$source_group_id_sql}, {$created_via_sso}, {$timestamp_func}, {$timestamp_func})"
            : "INSERT INTO `{$table}` (`object_id`, `client_id`, `user_id`, `tenant_id`, `source`, `priority`, `source_group_id`, `created_via_sso`, `created_at`, `updated_at`)\n"
              . "VALUES ('{$object_id}', '{$client_id}', {$user_id}, '{$tenant_id}', '{$source}', '{$priority}', {$source_group_id_sql}, {$created_via_sso}, {$timestamp_func}, {$timestamp_func})");

        return exec_sql_query(DB_NAGIOSXI, $sql);
    }
}

if (!function_exists('update_sso_mapping')) {
    function update_sso_mapping($object_id, $client_id, array $fields)
    {
        global $db_tables;

        $table = $db_tables[DB_NAGIOSXI]['sso_mappings'];
        $object_id_sql = escape_sql_param($object_id, DB_NAGIOSXI);
        $client_id_sql = escape_sql_param($client_id, DB_NAGIOSXI);
        $db_type = get_nagiosxi_db_type();

        $set = array();
        foreach ($fields as $key => $value) {
            if ($key === 'object_id' || $key === 'client_id') {
                continue;
            }

            if (is_null($value)) {
                $set[] = ($db_type === 'pgsql' ? "{$key} = NULL" : "`{$key}` = NULL");
            } else if (is_int($value) || is_numeric($value)) {
                $set[] = ($db_type === 'pgsql' ? "{$key} = " . (int)$value : "`{$key}` = " . (int)$value);
            } else {
                $escaped = escape_sql_param($value, DB_NAGIOSXI);
                $set[] = ($db_type === 'pgsql' ? "{$key} = '{$escaped}'" : "`{$key}` = '{$escaped}'");
            }
        }

        if (empty($set)) {
            return true;
        }

        $set[] = ($db_type === 'pgsql' ? "updated_at = CURRENT_TIMESTAMP" : "`updated_at` = NOW()");

        $where = ($db_type === 'pgsql'
            ? "object_id = '{$object_id_sql}' AND client_id = '{$client_id_sql}'"
            : "`object_id` = '{$object_id_sql}' AND `client_id` = '{$client_id_sql}'");

        $sql = ($db_type === 'pgsql'
            ? "UPDATE {$table} SET " . implode(', ', $set) . " WHERE {$where}"
            : "UPDATE `{$table}` SET " . implode(', ', $set) . " WHERE {$where}");

        return exec_sql_query(DB_NAGIOSXI, $sql);
    }
}

if (!function_exists('remove_sso_mapping')) {
    function remove_sso_mapping($object_id, $client_id, $source_filter = null)
    {
        global $db_tables;

        $table = $db_tables[DB_NAGIOSXI]['sso_mappings'];
        $object_id_sql = escape_sql_param($object_id, DB_NAGIOSXI);
        $client_id_sql = escape_sql_param($client_id, DB_NAGIOSXI);
        $db_type = get_nagiosxi_db_type();

        $quote = ($db_type === 'pgsql') ? '' : '`';
        $where = "{$quote}object_id{$quote} = '{$object_id_sql}' AND {$quote}client_id{$quote} = '{$client_id_sql}'";
        if ($source_filter !== null) {
            $source_sql = escape_sql_param($source_filter, DB_NAGIOSXI);
            $where .= " AND {$quote}source{$quote} = '{$source_sql}'";
        }

        // Get user_id and created_via_sso before deleting (for cleanup)
        $select_sql = ($db_type === 'pgsql'
            ? "SELECT user_id, created_via_sso FROM {$table} WHERE {$where}"
            : "SELECT `user_id`, `created_via_sso` FROM `{$table}` WHERE {$where}");
        $rs = exec_sql_query(DB_NAGIOSXI, $select_sql, true, false);
        
        $affected_users = array();
        if ($rs && $rs->RecordCount() > 0) {
            while (!$rs->EOF) {
                $user_id = (int)$rs->fields['user_id'];
                $created_via_sso = isset($rs->fields['created_via_sso']) ? (int)$rs->fields['created_via_sso'] : 0;
                if (!isset($affected_users[$user_id])) {
                    $affected_users[$user_id] = $created_via_sso;
                } else {
                    // If any mapping for this user has created_via_sso=1, mark it
                    if ($created_via_sso == 1) {
                        $affected_users[$user_id] = 1;
                    }
                }
                $rs->MoveNext();
            }
        }

        $sql = ($db_type === 'pgsql'
            ? "DELETE FROM {$table} WHERE {$where}"
            : "DELETE FROM `{$table}` WHERE {$where}");
        exec_sql_query(DB_NAGIOSXI, $sql);

        // Check and cleanup orphaned SSO-created users
        foreach ($affected_users as $user_id => $was_sso_created) {
            if ($was_sso_created == 1) {
                check_and_delete_orphaned_sso_user($user_id);
            }
        }
    }
}

if (!function_exists('remove_sso_mappings_for_object')) {
    function remove_sso_mappings_for_object($object_id, $client_id = null)
    {
        global $db_tables;

        $table = $db_tables[DB_NAGIOSXI]['sso_mappings'];
        $object_id_sql = escape_sql_param($object_id, DB_NAGIOSXI);
        $db_type = get_nagiosxi_db_type();
        $quote = ($db_type === 'pgsql') ? '' : '`';

        $where = "{$quote}object_id{$quote} = '{$object_id_sql}'";

        if ($client_id !== null) {
            $client_id_sql = escape_sql_param($client_id, DB_NAGIOSXI);
            $where .= " AND {$quote}client_id{$quote} = '{$client_id_sql}'";
        }

        // Get user_id and created_via_sso before deleting (for cleanup)
        $select_sql = ($db_type === 'pgsql'
            ? "SELECT user_id, created_via_sso FROM {$table} WHERE {$where}"
            : "SELECT `user_id`, `created_via_sso` FROM `{$table}` WHERE {$where}");
        $rs = exec_sql_query(DB_NAGIOSXI, $select_sql, true, false);
        
        $affected_users = array();
        if ($rs && $rs->RecordCount() > 0) {
            while (!$rs->EOF) {
                $user_id = (int)$rs->fields['user_id'];
                $created_via_sso = isset($rs->fields['created_via_sso']) ? (int)$rs->fields['created_via_sso'] : 0;
                if (!isset($affected_users[$user_id])) {
                    $affected_users[$user_id] = $created_via_sso;
                } else {
                    // If any mapping for this user has created_via_sso=1, mark it
                    if ($created_via_sso == 1) {
                        $affected_users[$user_id] = 1;
                    }
                }
                $rs->MoveNext();
            }
        }

        $sql = ($db_type === 'pgsql'
            ? "DELETE FROM {$table} WHERE {$where}"
            : "DELETE FROM `{$table}` WHERE {$where}");
        exec_sql_query(DB_NAGIOSXI, $sql);

        // Check and cleanup orphaned SSO-created users
        // Only call cleanup if the deleted mapping had created_via_sso=1
        foreach ($affected_users as $user_id => $was_sso_created) {
            if ($was_sso_created == 1) {
                check_and_delete_orphaned_sso_user($user_id);
            }
        }
    }
}

/**
 * Parse source_group_id field to array, handling backward compatibility
 * Handles NULL, single string values (legacy), and JSON array values (new format)
 * 
 * @param mixed $source_group_id The source_group_id field value (can be NULL, string, or JSON)
 * @return array Array of group IDs
 */
if (!function_exists('get_group_ids_from_field')) {
    function get_group_ids_from_field($source_group_id) {
        if (empty($source_group_id)) {
            return array();
        }
        
        // Try to decode as JSON array first (new format)
        $decoded = json_decode($source_group_id, true);
        if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
            return $decoded;
        }
        
        // If not JSON, treat as single string value (legacy format)
        return array($source_group_id);
    }
}

/**
 * Add a group ID to the source_group_id field array
 * 
 * @param mixed $source_group_id Current source_group_id value
 * @param string $group_id Group ID to add
 * @return string JSON encoded array of group IDs
 */
if (!function_exists('add_group_id_to_field')) {
    function add_group_id_to_field($source_group_id, $group_id) {
        if (empty($group_id)) {
            return $source_group_id;
        }
        
        $group_ids = get_group_ids_from_field($source_group_id);
        
        // Add group ID if not already present
        if (!in_array($group_id, $group_ids, true)) {
            $group_ids[] = $group_id;
        }
        
        return json_encode($group_ids);
    }
}

/**
 * Remove a group ID from the source_group_id field array
 * 
 * @param mixed $source_group_id Current source_group_id value
 * @param string $group_id Group ID to remove
 * @return string|null JSON encoded array of remaining group IDs, or NULL if array becomes empty
 */
if (!function_exists('remove_group_id_from_field')) {
    function remove_group_id_from_field($source_group_id, $group_id) {
        if (empty($group_id)) {
            return $source_group_id;
        }
        
        $group_ids = get_group_ids_from_field($source_group_id);
        
        // Remove group ID from array
        $key = array_search($group_id, $group_ids, true);
        if ($key !== false) {
            unset($group_ids[$key]);
            $group_ids = array_values($group_ids); // Re-index array
        }
        
        // Return NULL if no groups remain, otherwise return JSON encoded array
        if (empty($group_ids)) {
            return null;
        }
        
        return json_encode($group_ids);
    }
}

/**
 * Remove individual configuration - fallback to group if exists
 */
if (!function_exists('remove_individual_sso_config')) {
    function remove_individual_sso_config($object_id, $client_id) {
        $mapping = get_sso_mapping($object_id, $client_id);
        if (!$mapping) {
            return false;
        }
        
        if ($mapping['source'] === 'both') {
            // Fallback to group configuration
            update_sso_mapping($object_id, $client_id, array(
                'source' => 'group',
                'priority' => 'group'
            ));
        } else {
            // Remove entirely (no group fallback)
            remove_sso_mapping($object_id, $client_id);
        }
        
        return true;
    }
}

/**
 * Remove group configuration - keep individual if exists
 */
if (!function_exists('remove_group_sso_config')) {
    function remove_group_sso_config($object_id, $client_id, $group_id) {
        $mapping = get_sso_mapping($object_id, $client_id);
        if (!$mapping) {
            return false;
        }
        
        $current_source_group_id = isset($mapping['source_group_id']) ? $mapping['source_group_id'] : null;
        $group_ids = get_group_ids_from_field($current_source_group_id);
        
        // Check if the group_id is actually in the list
        if (!in_array($group_id, $group_ids, true)) {
            // Group not found in mapping, nothing to remove
            return false;
        }
        
        if ($mapping['source'] === 'both') {
            // Keep individual configuration, remove group from array
            $remaining_groups = remove_group_id_from_field($current_source_group_id, $group_id);
            update_sso_mapping($object_id, $client_id, array(
                'source' => 'individual',
                'priority' => 'individual',
                'source_group_id' => $remaining_groups
            ));
        } else if ($mapping['source'] === 'group') {
            // Remove group from array
            $remaining_groups = remove_group_id_from_field($current_source_group_id, $group_id);
            
            if ($remaining_groups === null) {
                // No groups remaining, remove entire mapping
                remove_sso_mapping($object_id, $client_id);
            } else {
                // Update with remaining groups
                update_sso_mapping($object_id, $client_id, array(
                    'source_group_id' => $remaining_groups
                ));
            }
        }
        
        return true;
    }
}

/**
 * Check if an XI user was created via SSO by checking if any mappings to that user have created_via_sso = 1
 * 
 * @param int $user_id The Nagios XI user ID to check
 * @param string|null $exclude_object_id Optional: exclude this object_id from the check (for updates)
 * @param string|null $exclude_client_id Optional: exclude this client_id from the check (for updates)
 * @return bool True if any mapping to this user has created_via_sso = 1, false otherwise
 */
if (!function_exists('check_if_xi_user_created_via_sso')) {
    function check_if_xi_user_created_via_sso($user_id, $exclude_object_id = null, $exclude_client_id = null) {
        global $db_tables;

        if (empty($user_id)) {
            return false;
        }

        $table = $db_tables[DB_NAGIOSXI]['sso_mappings'];
        $user_id_sql = (int)$user_id;
        $db_type = get_nagiosxi_db_type();
        $quote = ($db_type === 'pgsql') ? '' : '`';

        // Build WHERE clause
        $where = "{$quote}user_id{$quote} = {$user_id_sql} AND {$quote}created_via_sso{$quote} = 1";
        
        // Exclude current mapping if updating
        if (!empty($exclude_object_id) && !empty($exclude_client_id)) {
            $exclude_object_id_sql = escape_sql_param($exclude_object_id, DB_NAGIOSXI);
            $exclude_client_id_sql = escape_sql_param($exclude_client_id, DB_NAGIOSXI);
            $where .= " AND NOT ({$quote}object_id{$quote} = '{$exclude_object_id_sql}' AND {$quote}client_id{$quote} = '{$exclude_client_id_sql}')";
        }

        $sql = ($db_type === 'pgsql'
            ? "SELECT COUNT(*) as count FROM {$table} WHERE {$where}"
            : "SELECT COUNT(*) as count FROM `{$table}` WHERE {$where}");
        
        $rs = exec_sql_query(DB_NAGIOSXI, $sql, true, false);
        
        if ($rs && $rs->RecordCount() > 0) {
            $count = (int)$rs->fields['count'];
            return $count > 0;
        }

        return false;
    }
}

if (!function_exists('link_aad_user_to_xi_user')) {
    function link_aad_user_to_xi_user($object_id, $client_id, $tenant_id, $user_id, $link_source = 'individual', $link_priority = 'individual', $source_group_id = null, $created_via_sso = false) {
        if (empty($object_id) || empty($client_id) || empty($tenant_id) || empty($user_id)) {
            return;
        }

        $existing = get_sso_mapping($object_id, $client_id);

        if ($existing) {
            $current_source = $existing['source'];
            $current_priority = $existing['priority'];
            $current_user_id = (int)$existing['user_id'];

            // Determine new source/priority based on incoming data
            if ($current_source === 'individual' && $link_source === 'group') {
                // Individual exists, group being added - keep individual user_id and priority
                $new_source = 'both';
                $new_priority = 'individual';
                $target_user_id = $current_user_id; // Preserve individual user_id
            } else if ($current_source === 'group' && $link_source === 'individual') {
                // Group exists, individual being added - use individual user_id and priority
                $new_source = 'both';
                $new_priority = 'individual';
                $target_user_id = (int)$user_id; // Use new individual user_id
            } else if ($current_source === 'both') {
                // Both already exist - preserve individual priority if incoming is individual
                $new_source = 'both';
                if ($link_priority === 'individual') {
                    $new_priority = 'individual';
                    $target_user_id = (int)$user_id; // Use individual user_id
                } else {
                    $new_priority = $current_priority;
                    $target_user_id = $current_user_id; // Keep existing user_id
                }
            } else {
                // Same source type - update normally
                $new_source = $link_source;
                $new_priority = $link_priority;
                $target_user_id = (int)$user_id;
            }

            // Determine created_via_sso value:
            // - If passed value is true, use it (new user being created)
            // - If passed value is false:
            //   1. First check if the CURRENT mapping already has created_via_sso=1 - if so, preserve it
            //   2. Otherwise, check if other mappings to this XI user have created_via_sso=true
            //      If yes, preserve it (the XI user was created via SSO)
            //      If no, use false (the XI user existed before SSO)
            $final_created_via_sso = $created_via_sso;
            if (!$created_via_sso) {
                // First check if the current mapping already has created_via_sso=1 - preserve it if so
                $current_created_via_sso = isset($existing['created_via_sso']) ? (int)$existing['created_via_sso'] : 0;
                if ($current_created_via_sso == 1) {
                    // Current mapping already marked as SSO-created - preserve it
                    $final_created_via_sso = true;
                } else {
                    // Check if this XI user was created via SSO by checking other mappings
                    $final_created_via_sso = check_if_xi_user_created_via_sso($target_user_id, $object_id, $client_id);
                }
            }

            $update = array(
                'user_id' => $target_user_id,
                'tenant_id' => $tenant_id,
                'source' => $new_source,
                'priority' => $new_priority,
                'created_via_sso' => $final_created_via_sso ? 1 : 0,
            );

            // Handle source_group_id: append to existing array if group source, replace if individual
            if ($source_group_id !== null && $link_source === 'group') {
                // For group sources, append to existing group IDs array
                $current_source_group_id = isset($existing['source_group_id']) ? $existing['source_group_id'] : null;
                $update['source_group_id'] = add_group_id_to_field($current_source_group_id, $source_group_id);
            } else if ($source_group_id !== null && $link_source === 'individual') {
                // For individual sources, set directly (individual configs don't use group arrays)
                $update['source_group_id'] = $source_group_id;
            } else if ($source_group_id === null && $link_source === 'group') {
                // If no source_group_id provided but source is group, preserve existing groups
                // (This handles cases where updating other fields but keeping groups)
                if (isset($existing['source_group_id'])) {
                    $update['source_group_id'] = $existing['source_group_id'];
                }
            }

            log_sso('link_aad_user_to_xi_user: UPDATING existing mapping (object_id: ' . $object_id . ') - Setting created_via_sso=' . ($final_created_via_sso ? '1' : '0') . ', user_id=' . $target_user_id, 'debug');
            update_sso_mapping($object_id, $client_id, $update);
        } else {
            // New mapping: for group sources, store as JSON array; for individual, store as-is
            $final_source_group_id = $source_group_id;
            if ($source_group_id !== null && $link_source === 'group') {
                // Store as JSON array for new group mappings
                $final_source_group_id = json_encode(array($source_group_id));
            }
            
            // Determine created_via_sso value:
            // - If passed value is true, use it (new user being created)
            // - If passed value is false, check if other mappings to this XI user have created_via_sso=true
            //   If yes, use true (the XI user was created via SSO)
            //   If no, use false (the XI user existed before SSO)
            $final_created_via_sso = $created_via_sso;
            if (!$created_via_sso) {
                // Check if this XI user was created via SSO by checking other mappings
                $final_created_via_sso = check_if_xi_user_created_via_sso((int)$user_id);
            }
            
            log_sso('link_aad_user_to_xi_user: CREATING new mapping (object_id: ' . $object_id . ') - Setting created_via_sso=' . ($final_created_via_sso ? '1' : '0') . ', user_id=' . (int)$user_id, 'debug');
            create_sso_mapping(array(
                'object_id' => $object_id,
                'client_id' => $client_id,
                'user_id' => (int)$user_id,
                'tenant_id' => $tenant_id,
                'source' => $link_source,
                'priority' => $link_priority,
                'source_group_id' => $final_source_group_id,
                'created_via_sso' => $final_created_via_sso ? 1 : 0,
            ));
        }
    }
}

/**
 * Delete an orphaned SSO-created user if they have no remaining mappings
 * NOTE: This function assumes the caller has already verified the user was created via SSO
 * (i.e., at least one of their mappings had created_via_sso=1)
 * 
 * @param int $user_id The Nagios XI user ID to check and delete
 * @return bool True if user was deleted, false otherwise
 */
if (!function_exists('check_and_delete_orphaned_sso_user')) {
    function check_and_delete_orphaned_sso_user($user_id) {
        global $db_tables;

        if (empty($user_id)) {
            log_sso("check_and_delete_orphaned_sso_user: Skipping - empty user_id provided", 'debug');
            return false;
        }

        $table = $db_tables[DB_NAGIOSXI]['sso_mappings'];
        $user_id_sql = (int)$user_id;
        $db_type = get_nagiosxi_db_type();

        log_sso("check_and_delete_orphaned_sso_user: Checking user_id={$user_id_sql} for orphan cleanup", 'debug');

        // Check if user has any remaining mappings
        $sql = ($db_type === 'pgsql'
            ? "SELECT COUNT(*) as count FROM {$table} WHERE user_id = {$user_id_sql}"
            : "SELECT COUNT(*) as count FROM `{$table}` WHERE `user_id` = {$user_id_sql}");
        
        $rs = exec_sql_query(DB_NAGIOSXI, $sql, true, false);
        
        $total_remaining = 0;
        if ($rs && $rs->RecordCount() > 0) {
            $total_remaining = (int)$rs->fields['count'];
        }

        // If user still has mappings, don't delete
        if ($total_remaining > 0) {
            log_sso("check_and_delete_orphaned_sso_user: User {$user_id_sql} still has {$total_remaining} SSO mapping(s) - NOT deleting", 'debug');
            return false;
        }

        log_sso("check_and_delete_orphaned_sso_user: User {$user_id_sql} has NO remaining SSO mappings - checking if user exists", 'debug');

        // Check if user exists
        $users_table = $db_tables[DB_NAGIOSXI]['users'];
        $sql = ($db_type === 'pgsql'
            ? "SELECT 1 FROM {$users_table} WHERE user_id = {$user_id_sql} LIMIT 1"
            : "SELECT 1 FROM `{$users_table}` WHERE `user_id` = {$user_id_sql} LIMIT 1");
        
        $rs = exec_sql_query(DB_NAGIOSXI, $sql, true, false);
        
        if (!$rs || $rs->RecordCount() === 0) {
            // User doesn't exist, nothing to delete
            log_sso("check_and_delete_orphaned_sso_user: User {$user_id_sql} doesn't exist in database - nothing to delete", 'debug');
            return false;
        }

        // User exists and has no SSO mappings - delete them
        log_sso("check_and_delete_orphaned_sso_user: User {$user_id_sql} is orphaned - attempting to DELETE XI user", 'info');
        
        // Include users.inc.php if not already included
        if (!function_exists('delete_user_id')) {
            require_once(dirname(dirname(dirname(dirname(__FILE__)))) . '/utils-users.inc.php');
        }

        try {
            $result = delete_user_id($user_id_sql, true);
            if ($result !== false) {
                log_sso("check_and_delete_orphaned_sso_user: Successfully deleted orphaned SSO-created user_id={$user_id_sql}", 'info');
                return true;
            } else {
                log_sso("check_and_delete_orphaned_sso_user: Failed to delete user {$user_id_sql} - delete_user_id() returned false", 'error');
                return false;
            }
        } catch (Exception $e) {
            log_sso("check_and_delete_orphaned_sso_user: Exception deleting user {$user_id_sql}: " . $e->getMessage(), 'error');
            return false;
        }
    }
}

/**
 * Clear all individual SSO configurations for a given client_id
 * For entries with source='both': Updates to source='group', priority='group' (fallback to group config)
 * For entries with source='individual': Deletes the mapping entirely
 * 
 * @param string $client_id The client_id to clear individual configs for
 * @return array Returns array with 'deleted_count' and 'updated_count'
 */
if (!function_exists('clear_all_individual_configs_for_client')) {
    function clear_all_individual_configs_for_client($client_id) {
        global $db_tables;

        if (empty($client_id)) {
            return array('deleted_count' => 0, 'updated_count' => 0, 'error' => 'client_id is required');
        }

        $table = $db_tables[DB_NAGIOSXI]['sso_mappings'];
        $client_id_sql = escape_sql_param($client_id, DB_NAGIOSXI);
        $db_type = get_nagiosxi_db_type();
        $quote = ($db_type === 'pgsql') ? '' : '`';

        // First, get all mappings for this client that have individual source
        $sql = ($db_type === 'pgsql'
            ? "SELECT object_id, source, user_id, created_via_sso FROM {$table} WHERE client_id = '{$client_id_sql}' AND (source = 'individual' OR source = 'both')"
            : "SELECT `object_id`, `source`, `user_id`, `created_via_sso` FROM `{$table}` WHERE `client_id` = '{$client_id_sql}' AND (`source` = 'individual' OR `source` = 'both')");
        
        $rs = exec_sql_query(DB_NAGIOSXI, $sql, true, false);
        
        if (!$rs) {
            return array('deleted_count' => 0, 'updated_count' => 0, 'error' => 'Failed to query mappings');
        }

        $deleted_count = 0;
        $updated_count = 0;
        $deleted_user_ids = array(); // Track user_ids of fully deleted mappings for cleanup

        // Process each mapping
        while (!$rs->EOF) {
            $object_id = $rs->fields['object_id'];
            $source = $rs->fields['source'];
            $user_id = (int)$rs->fields['user_id'];
            $created_via_sso = isset($rs->fields['created_via_sso']) ? (int)$rs->fields['created_via_sso'] : 0;

            if ($source === 'both') {
                // Fallback to group configuration
                update_sso_mapping($object_id, $client_id, array(
                    'source' => 'group',
                    'priority' => 'group'
                ));
                $updated_count++;
            } else if ($source === 'individual') {
                // Remove entirely (no group fallback)
                // Track user_id and created_via_sso for cleanup
                if (!isset($deleted_user_ids[$user_id])) {
                    $deleted_user_ids[$user_id] = $created_via_sso;
                } else {
                    // If any mapping for this user has created_via_sso=1, mark it
                    if ($created_via_sso == 1) {
                        $deleted_user_ids[$user_id] = 1;
                    }
                }
                remove_sso_mapping($object_id, $client_id);
                $deleted_count++;
            }

            $rs->MoveNext();
        }

        // remove_sso_mapping already calls XI user cleanup for users created via SSO, so we don't need to do it again here

        return array(
            'deleted_count' => $deleted_count,
            'updated_count' => $updated_count,
            'total_affected' => $deleted_count + $updated_count
        );
    }
}

