import { Injectable, Component, ViewChild, NgModule } from '@angular/core';
import { gettext, AlertService, ViewContext, CoreModule, FormsModule, HOOK_ROUTE } from '@c8y/ngx-components';
import { __awaiter } from 'tslib';
import { InventoryService, FetchClient, IdentityService } from '@c8y/client';
import { get } from 'lodash-es';
import { Router } from '@angular/router';
import { pipe } from 'rxjs';
import { map } from 'rxjs/operators';

class LpwanSetDeviceProtocolService {
    constructor(inventoryService, client, identityService) {
        this.inventoryService = inventoryService;
        this.client = client;
        this.identityService = identityService;
        this.supportedDevicesCfgs = [
            {
                name: 'lora',
                match: device => get(device, 'c8y_LpwanDevice.lpwanDeviceType') === 'Lora',
                protocolTypes: ['c8y_ActilityDeviceType', 'c8y_LoraDeviceType', 'c8y_LpwanDeviceType'],
                externalIdTypes: ['c8y_LoriotEUI', 'c8y_Serial']
            },
            {
                name: 'sigfox',
                match: device => get(device, 'c8y_LpwanDevice.serviceProvider') === 'Sigfox',
                protocolTypes: ['c8y_SigfoxDeviceType', 'c8y_LpwanDeviceType'],
                externalIdTypes: ['com.sigfox.deviceId']
            },
        ];
        this.header = { 'Content-Type': 'application/json' };
    }
    refreshCache(device) {
        return __awaiter(this, void 0, void 0, function* () {
            const externalId = yield this.getExternalId(device);
            if (externalId) {
                const url = `${this.getMicroserviceUrl(device)}/refreshCache/${externalId}`;
                const options = {
                    method: 'POST',
                    headers: this.header,
                    body: JSON.stringify({})
                };
                return this.client.fetch(url, options);
            }
        });
    }
    getMicroserviceUrl(device) {
        const { serviceProvider } = device.c8y_LpwanDevice;
        let serviceName = serviceProvider.toLowerCase();
        if (serviceProvider === 'Sigfox') {
            serviceName = 'sigfox-agent';
        }
        return `/service/${serviceName}`;
    }
    isSupportedDevice(device) {
        return this.supportedDevicesCfgs.some(({ match }) => match(device));
    }
    getCurrentProtocol(device) {
        return __awaiter(this, void 0, void 0, function* () {
            const lpwanDevice = device.c8y_LpwanDevice;
            let protocolId;
            if (lpwanDevice.typeExternalId) {
                const externalId = (yield this.identityService.detail(lpwanDevice.typeExternalId)).data;
                protocolId = externalId.managedObject.id;
            }
            if (!protocolId && lpwanDevice.type) {
                protocolId = lpwanDevice.type.split('/')[2];
            }
            if (!protocolId) {
                return null;
            }
            return (yield this.inventoryService.detail(protocolId)).data;
        });
    }
    applyProtocol(device, selectedProtocol) {
        return __awaiter(this, void 0, void 0, function* () {
            const [protocolExternalId] = (yield this.identityService.list(selectedProtocol.id)).data;
            const { externalId, type } = protocolExternalId;
            device.c8y_LpwanDevice.typeExternalId = { externalId, type };
            device.c8y_LpwanDevice.type = 'inventory/managedObjects/' + selectedProtocol.id;
            device.type = selectedProtocol.name;
            return this.inventoryService.update(device);
        });
    }
    getAvailableProtocols(device) {
        return __awaiter(this, void 0, void 0, function* () {
            const query = {
                type: {
                    __in: this.getProtocolTypesMatchingDevice(device)
                }
            };
            return this.inventoryService.listQuery(query, { pageSize: 100 });
        });
    }
    getProtocolTypesMatchingDevice(device) {
        const matchingCfg = this.supportedDevicesCfgs.find(({ match }) => match(device));
        return matchingCfg ? matchingCfg.protocolTypes : [];
    }
    getExternalId(device) {
        return __awaiter(this, void 0, void 0, function* () {
            const matchingCfg = this.supportedDevicesCfgs.find(({ match }) => match(device));
            const externalIds = (yield this.identityService.list(device.id)).data;
            const externalId = externalIds.find(({ type }) => matchingCfg.externalIdTypes.includes(type));
            return externalId ? externalId.externalId : null;
        });
    }
}
LpwanSetDeviceProtocolService.decorators = [
    { type: Injectable }
];
LpwanSetDeviceProtocolService.ctorParameters = () => [
    { type: InventoryService },
    { type: FetchClient },
    { type: IdentityService }
];

