import { Subject } from '@restorecommerce/rc-grpc-clients/dist/generated/io/restorecommerce/auth.js';
import { InMemoryAdapter } from './in-memory-adapter.js';
import { marshallProtobufAny, unmarshallProtobufAny } from './utils.js';
const delegateToRemoteService = (type) => ['AccessToken', 'RefreshToken'].includes(type);
export function createIdentityServiceAdapterClass(remoteTokenService, logger, localTokenServiceFactory) {
    return class IdentityServiceAdapter {
        type;
        localTokenService;
        constructor(type) {
            this.type = type;
            this.localTokenService = localTokenServiceFactory ? localTokenServiceFactory(type) : new InMemoryAdapter(type);
        }
        async consume(id) {
            logger.verbose(`Consuming ${this.type} token ${id}`);
            if (delegateToRemoteService(this.type)) {
                try {
                    await remoteTokenService.consume({
                        id,
                        type: this.type,
                        subject: undefined
                    });
                }
                catch (error) {
                    logger.error(`Error consuming ${this.type} token ${id}`, error);
                }
            }
            else {
                await this.localTokenService.consume(id);
            }
        }
        async destroy(id) {
            logger.verbose(`Destroying ${this.type} token ${id}`);
            if (delegateToRemoteService(this.type)) {
                try {
                    await remoteTokenService.destroy({
                        id,
                        type: this.type,
                        subject: Subject.fromPartial({ token: id })
                    });
                }
                catch (error) {
                    logger.error(`Error destroying ${this.type} token ${id}`, error);
                }
            }
            else {
                await this.localTokenService.destroy(id);
            }
        }
        async find(id) {
            logger.verbose(`Finding ${this.type} token ${id}`);
            if (delegateToRemoteService(this.type)) {
                try {
                    let response = await remoteTokenService.find({
                        id,
                        type: this.type,
                        subject: Subject.fromPartial({ token: id })
                    });
                    let tokenResponse;
                    if (response) {
                        tokenResponse = unmarshallProtobufAny(response);
                        if (tokenResponse) {
                            // oidc-provider expects "exp" to be in epochTime in seconds
                            tokenResponse.exp = tokenResponse?.exp ? Math.floor(new Date(tokenResponse?.exp)?.getTime() / 1000) : undefined;
                        }
                    }
                    return tokenResponse;
                }
                catch (error) {
                    logger.error(`Error finding ${this.type} token ${id}`, error);
                    return undefined;
                }
            }
            else {
                return await this.localTokenService.find(id);
            }
        }
        async findByUid(uid) {
            logger.verbose(`Finding by Uid ${uid}`);
            return await this.localTokenService.findByUid(uid);
        }
        // Not needed. DeviceFlow only
        async findByUserCode(userCode) {
            logger.error('Finding br UserCode is unsupported', this.type, ...arguments);
            throw new Error('UNSUPPORTED');
        }
        async upsert(id, payload, expiresIn) {
            logger.info(`Upserting ${this.type} token ${id}`, payload);
            if (delegateToRemoteService(this.type)) {
                try {
                    await remoteTokenService.upsert({
                        expiresIn: new Date(Date.now() + (1000 * expiresIn)),
                        id,
                        payload: marshallProtobufAny(payload),
                        type: this.type,
                        subject: undefined
                    });
                }
                catch (error) {
                    logger.error(`Error upserting ${this.type} token ${id}`, error);
                }
            }
            else {
                return this.localTokenService.upsert(id, payload, expiresIn * 1000);
            }
        }
        async revokeByGrantId(grantId) {
            logger.error(`Revoking grant id ${this.type} token ${grantId}`);
            await this.localTokenService.revokeByGrantId(grantId);
            if (delegateToRemoteService(this.type)) {
                try {
                    await remoteTokenService.revokeByGrantId({
                        grantId,
                        subject: Subject.fromPartial({ token: grantId })
                    });
                }
                catch (error) {
                    logger.error(`Error revoking grant id ${grantId}`, error);
                }
            }
        }
    };
}
//# sourceMappingURL=adapter.js.map