import { HttpApi, IHttpOptions, IParserResponse, JSONParser } from '@3kles/3kles-corebe';
import { IMIRequest } from '../models/ion.model';

import { AuthService } from '../auth';

export interface IHttpIonOptions extends IHttpOptions {
    retryCounter?: number;
}

export class IONConnector extends HttpApi {

    private retry: number = (+process.env.RETRY || 3);

    constructor(private authService: AuthService, private ionOption: {
        protocol?: string,
        context: string,
        middleware?: string
    }) {
        super(ionOption.protocol || 'https');
        this.ionOption.middleware = this.ionOption.middleware ? (this.ionOption.middleware.startsWith("/") ? `` : `/`) + this.ionOption.middleware : null;
    }

    public buildRequest(params: any, originDataRequest?: any, data?: string): any {
        if (params.protocol) {
            this.protocol = params.protocol;
        }
        const iu = process.env.iu;
        const ti = process.env.ti;
        const context = process.env.context || this.ionOption.context;
        const url = new URL(process.env.m3 || `${iu}/${ti}/${context}`);
        const hostname = url.hostname;
        const port = (url.host.split(':').length > 1) ? +url.host.split(':')[1] : 443;

        const path = url.pathname + this.buildUrlApi(params);

        const options: IHttpIonOptions = {
            ...params,
            hostname: params.hostname || hostname,
            port: params.port || port,
            path,
            retryCounter: 0
        };
        if (data) {
            options.data = data;
        }
        return options;
    }

    public async executeRequest(options: any): Promise<{ statusCode: number; headers: any; body: any; }> {
        const token = await this.authService.getIONBEServiceToken();
        options.headers = { ...options.headers, Authorization: `${this.authService.formatAuthToken(token)}` };
        try {
            return await super.executeRequest(options);
        } catch (err) {
            console.error(err);
            if ((err.statusCode === 503 || err.statusCode === 502) && options.retryCounter < this.retry) {
                options.retryCounter = ~~options.retryCounter + 1;
                return await this.executeRequest(options);
            }
            throw err;
        }
    }

    public get middleware(): string {
        return this.ionOption.middleware;
    }

    public get context(): string {
        return this.ionOption.context;
    }

    private buildQueryApi(data: { [key: string]: string }): string {
        return '?' + Object.entries(data).map(([key, value]) => key + "=" + (value == null ? "" : encodeURIComponent(value)))
            .reduce((a: string, b: string) => a.trim() + '&' + b.trim(), '');
    }

    private buildUrlApi(request: IMIRequest): string {
        const url = (this.ionOption.middleware ? this.ionOption.middleware : '') + (request.path.startsWith("/") ? `` : `/`) + request.path;
        if (request.query) {
            return url + this.buildQueryApi(request.query);
        } else {
            return url;
        }
    }

}
