import { z } from 'zod';
import { globalOptionsZod } from '../../../../Command.js';
import { entraGroup } from '../../../../utils/entraGroup.js';
import { odata } from '../../../../utils/odata.js';
import { zod } from '../../../../utils/zod.js';
import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';
const RoleEnum = {
    Owner: 'Owner',
    Member: 'Member'
};
export const options = z.strictObject({
    ...globalOptionsZod.shape,
    groupId: z.uuid().optional().alias('i'),
    groupName: z.string().optional().alias('n'),
    role: zod.coercedEnum(RoleEnum).optional().alias('r'),
    properties: z.string().optional().alias('p'),
    filter: z.string().optional().alias('f')
});
class EntraGroupMemberListCommand extends GraphCommand {
    get name() {
        return commands.GROUP_MEMBER_LIST;
    }
    get description() {
        return 'Lists members of a specific Entra group';
    }
    defaultProperties() {
        return ['id', 'displayName', 'userPrincipalName', 'roles'];
    }
    get schema() {
        return options;
    }
    getRefinedSchema(schema) {
        return schema
            .refine(options => [options.groupId, options.groupName].filter(o => o !== undefined).length === 1, {
            error: 'Use one of the following options: groupId or groupName.',
            params: {
                customCode: 'optionSet',
                options: ['groupId', 'groupName']
            }
        });
    }
    async commandAction(logger, args) {
        try {
            const groupId = await this.getGroupId(args.options, logger);
            const users = [];
            if (!args.options.role || args.options.role === 'Owner') {
                const owners = await this.getUsers(args.options, 'Owners', groupId, logger);
                owners.forEach(owner => users.push({ ...owner, roles: ['Owner'] }));
            }
            if (!args.options.role || args.options.role === 'Member') {
                const members = await this.getUsers(args.options, 'Members', groupId, logger);
                members.forEach((member) => {
                    const user = users.find((u) => u.id === member.id);
                    if (user !== undefined) {
                        user.roles.push('Member');
                    }
                    else {
                        users.push({ ...member, roles: ['Member'] });
                    }
                });
            }
            await logger.log(users);
        }
        catch (err) {
            this.handleRejectedODataJsonPromise(err);
        }
    }
    async getGroupId(options, logger) {
        if (options.groupId) {
            return options.groupId;
        }
        if (this.verbose) {
            await logger.logToStderr('Retrieving Group Id...');
        }
        return await entraGroup.getGroupIdByDisplayName(options.groupName);
    }
    async getUsers(options, role, groupId, logger) {
        const { properties, filter } = options;
        if (this.verbose) {
            await logger.logToStderr(`Retrieving ${role} of the group with id ${groupId}`);
        }
        const selectProperties = properties ?
            `${properties.split(',').filter(f => f.toLowerCase() !== 'id').concat('id').map(p => p.trim()).join(',')}` :
            'id,displayName,userPrincipalName,givenName,surname';
        const allSelectProperties = selectProperties.split(',');
        const propertiesWithSlash = allSelectProperties.filter(item => item.includes('/'));
        let fieldExpand = '';
        propertiesWithSlash.forEach(p => {
            if (fieldExpand.length > 0) {
                fieldExpand += ',';
            }
            fieldExpand += `${p.split('/')[0]}($select=${p.split('/')[1]})`;
        });
        const expandParam = fieldExpand.length > 0 ? `&$expand=${fieldExpand}` : '';
        const selectParam = allSelectProperties.filter(item => !item.includes('/'));
        const endpoint = `${this.resource}/v1.0/groups/${groupId}/${role}?$select=${selectParam}${expandParam}`;
        let users;
        if (filter) {
            // While using the filter, we need to specify the ConsistencyLevel header.
            // Can be refactored when the header is no longer necessary.
            const requestOptions = {
                url: `${endpoint}&$filter=${encodeURIComponent(filter)}&$count=true`,
                headers: {
                    accept: 'application/json;odata.metadata=none',
                    ConsistencyLevel: 'eventual'
                },
                responseType: 'json'
            };
            users = await odata.getAllItems(requestOptions);
        }
        else {
            users = await odata.getAllItems(endpoint);
        }
        return users;
    }
}
export default new EntraGroupMemberListCommand();
//# sourceMappingURL=group-member-list.js.map