import * as i0 from '@angular/core';
import { Injectable, NgModule } from '@angular/core';
import * as i1 from '@c8y/ngx-components';
import { CoreModule, ManagedObjectRealtimeService, DeviceBootstrapRealtimeService } from '@c8y/ngx-components';
import * as i2 from '@c8y/client';
import { DeviceRegistrationStatus } from '@c8y/client';
import { gettext } from '@c8y/ngx-components/gettext';
import { set, pick, get } from 'lodash-es';
import { BehaviorSubject, Subject, merge, interval } from 'rxjs';
import { filter, switchMap, map, takeUntil, tap, distinctUntilChanged } from 'rxjs/operators';
import { downgradeInjectable } from '@angular/upgrade/static';
import * as angular from 'angular';
import { registerNgModule } from '@c8y/ng1-modules';

var DataBrokerConnectorStatus;
(function (DataBrokerConnectorStatus) {
    DataBrokerConnectorStatus["ACTIVE"] = "ACTIVE";
    DataBrokerConnectorStatus["SUSPENDED"] = "SUSPENDED";
    DataBrokerConnectorStatus["WAITING"] = "WAITING";
})(DataBrokerConnectorStatus || (DataBrokerConnectorStatus = {}));

class SubscriptionStatusViewModelFactory {
    build(status) {
        let statusViewModel = null;
        switch (status) {
            case DataBrokerConnectorStatus.ACTIVE: // dataBrokerConnectorsSvc.STATUS.ACTIVE.value
                statusViewModel = {
                    icon: 'check-circle',
                    textClass: 'text-success',
                    text: gettext('Active`data broker subscription`')
                };
                break;
            case DataBrokerConnectorStatus.SUSPENDED: // dataBrokerConnectorsSvc.STATUS.SUSPENDED.value
                statusViewModel = {
                    icon: 'exclamation-triangle',
                    textClass: 'text-warning',
                    text: gettext('Inactive`data broker subscription`')
                };
                break;
            case DataBrokerConnectorStatus.WAITING: // dataBrokerConnectorsSvc.STATUS.WAITING.value
                statusViewModel = {
                    icon: 'spinner',
                    iconClass: 'icon-spin',
                    textClass: 'text-warning',
                    text: gettext('Waiting`data broker subscription`')
                };
                break;
            default:
                break;
        }
        return statusViewModel;
    }
}
class NewDeviceRequestStatusFactory {
    build(status) {
        let result = null;
        switch (status) {
            case DeviceRegistrationStatus.WAITING_FOR_CONNECTION:
                result = {
                    name: DeviceRegistrationStatus.WAITING_FOR_CONNECTION,
                    label: gettext('Waiting for connection`data broker subscription`'),
                    value: DeviceRegistrationStatus.WAITING_FOR_CONNECTION
                };
                break;
            case DeviceRegistrationStatus.PENDING_ACCEPTANCE:
                result = {
                    name: DeviceRegistrationStatus.PENDING_ACCEPTANCE,
                    label: gettext('Pending acceptance`data broker subscription`'),
                    value: DeviceRegistrationStatus.PENDING_ACCEPTANCE
                };
                break;
            case DeviceRegistrationStatus.ACCEPTED:
                result = {
                    name: DeviceRegistrationStatus.ACCEPTED,
                    label: gettext('Accepted`data broker subscription`'),
                    value: DeviceRegistrationStatus.ACCEPTED
                };
            case DeviceRegistrationStatus.BLOCKED:
                result = {
                    name: DeviceRegistrationStatus.BLOCKED,
                    label: gettext('Blocked`data broker subscription`'),
                    value: DeviceRegistrationStatus.BLOCKED
                };
                break;
        }
        return result;
    }
}