class LpwanAssignDeviceProtocolComponent {
    constructor(lpwanService, alertService, router, inventoryService) {
        this.lpwanService = lpwanService;
        this.alertService = alertService;
        this.router = router;
        this.inventoryService = inventoryService;
        this.filterCurrentProtocol = pipe(map((protocols) => protocols.filter(protocol => !this.currentProtocol || this.currentProtocol.id !== protocol.id)));
    }
    ngOnInit() {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.reload();
        });
    }
    reload() {
        return __awaiter(this, void 0, void 0, function* () {
            this.loading = true;
            this.newProtocol = null;
            try {
                yield this.loadDevice();
                this.availableProtocols = yield this.lpwanService.getAvailableProtocols(this.device);
                this.currentProtocol = yield this.lpwanService.getCurrentProtocol(this.device);
            }
            catch (ex) {
                this.alertService.addServerFailure(ex);
            }
            finally {
                this.loading = false;
            }
        });
    }
    loadDevice() {
        return __awaiter(this, void 0, void 0, function* () {
            const deviceId = this.router.routerState.snapshot.url.match(/\d+/)[0];
            const { data } = yield this.inventoryService.detail(deviceId);
            this.device = data;
        });
    }
    apply(selectedProtocol) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                const moUpdated = (yield this.lpwanService.applyProtocol(this.device, selectedProtocol)).res.status === 200;
                yield this.reload();
                this.alertService.success(gettext('Device protocol set.'));
                this.lpwanSetDeviceProtocolForm.reset('dirty');
                if (moUpdated) {
                    this.refreshCache();
                }
            }
            catch (ex) {
                this.alertService.danger(gettext('Could not set device protocol.'));
            }
        });
    }
    refreshCache() {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                yield this.lpwanService.refreshCache(this.device);
            }
            catch (ex) {
                // do nothing (refreshing is an optional step)
            }
        });
    }
}
LpwanAssignDeviceProtocolComponent.decorators = [
    { type: Component, args: [{
                selector: 'set-device-protocol',
                template: "<form #lpwanSetDeviceProtocolForm=\"ngForm\" class=\"row\">\n  <div class=\"col-md-6\">\n    <div class=\"card\">\n      <div class=\"card-header separator\">\n        <h4 class=\"card-title\">\n          {{ 'LPWAN device protocol' | translate }}\n        </h4>\n      </div>\n      <div *ngIf=\"loading\" class=\"card-block\">\n        <div class=\"p-relative\" style=\"min-height: 40px; min-width: 55px;\">\n          <div class=\"spinner\">\n            <div class=\"rect1\"></div>\n            <div class=\"rect2\"></div>\n            <div class=\"rect3\"></div>\n            <div class=\"rect4\"></div>\n          </div>\n        </div>\n        <span translate>Loading</span>\n      </div>\n      <div *ngIf=\"!loading\">\n        <div class=\"card-block\">\n          <div class=\"form-group\">\n            <label translate>Current device protocol</label>\n            <p class=\"form-control-static\" *ngIf=\"!currentProtocol\">\n              {{ device.type }}\n            </p>\n            <p class=\"form-control-static\" *ngIf=\"currentProtocol\">\n              {{ currentProtocol.name }}\n            </p>\n          </div>\n          <div class=\"form-group\">\n            <label translate>New device protocol</label>\n            <div class=\"c8y-select-wrapper\">\n              <select class=\"form-control\" [(ngModel)]=\"newProtocol\" name=\"newProtocol\" required>\n                <option *ngIf=\"!newProtocol\" [ngValue]=\"null\">\n                  {{ 'Select device protocol' | translate }}\n                </option>\n                <option\n                  *c8yFor=\"let protocol of availableProtocols; pipe: filterCurrentProtocol\"\n                  [ngValue]=\"protocol\"\n                >\n                  {{ protocol.name }}\n                </option>\n              </select>\n            </div>\n          </div>\n        </div>\n        <div class=\"card-footer separator\">\n          <button\n            title=\"{{ 'Apply' | translate }}\"\n            class=\"btn btn-primary\"\n            (click)=\"apply(newProtocol)\"\n            [disabled]=\"!lpwanSetDeviceProtocolForm.dirty\"\n          >\n            {{ 'Apply' | translate }}\n          </button>\n        </div>\n      </div>\n    </div>\n  </div>\n</form>\n\u200C\n"
            },] }
];
LpwanAssignDeviceProtocolComponent.ctorParameters = () => [
    { type: LpwanSetDeviceProtocolService },
    { type: AlertService },
    { type: Router },
    { type: InventoryService }
];
LpwanAssignDeviceProtocolComponent.propDecorators = {
    lpwanSetDeviceProtocolForm: [{ type: ViewChild, args: ['lpwanSetDeviceProtocolForm', { static: false },] }]
};

class LpwanAgentGuard {
    constructor(lpwanService) {
        this.lpwanService = lpwanService;
    }
    canActivate(route) {
        const device = route.data.contextData || route.parent.data.contextData;
        return this.lpwanService.isSupportedDevice(device);
    }
}
LpwanAgentGuard.decorators = [
    { type: Injectable }
];
LpwanAgentGuard.ctorParameters = () => [
    { type: LpwanSetDeviceProtocolService }
];

const routes = [
    {
        context: ViewContext.Device,
        path: 'assign-protocol',
        component: LpwanAssignDeviceProtocolComponent,
        label: gettext('LPWAN'),
        icon: 'c8y-device-protocols',
        canActivate: [LpwanAgentGuard]
    }
];
const ɵ0 = routes;
class LpwanProtocolModule {
}
LpwanProtocolModule.decorators = [
    { type: NgModule, args: [{
                declarations: [
                    LpwanAssignDeviceProtocolComponent
                ],
                imports: [
                    CoreModule,
                    FormsModule
                ],
                entryComponents: [LpwanAssignDeviceProtocolComponent],
                providers: [
                    LpwanAgentGuard,
                    LpwanSetDeviceProtocolService,
                    {
                        provide: HOOK_ROUTE,
                        useValue: ɵ0,
                        multi: true
                    }
                ]
            },] }
];

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

export { LpwanAssignDeviceProtocolComponent, LpwanProtocolModule, ɵ0, LpwanSetDeviceProtocolService as ɵa, LpwanAgentGuard as ɵb };
//# sourceMappingURL=c8y-ngx-components-protocol-lpwan.js.map
