import { AbstractMessage } from '../core/abstract-message.js';
import { Message } from '../core/message.js';
import { ProtocolsGrantAuthorization } from '../core/protocols-grant-authorization.js';
import { removeUndefinedProperties } from '@enbox/common';
import { Time } from '../utils/time.js';
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
import { normalizeProtocolUrl, validateProtocolUrlNormalized } from '../utils/url.js';
export class ProtocolsQuery extends AbstractMessage {
    static async parse(message) {
        if (message.authorization !== undefined) {
            await Message.validateSignatureStructure(message.authorization.signature, message.descriptor);
        }
        if (message.descriptor.filter !== undefined) {
            validateProtocolUrlNormalized(message.descriptor.filter.protocol);
        }
        Time.validateTimestamp(message.descriptor.messageTimestamp);
        return new ProtocolsQuery(message);
    }
    static async create(options) {
        const permissionGrantInvocation = Message.normalizePermissionGrantInvocation({
            permissionGrantId: options.permissionGrantId,
        });
        const descriptor = {
            interface: DwnInterfaceName.Protocols,
            method: DwnMethodName.Query,
            messageTimestamp: options.messageTimestamp ?? Time.getCurrentTimestamp(),
            filter: options.filter ? ProtocolsQuery.normalizeFilter(options.filter) : undefined,
            ...permissionGrantInvocation,
        };
        // delete all descriptor properties that are `undefined` else the code will encounter the following IPLD issue when attempting to generate CID:
        // Error: `undefined` is not supported by the IPLD Data Model and cannot be encoded
        removeUndefinedProperties(descriptor);
        // only generate the `authorization` property if signature input is given
        let authorization;
        if (options.signer !== undefined) {
            authorization = await Message.createAuthorization({
                descriptor,
                signer: options.signer,
                ...permissionGrantInvocation
            });
        }
        const message = { descriptor, authorization };
        Message.validateJsonSchema(message);
        const protocolsQuery = new ProtocolsQuery(message);
        return protocolsQuery;
    }
    static normalizeFilter(filter) {
        return {
            ...filter,
            protocol: normalizeProtocolUrl(filter.protocol),
        };
    }
    async authorize(tenant, validationStateReader) {
        // if author is the same as the target tenant, we can directly grant access
        if (this.author === tenant) {
            return;
        }
        else if (this.author !== undefined && Message.getPermissionGrantId(this.signaturePayload) !== undefined) {
            const permissionGrantId = Message.getPermissionGrantId(this.signaturePayload);
            const permissionGrant = await validationStateReader.fetchGrant(tenant, permissionGrantId);
            await ProtocolsGrantAuthorization.authorizeQuery({
                expectedGrantor: tenant,
                expectedGrantee: this.author,
                incomingMessage: this.message,
                permissionGrant,
                validationStateReader
            });
        }
        else {
            throw new DwnError(DwnErrorCode.ProtocolsQueryUnauthorized, 'The ProtocolsQuery failed authorization');
        }
    }
}
//# sourceMappingURL=protocols-query.js.map