import { ResultCode } from '@iotize/tap/client/api';
import { TapApduRequestConverter, TapApduResponseConverter, TapClient, TapClientError, TapResponseFrameBuilder, } from '@iotize/tap/client/impl';
import { from, of, Subject, throwError } from 'rxjs';
import { delay, first, timeout } from 'rxjs/operators';
import { debug } from '../debug';
import { createMockProtocol } from './mock-protocol';
import { MockRouter } from './mock-router';
const TAG = 'MockClient';
export function createMockClient(options) {
    return new MockClient({
        isConnected: !!(options === null || options === void 0 ? void 0 : options.connected)
    });
}
export class MockClient extends TapClient {
    constructor(options = {}, router = new MockRouter()) {
        super(new TapApduRequestConverter(), new TapApduResponseConverter());
        this.router = router;
        this.input = new Subject();
        this.output = new Subject();
        this.options = Object.assign(Object.assign({}, MockClient.DEFAULT_OPTIONS), options);
    }
    isConnected() {
        return this.options.isConnected;
    }
    // /**
    //  *
    //  * TOPO add support for parameters ?
    //  * TODO use Shell Grammar instead ?
    //  *
    //  * @param map
    //  */
    // public static createFromMap(map: MappingType): MockClient {
    //     const client = new MockClient();
    //     client.addRoutes(map);
    //     return client;
    // }
    static createWithMockProtocol() {
        const client = new MockClient({
            isConnected: false
        });
        client.addComProtocol(createMockProtocol());
        return client;
    }
    connect() {
        const observable = of(undefined).pipe(delay(this.options.connect.delay));
        observable.subscribe(() => {
            this.options.isConnected = true;
        });
        return observable;
    }
    disconnect() {
        const observable = of(undefined).pipe(delay(this.options.disconnect.delay));
        observable.subscribe(() => {
            this.options.isConnected = false;
        });
        return observable;
    }
    mockResponse(tapResponse) {
        this.output.next(tapResponse);
    }
    request(request) {
        if (!this.isConnected()) {
            return throwError(TapClientError.notConnectedError());
        }
        const responseP = this.output
            .pipe(
        // tap(event => console.log('EVENT', event)),
        first(), delay(this.options.command.delay), timeout(this.options.command.timeout))
            .toPromise();
        this.input.next(request);
        return from(responseP);
    }
    // /**
    //  * @deprecated in favor of addRoute
    //  * @param cmd
    //  * @param response
    //  */
    // public mapCommandToResponse(cmd: Command, response: TapResponse<any>) {
    //     return this.addRoute(cmd, response);
    // }
    // public addRoute<T>(
    //     command: Command | string | RegExp | TapRequestFilter,
    //     response: ResponseMapType
    // ): this {
    //     debug(
    //         TAG,
    //         `\t- Mapping command ${command.toString()} to response ${response.toString()}`
    //     );
    //     if (command instanceof RegExp) {
    //         throw new Error(
    //             `Route with regular expressions are not implemented yet`
    //         );
    //     } else if (typeof command === 'string') {
    //         command = Util.parseApiRequestString(command);
    //     }
    //     this.router.addRoute(
    //         command,
    //         this.createResponse(command, response)
    //     );
    //     return this;
    // }
    // public addRoutes(map: MappingType): this {
    //     for (const pathString in map) {
    //         const info = map[pathString];
    //         const command: Command = Util.parseApiRequestString(pathString);
    //         const response = this.createResponse(command, info);
    //         this.addRoute(command, response);
    //     }
    //     return this;
    // }
    // public hasRoute(command: Command | string): boolean {
    //     if (typeof command === 'string') {
    //         command = Util.parseApiRequestString(command);
    //     }
    //     return this.router.findRoute(command) != undefined;
    // }
    // createResponse<T>(
    //     command: Command | TapRequestFilter,
    //     info: ResponseMapType
    // ): TapResponse<T> | ResponseAdapterFunction<any> {
    //     let response: TapResponse<T>;
    //     if (typeof info === 'number') {
    //         response = TapResponse.create(info);
    //     } else if (typeof info === 'string') {
    //         response = new TapResponse(hexStringToBuffer(info));
    //     } else if (typeof info === 'object') {
    //         if (info instanceof TapResponse) {
    //             response = info;
    //         } else {
    //             response = TapResponse.create(typeof info.codeRet === 'number' ? info.codeRet : info.status);
    //             (response as TapResponse<T>).setBody(info.body);
    //         }
    //     } else if (typeof info === 'function') {
    //         if (command instanceof ApiRequest) {
    //             response = info(command);
    //         } else {
    //             return (command: TapRequestFrame) => {
    //                 const response = info(command);
    //                 if (response instanceof ResponseImpl) {
    //                     response.setRequest(command);
    //                 }
    //                 return response;
    //             };
    //         }
    //     } else {
    //         throw new Error(
    //             `Invalid payload type from key ${command.toString()}`
    //         );
    //     }
    //     if (command instanceof ApiRequest && response instanceof ResponseImpl) {
    //         response.setRequest(command);
    //     }
    //     return response;
    // }
    computeResponse(cmd) {
        const response = this.router.findRoute(cmd);
        if (response) {
            return response;
        }
        else {
            debug(TAG, `MockClient`, `command ${cmd} has not been mapped. Returning 404 not found`);
            return TapResponseFrameBuilder.ERROR(ResultCode.NOT_FOUND);
        }
    }
}
MockClient.DEFAULT_OPTIONS = {
    isConnected: false,
    connect: {
        delay: 100
    },
    disconnect: {
        delay: 100
    },
    command: {
        delay: 100,
        timeout: 500
    },
    encryption: true
};
//# sourceMappingURL=data:application/json;base64, 