import { DEFAULT_AUTO_REFRESH, DEFAULT_PORT_MAPPING_TTL, DEVICE_WAN_IP_CONNECTION_2 } from './constants.js';
import { InternetGatewayService } from './internet-gateway-service.js';
import { findNamespacedKey } from './utils.js';
export class InternetGatewayService4 extends InternetGatewayService {
    async mapPort(localPort, localHost, options = {}) {
        const mapping = {
            remoteHost: options.remoteHost ?? '',
            externalPort: `${options.externalPort ?? localPort}`,
            internalClient: localHost,
            protocol: options.protocol?.toUpperCase() === 'UDP' ? 'UDP' : 'TCP',
            description: options.description ?? this.options.description ?? '@achingbrain/nat-port-mapper',
            ttl: Math.max(Math.round((options.ttl ?? this.options.ttl ?? DEFAULT_PORT_MAPPING_TTL) / 1000), 3600)
        };
        this.log('creating mapping for local port %d to %j', localPort, mapping);
        const gateway = await this.getGateway(options);
        const response = await gateway.run(DEVICE_WAN_IP_CONNECTION_2, 'AddAnyPortMapping', [
            ['NewRemoteHost', mapping.remoteHost],
            ['NewExternalPort', mapping.externalPort],
            ['NewProtocol', mapping.protocol],
            ['NewInternalPort', localPort],
            ['NewInternalClient', mapping.internalClient],
            ['NewEnabled', 1],
            ['NewPortMappingDescription', mapping.description],
            ['NewLeaseDuration', mapping.ttl]
        ], options);
        // UPnP2 will resolve port mapping conflicts for us so we need to read the
        // mapped port from the response
        const key = findNamespacedKey('AddAnyPortMappingResponse', response);
        if (options.autoRefresh ?? this.options.autoRefresh ?? DEFAULT_AUTO_REFRESH) {
            this.configureRefresh(localPort, mapping, options);
        }
        this.addMapping(localPort, mapping);
        return Number(response[key].NewReservedPort);
    }
    async refreshPort(localPort, options) {
        const mappings = this.mappings.get(localPort) ?? [];
        for (const mapping of mappings) {
            try {
                const gateway = await this.getGateway(options);
                await gateway.run(DEVICE_WAN_IP_CONNECTION_2, 'AddAnyPortMapping', [
                    ['NewRemoteHost', mapping.remoteHost],
                    ['NewExternalPort', mapping.externalPort],
                    ['NewProtocol', mapping.protocol],
                    ['NewInternalPort', localPort],
                    ['NewInternalClient', mapping.internalClient],
                    ['NewEnabled', 1],
                    ['NewPortMappingDescription', mapping.description],
                    ['NewLeaseDuration', mapping.ttl]
                ], options);
            }
            catch (err) {
                this.log.error('could not refresh port %d mapping - %e', localPort, err);
            }
            this.configureRefresh(localPort, mapping, options);
        }
    }
    async unmap(localPort, options) {
        const mappings = this.mappings.get(localPort) ?? [];
        for (const mapping of mappings) {
            try {
                clearTimeout(mapping.refreshTimeout);
                const gateway = await this.getGateway(options);
                await gateway.run(DEVICE_WAN_IP_CONNECTION_2, 'DeletePortMapping', [
                    ['NewRemoteHost', ''],
                    ['NewExternalPort', localPort],
                    ['NewProtocol', '']
                ], options);
            }
            catch (err) {
                this.log.error('could not unmap port %d - %e', localPort, err);
            }
        }
        this.mappings.delete(localPort);
    }
}
//# sourceMappingURL=internet-gateway-service-4.js.map