class DataBrokerSubscriptionsService {
    constructor(moRealtimeService, deviceBootstrapRealtimeService, inventoryService, userService, deviceRegistrationService, appStateService) {
        this.moRealtimeService = moRealtimeService;
        this.deviceBootstrapRealtimeService = deviceBootstrapRealtimeService;
        this.inventoryService = inventoryService;
        this.userService = userService;
        this.deviceRegistrationService = deviceRegistrationService;
        this.appStateService = appStateService;
        this.FRAGMENT_TYPE = 'c8y_BrokerSource';
        this.NEW_DEVICE_REQUEST_TYPE = 'c8y_DataBroker';
        /**
         * inventory polling interval
         */
        this.POLL_INTERVAL_FOR_SUBSCRIPTIONS = 15000;
        this.moRealtimeSubscriptionsMap = new Map();
        this.refreshPendingTrigger$ = new BehaviorSubject(null);
        this.filters = {
            fragmentType: this.FRAGMENT_TYPE,
            pageSize: 2000
        };
        this.subscriptionStatusViewModelFactory = new SubscriptionStatusViewModelFactory();
        this.newDeviceRequestStatusViewModelFactory = new NewDeviceRequestStatusFactory();
        // Build legacy enum structure for ng1 component
        this.NEW_DEVICE_REQUEST_STATUS = this.generateDeviceRequestStatusEnum(this.newDeviceRequestStatusViewModelFactory);
    }
    async getBrokerSubscriptionsList() {
        return (await this.inventoryService.list(this.filters)).data;
    }
    /**
     * User status text (legacy compatibility)
     */
    getVisibleUserStatusText(user) {
        return user.enabled ? gettext('active`subscription`') : gettext('inactive`subscription`');
    }
    async remove(subscription) {
        // handle realtime unsubsribe
        if (this.moRealtimeSubscriptionsMap.has(subscription.id)) {
            this.moRealtimeSubscriptionsMap.get(subscription.id).unsubscribe();
            this.moRealtimeSubscriptionsMap.delete(subscription.id);
        }
        // handle removal
        const brokerSourceRenamed = `_${this.FRAGMENT_TYPE}`;
        set(subscription, this.FRAGMENT_TYPE, null);
        return await this.inventoryService.update(pick(subscription, ['id', this.FRAGMENT_TYPE, brokerSourceRenamed]));
    }
    async setStatus(subscription, enabled) {
        const userData = (await this.userService.update({
            id: subscription.userId,
            enabled
        })).data;
        subscription.userEnabled = userData.enabled;
        subscription.visibleUserStatus = this.getVisibleUserStatusText(userData);
        return subscription;
    }
    /**
     * List of pending subscriptions
     */
    async listPendingBrokerSubscriptions() {
        return (await this.deviceRegistrationService.list({
            pageSize: 2000,
            withTotalPages: true
        })).data;
    }
    /**
     * Accept subscription
     */
    async accept(code) {
        return (await this.deviceRegistrationService.accept(code)).data;
    }
    /**
     * Discard subscription
     */
    async discard(code) {
        return await this.deviceRegistrationService.delete(code);
    }
    /**
     * Add new subscription
     */
    async create(code) {
        return (await this.deviceRegistrationService.create({
            id: code,
            type: this.NEW_DEVICE_REQUEST_TYPE
        })).data;
    }
    getForNg1({ pollingInterval, onPendingSubscriptions, onExistingSubscriptions, onMoUpdate }) {
        const reload$ = new Subject();
        const destroy$ = new Subject();
        const ready$ = new Subject();
        const unsubscribeRealtime = () => {
            const moRealtimeSubscriptionIterator = this.moRealtimeSubscriptionsMap.keys();
            let key = moRealtimeSubscriptionIterator.next().value;
            while (this.moRealtimeSubscriptionsMap.has(key)) {
                this.moRealtimeSubscriptionsMap.get(key).unsubscribe();
                this.moRealtimeSubscriptionsMap.delete(key);
                key = moRealtimeSubscriptionIterator.next().value;
            }
        };
        const userInitialized$ = this.appStateService.currentUser.pipe(filter(currentUser => currentUser !== null));
        const triggers = merge(reload$, ready$);
        const pendingSubscriptions$ = merge(triggers, this.deviceBootstrapRealtimeService.onAll$(), this.refreshPendingTrigger$).pipe(switchMap(() => userInitialized$), switchMap(() => this.listPendingBrokerSubscriptions()), map(pendingSubscriptions => this.convertDeviceRegistrationsToSubscriptionViewModels(pendingSubscriptions)), takeUntil(destroy$));
        const existingSubscriptions$ = merge(triggers, interval(pollingInterval)).pipe(switchMap(() => userInitialized$), switchMap(() => this.getBrokerSubscriptionsList()), tap(mos => {
            if (this.subscriptionsCount !== mos.length) {
                this.refreshPendingTrigger$.next();
                this.subscriptionsCount = mos.length;
            }
            mos.forEach(mo => {
                if (!this.moRealtimeSubscriptionsMap.has(mo.id)) {
                    const mortObservable = this.moRealtimeService
                        .onUpdate$(mo.id)
                        .pipe(switchMap(mo => this.convertToViewModel([mo])));
                    this.moRealtimeSubscriptionsMap.set(mo.id, mortObservable.subscribe(onMoUpdate));
                }
            });
        }), distinctUntilChanged(), switchMap(mos => this.convertToViewModel(mos)), takeUntil(destroy$));
        return {
            init() {
                pendingSubscriptions$.subscribe(onPendingSubscriptions);
                existingSubscriptions$.subscribe(onExistingSubscriptions);
                setTimeout(() => {
                    ready$.next();
                }, 1000);
            },
            reload() {
                reload$.next();
            },
            destroy() {
                destroy$.next();
                destroy$.complete();
                unsubscribeRealtime();
            }
        };
    }
    convertDeviceRegistrationsToSubscriptionViewModels(pendingSubscriptions) {
        const convertedToViewModel = pendingSubscriptions
            .filter(deviceRequest => deviceRequest.type === this.NEW_DEVICE_REQUEST_TYPE)
            .map(deviceRequest => {
            return Object.assign({}, get(deviceRequest, 'customProperties.c8y_BrokerSource'), {
                status: this.newDeviceRequestStatusViewModelFactory.build(deviceRequest.status),
                type: deviceRequest.type,
                id: deviceRequest.id
            });
        });
        return convertedToViewModel;
    }
    generateDeviceRequestStatusEnum(newDeviceRequestViewModelFactory) {
        const result = {};
        for (const status in DeviceRegistrationStatus) {
            Object.defineProperty(result, status, {
                enumerable: true,
                writable: false,
                configurable: false,
                value: newDeviceRequestViewModelFactory.build(status)
            });
        }
        return result;
    }
    // Function maps data in suitable manner to have it easier to display. Used in service mainly for compatibility
    async convertToViewModel(subscriptions) {
        const viewModelSubscriptions = subscriptions.map(async (subscription) => {
            const { data: userDetails } = await this.userService.detail(subscription.owner);
            return {
                userEnabled: userDetails.enabled,
                visibleUserStatus: this.getVisibleUserStatusText(userDetails), //TODO:IIAR should be extracted to ngx pipe when the rest of data-broker is migrated
                userId: userDetails.id,
                status: this.getStatusViewModel(subscription.c8y_BrokerSource.status), //TODO:IIAR should be extracted to ngx pipe when the rest of data-broker is migrated
                id: subscription.id,
                _c8y_BrokerSource: subscription.c8y_BrokerSource
            };
        });
        return Promise.all(viewModelSubscriptions);
    }
    // Status decoration (legacy compatibility)
    getStatusViewModel(status) {
        return this.subscriptionStatusViewModelFactory.build(status);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataBrokerSubscriptionsService, deps: [{ token: i1.ManagedObjectRealtimeService }, { token: i1.DeviceBootstrapRealtimeService }, { token: i2.InventoryService }, { token: i2.UserService }, { token: i2.DeviceRegistrationService }, { token: i1.AppStateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataBrokerSubscriptionsService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataBrokerSubscriptionsService, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: i1.ManagedObjectRealtimeService }, { type: i1.DeviceBootstrapRealtimeService }, { type: i2.InventoryService }, { type: i2.UserService }, { type: i2.DeviceRegistrationService }, { type: i1.AppStateService }] });

class DataBrokerModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataBrokerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.19", ngImport: i0, type: DataBrokerModule, imports: [CoreModule] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataBrokerModule, providers: [
            DataBrokerSubscriptionsService,
            ManagedObjectRealtimeService,
            DeviceBootstrapRealtimeService
        ], imports: [CoreModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DataBrokerModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [],
                    imports: [CoreModule],
                    providers: [
                        DataBrokerSubscriptionsService,
                        ManagedObjectRealtimeService,
                        DeviceBootstrapRealtimeService
                    ],
                    exports: []
                }]
        }] });

const dataBrokerSubscriptionsServiceDowngradedInjectable = downgradeInjectable(DataBrokerSubscriptionsService);

const NAME_DATA_BROKER = 'c8y.upgrade.dataBroker';
angular
    .module(NAME_DATA_BROKER, [])
    .service('c8yDataBrokerSubscriptionsService', dataBrokerSubscriptionsServiceDowngradedInjectable);
const ng1ModulesDataBroker = [NAME_DATA_BROKER];
registerNgModule(ng1ModulesDataBroker);

/**
 * Generated bundle index. Do not edit.
 */

export { DataBrokerModule, dataBrokerSubscriptionsServiceDowngradedInjectable, ng1ModulesDataBroker };
//# sourceMappingURL=c8y-ngx-components-data-broker.mjs.map
