import { z } from 'zod';
import { globalOptionsZod } from '../../../../Command.js';
import request from '../../../../request.js';
import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';
import { roleDefinition } from '../../../../utils/roleDefinition.js';
import { validation } from '../../../../utils/validation.js';
import { entraUser } from '../../../../utils/entraUser.js';
import { entraGroup } from '../../../../utils/entraGroup.js';
import { accessToken } from '../../../../utils/accessToken.js';
import auth from '../../../../Auth.js';
export const options = z.strictObject({
    ...globalOptionsZod.shape,
    roleDefinitionName: z.string().optional().alias('n'),
    roleDefinitionId: z.uuid().optional().alias('i'),
    userId: z.uuid().optional(),
    userName: z.string().optional(),
    groupId: z.uuid().optional(),
    groupName: z.string().optional(),
    administrativeUnitId: z.uuid().optional(),
    applicationId: z.uuid().optional(),
    justification: z.string().optional().alias('j'),
    startDateTime: z.string().refine(date => validation.isValidISODateTime(date), {
        error: e => `'${e.input}' is not a valid ISO 8601 date time string.`
    }).optional().alias('s'),
    endDateTime: z.string().refine(date => validation.isValidISODateTime(date), {
        error: e => `'${e.input}' is not a valid ISO 8601 date time string.`
    }).optional().alias('e'),
    duration: z.string().refine(dur => validation.isValidISODuration(dur), {
        error: e => `'${e.input}' is not a valid ISO 8601 duration.`
    }).optional().alias('d'),
    ticketNumber: z.string().optional(),
    ticketSystem: z.string().optional(),
    noExpiration: z.boolean().default(false)
});
class EntraPimRoleAssignmentAddCommand extends GraphCommand {
    get name() {
        return commands.PIM_ROLE_ASSIGNMENT_ADD;
    }
    get description() {
        return 'Requests activation of an Entra role assignment for a user or group';
    }
    get schema() {
        return options;
    }
    getRefinedSchema(schema) {
        return schema
            .refine(options => [options.roleDefinitionId, options.roleDefinitionName].filter(o => o !== undefined).length === 1, {
            message: 'Specify either roleDefinitionId or roleDefinitionName',
            params: {
                customCode: 'optionSet',
                options: ['roleDefinitionId', 'roleDefinitionName']
            }
        })
            .refine(options => {
            const specified = [options.noExpiration ? true : undefined, options.endDateTime, options.duration].filter(o => o !== undefined).length;
            return specified <= 1;
        }, {
            message: 'Specify only one of the following options: noExpiration, endDateTime, duration',
            params: {
                customCode: 'optionSet',
                options: ['noExpiration', 'endDateTime', 'duration']
            }
        })
            .refine(options => {
            const specified = [options.userId, options.userName, options.groupId, options.groupName].filter(o => o !== undefined).length;
            return specified <= 1;
        }, {
            message: 'Specify only one of the following options: userId, userName, groupId, groupName',
            params: {
                customCode: 'optionSet',
                options: ['userId', 'userName', 'groupId', 'groupName']
            }
        })
            .refine(options => {
            const specified = [options.administrativeUnitId, options.applicationId].filter(o => o !== undefined).length;
            return specified <= 1;
        }, {
            message: 'Specify only one of the following options: administrativeUnitId, applicationId',
            params: {
                customCode: 'optionSet',
                options: ['administrativeUnitId', 'applicationId']
            }
        });
    }
    async commandAction(logger, args) {
        const { userId, userName, groupId, groupName, startDateTime, endDateTime, ticketNumber, ticketSystem } = args.options;
        try {
            const token = auth.connection.accessTokens[auth.defaultResource].accessToken;
            const isAppOnlyAccessToken = accessToken.isAppOnlyAccessToken(token);
            if (isAppOnlyAccessToken) {
                throw 'When running with application permissions either userId, userName, groupId or groupName is required';
            }
            const roleDefinitionId = await this.getRoleDefinitionId(args.options, logger);
            const principalId = await this.getPrincipalId(args.options, logger);
            const requestOptions = {
                url: `${this.resource}/v1.0/roleManagement/directory/roleAssignmentScheduleRequests`,
                headers: {
                    'accept': 'application/json;odata.metadata=none'
                },
                responseType: 'json',
                data: {
                    principalId: principalId,
                    roleDefinitionId: roleDefinitionId,
                    directoryScopeId: this.getDirectoryScope(args.options),
                    action: !userId && !userName && !groupId && !groupName ? 'selfActivate' : 'adminAssign',
                    justification: args.options.justification,
                    scheduleInfo: {
                        startDateTime: startDateTime,
                        expiration: {
                            duration: this.getDuration(args.options),
                            endDateTime: endDateTime,
                            type: this.getExpirationType(args.options)
                        }
                    },
                    ticketInfo: {
                        ticketNumber: ticketNumber,
                        ticketSystem: ticketSystem
                    }
                }
            };
            const response = await request.post(requestOptions);
            await logger.log(response);
        }
        catch (err) {
            this.handleRejectedODataJsonPromise(err);
        }
    }
    async getRoleDefinitionId(options, logger) {
        if (options.roleDefinitionId) {
            return options.roleDefinitionId;
        }
        if (this.verbose) {
            await logger.logToStderr(`Retrieving role definition by its name '${options.roleDefinitionName}'`);
        }
        const role = await roleDefinition.getRoleDefinitionByDisplayName(options.roleDefinitionName);
        return role.id;
    }
    async getPrincipalId(options, logger) {
        if (options.userId || options.groupId) {
            return options.userId || options.groupId;
        }
        if (options.userName) {
            if (this.verbose) {
                await logger.logToStderr(`Retrieving user by its name '${options.userName}'`);
            }
            return await entraUser.getUserIdByUpn(options.userName);
        }
        else if (options.groupName) {
            if (this.verbose) {
                await logger.logToStderr(`Retrieving group by its name '${options.groupName}'`);
            }
            return await entraGroup.getGroupIdByDisplayName(options.groupName);
        }
        if (this.verbose) {
            await logger.logToStderr(`Retrieving id of the current user`);
        }
        const token = auth.connection.accessTokens[auth.defaultResource].accessToken;
        return accessToken.getUserIdFromAccessToken(token);
    }
    getExpirationType(options) {
        if (options.endDateTime) {
            return 'afterDateTime';
        }
        if (options.noExpiration) {
            return 'noExpiration';
        }
        return 'afterDuration';
    }
    getDuration(options) {
        if (!options.duration && !options.endDateTime && !options.noExpiration) {
            return 'PT8H';
        }
        return options.duration;
    }
    getDirectoryScope(options) {
        if (options.administrativeUnitId) {
            return `/administrativeUnits/${options.administrativeUnitId}`;
        }
        if (options.applicationId) {
            return `/${options.applicationId}`;
        }
        return '/';
    }
}
export default new EntraPimRoleAssignmentAddCommand();
//# sourceMappingURL=pim-role-assignment-add.js.map