import axios, { AxiosResponse } from 'axios';
import { AxiosRequestConfig } from 'axios';
import { IHttpCommand } from '../commands/abstract/httpCommand';
import { HttpMethod } from '../commands/abstract/httpMethod';
import { VERSION } from '../constants';
import { Environment } from '../models/configuration/environment';
import { AbpResponse } from '../models/http/abpResponse';
import nonstop from '../nonstop';
import { BaseService } from './abstract/baseService';

class DataService extends BaseService {
    public static sharedInstance = new DataService();

    protected logTag: string = 'DataService';

    public async executeCommand<TRequest, TResponse, TError>(command: IHttpCommand<TRequest, TResponse, TError>): Promise<TResponse | null> {
        const rawResponse = await this.getResponseJson(command);
        const response = command.transformResponse(rawResponse);
        return response;
    }

    public async getFromExternalUrl(url: string) {
        const requestConfig: AxiosRequestConfig = {
            method: HttpMethod.Get,
            url,
        };
        await axios.request(requestConfig);
    }

    private async getResponseJson<TRequest, TResponse, TError>(command: IHttpCommand<TRequest, TResponse, TError>): Promise<AbpResponse<TResponse> | null> {
        const requestConfig: AxiosRequestConfig = {
            baseURL: this.getApiUrl(nonstop.config.environment),
            headers: {
                'Accept': 'application/json',
                'ClientName': nonstop.config.platform,
                'ClientVersion': VERSION,
                'Content-Type': 'application/json',
            },
            method: command.method,
            responseType: 'json',
            url: command.buildEndpoint(),
        };
        if (requestConfig.url && requestConfig.url.indexOf('{externalId}') !== -1) {
            this.logError('Use of this method requires a logged in user and no logged in user could be found.');
            return null;
        } else {
            this.logInfo(`Making ${command.method} request to ${requestConfig.url}`);
            if (command.method === HttpMethod.Get) {
                requestConfig.params = command.buildRequestContent();
                this.logInfo(`With query parameters ${JSON.stringify(requestConfig.params)}`);
            } else {
                requestConfig.data = command.buildRequestContent();
                this.logInfo(`With post data ${JSON.stringify(requestConfig.data)}`);
            }
            try {
                const response = await axios.request<AbpResponse<TResponse>>(requestConfig);
                this.logInfo('Request succeeded');
                this.logInfo(`Response data: ${JSON.stringify(response.data)}`);
                return response.data;
            } catch (e) {
                const response: AxiosResponse<AbpResponse<TError>> = e.response;
                this.logError('Request failed');
                this.logError(`Status code ${response.status}`);
                this.logError(`Status text ${response.statusText}`);
                this.logError(`Response data ${JSON.stringify(response.data)}`);
                command.handleError(response);
                return null;
            }
        }
    }

    private getApiUrl(environment: Environment) {
        switch (environment) {
            case Environment.Dev:
                return 'https://dev.api.nonstopapp.co/';
            case Environment.Staging:
                return 'https://staging.api.nonstopapp.co/';
            case Environment.QA:
                return 'https://qa.api.nonstopapp.co/';
            case Environment.Production:
                return 'https://api.nonstopapp.co/';
            case Environment.Local:
                return 'https://localhost:44300/';
        }
    }
}

export default DataService.sharedInstance as DataService;