import * as i0 from '@angular/core';
import { inject, Injectable } from '@angular/core';
import * as i1 from '@c8y/client';
import * as i2 from '@c8y/ngx-components';
import { Permissions, ContextRouteService, ViewContext } from '@c8y/ngx-components';
import { gettext } from '@c8y/ngx-components/gettext';
import { defer, shareReplay } from 'rxjs';
import { uniqWith, isEqual, intersectionWith } from 'lodash';

const CREDENTIALS_TYPES = {
    NONE: {
        name: 'NONE',
        value: 'NONE',
        label: gettext('No password')
    },
    USER_PASS: {
        name: 'USER_PASS',
        value: 'USER_PASS',
        label: gettext('Username and password')
    },
    PASS_ONLY: {
        name: 'PASS_ONLY',
        value: 'PASS_ONLY',
        label: gettext('Password only')
    },
    KEY_PAIR: {
        name: 'KEY_PAIR',
        value: 'KEY_PAIR',
        label: gettext('Public/private keys')
    },
    CERTIFICATE: {
        name: 'CERTIFICATE',
        value: 'CERTIFICATE',
        label: gettext('Certificate')
    }
};
const canActivateRemoteAccess = (route) => {
    const permissions = inject(Permissions);
    const remoteAccessService = inject(RemoteAccessService);
    const contextRouteService = inject(ContextRouteService);
    if (!permissions.hasRole(Permissions.ROLE_REMOTE_ACCESS_ADMIN)) {
        return false;
    }
    const contextDetails = contextRouteService.getContextData(route);
    if (contextDetails.context !== ViewContext.Device) {
        return false;
    }
    const device = contextDetails.contextData;
    if (!device || !Array.isArray(device.c8y_SupportedOperations)) {
        return false;
    }
    const supportedOperations = device.c8y_SupportedOperations;
    if (!supportedOperations.includes('c8y_RemoteAccessConnect')) {
        return false;
    }
    return remoteAccessService.isAvailable$();
};
class RemoteAccessService {
    constructor(fetchClient, serviceRegistry) {
        this.fetchClient = fetchClient;
        this.serviceRegistry = serviceRegistry;
        this.baseUrl = '/service/remoteaccess';
    }
    /**
     * Verifies if the remote access service is available by sending a HEAD request to is's health endpoint.
     * @returns cached Observable that emits true if the service is available, false otherwise.
     */
    isAvailable$() {
        if (!this.cachedIsAvailable$) {
            this.cachedIsAvailable$ = defer(() => this.healthEndpointAvailable()).pipe(shareReplay(1));
        }
        return this.cachedIsAvailable$;
    }
    /**
     * misses the leading ? for the query params
     */
    getAuthQueryParamsForWebsocketConnection() {
        const { headers } = this.fetchClient.getFetchOptions();
        const params = new URLSearchParams();
        if (headers) {
            const xsrfToken = headers['X-XSRF-TOKEN'];
            const auth = headers['Authorization'];
            if (xsrfToken) {
                params.append('XSRF-TOKEN', xsrfToken);
            }
            if (auth) {
                params.append('token', auth.replace('Bearer ', '').replace('Basic ', ''));
            }
        }
        const paramsString = params.toString();
        return paramsString;
    }
    /**
     * Returns the URI for the websocket connection to the remote access service.
     */
    getWebSocketUri(deviceId, configurationId) {
        const authQueryParams = this.getAuthQueryParamsForWebsocketConnection();
        const protocol = window.location.protocol === 'http:' ? 'ws' : 'wss';
        const pathName = `${protocol}://${window.location.host}${this.baseUrl}/client/${deviceId}/configurations/${configurationId}`;
        return authQueryParams ? `${pathName}?${authQueryParams}` : pathName;
    }
    /**
     * Retrieves all configurations for a given device.
     */
    async listConfigurations(deviceId) {
        const response = await this.fetchClient.fetch(`${this.baseUrl}/devices/${deviceId}/configurations`);
        if (response.ok) {
            return response.json();
        }
        throw new Error(`Failed to fetch configurations for device ${deviceId}`);
    }
    /**
     * Deletes a configuration for a given device.
     */
    async deleteConfiguration(deviceId, configurationId) {
        const response = await this.fetchClient.fetch(`${this.baseUrl}/devices/${deviceId}/configurations/${configurationId}`, { method: 'DELETE' });
        if (response.ok) {
            return;
        }
        throw new Error(`Failed to delete configuration for device ${deviceId}`);
    }
    /**
     * Retrieves all available remote access protocol providers.
     */
    getProtocolProviders() {
        return this.serviceRegistry.get('remoteAccessProtocolHook');
    }
    /**
     * Retrieves all supported protocol providers for a given device.
     * Based on the declarations in the fragment c8y_RemoteAccessSupportedProtocols of the device managed object.
     */
    getSupportedProtocolProvidersFor(device) {
        const { c8y_RemoteAccessSupportedProtocols = [] } = device;
        const uniqueInput = uniqWith(c8y_RemoteAccessSupportedProtocols.map(p => p.toUpperCase()), isEqual);
        const supportedProviders = intersectionWith(this.getProtocolProviders(), uniqueInput, ({ protocolName }, protocol) => protocolName?.toUpperCase() === protocol);
        return supportedProviders?.length > 0 ? supportedProviders : this.getProtocolProviders();
    }
    /**
     * Creates a new configuration for a given device.
     */
    async addConfiguration(deviceId, configuration) {
        const response = await this.fetchClient.fetch(`${this.baseUrl}/devices/${deviceId}/configurations`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(configuration)
        });
        if (response.ok) {
            return response.json();
        }
        throw new Error(`Failed to add configuration for device ${configuration.attrs.deviceId}`);
    }
    /**
     * Updates a configuration for a given device.
     */
    async updateConfiguration(deviceId, configuration) {
        const response = await this.fetchClient.fetch(`${this.baseUrl}/devices/${deviceId}/configurations/${configuration.id}`, {
            method: 'PUT',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(configuration)
        });
        if (response.ok) {
            return response.json();
        }
        throw new Error(`Failed to update configuration for device ${configuration.attrs.deviceId}`);
    }
    /**
     * Generates a SSH key pair for a given hostname.
     */
    async generateKeyPair(hostname) {
        const response = await this.fetchClient.fetch(`${this.baseUrl}/keypair/generate`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ hostname })
        });
        if (response.ok) {
            return response.json();
        }
        throw new Error(`Failed to generate key pair for ${hostname}`);
    }
    async healthEndpointAvailable() {
        try {
            const response = await this.fetchClient.fetch(`${this.baseUrl}/health`, {
                method: 'HEAD',
                headers: {
                    'Content-Type': 'application/json'
                }
            });
            if (response.ok) {
                return !!response.ok;
            }
        }
        catch (e) {
            return false;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: RemoteAccessService, deps: [{ token: i1.FetchClient }, { token: i2.ServiceRegistry }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: RemoteAccessService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: RemoteAccessService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }], ctorParameters: () => [{ type: i1.FetchClient }, { type: i2.ServiceRegistry }] });

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

export { CREDENTIALS_TYPES, RemoteAccessService, canActivateRemoteAccess };
//# sourceMappingURL=c8y-ngx-components-remote-access-data.mjs.map
