import {BASE_URL} from "../constants/apiConstants";
import {
    ApiResponse, InstrumentDto,
    InstrumentListDto,
    InverterDto,
    InverterListDto,
    JwtAuthenticationResponse,
    LoginRequest, MeasurementDataDto, MeasurementPickerDto,
    MonitoredAreaDto,
    MonitoredAreaListDto, PickedMeasurementsDto,
    UserSummary
} from "./RequestBodyData";

export class ApiRequestStore {
    login = (body: LoginRequest): Promise<JwtAuthenticationResponse> => this.createRequest<JwtAuthenticationResponse>({
        url: `${BASE_URL}/api/auth/signin`,
        method: "POST",
        body: JSON.stringify(body)
    });


    getCurrentUser = (): Promise<UserSummary> => {
        if (!localStorage.getItem("accessToken")) {
            return Promise.reject("No access token set.")
        }

        return this.createRequest<UserSummary>({
            url: `${BASE_URL}/api/user/me`,
            method: "GET"
        })
    };

    createNewInstrument = (body: InstrumentDto): Promise<ApiResponse> => this.createRequest<ApiResponse>(
        {
            url: `${BASE_URL}/api/instruments`,
            method: "POST",
            body: JSON.stringify(body)
        }
    );

    loadInstruments = (): Promise<InstrumentListDto> => this.createRequest<InstrumentListDto>(
        {
            url: `${BASE_URL}/api/instruments`,
            method: "GET",
        }
    );

    updateInstrument = (body: InstrumentDto): Promise<ApiResponse> => this.createRequest<ApiResponse>(
        {
            url: `${BASE_URL}/api/instruments`,
            method: "PUT",
            body: JSON.stringify(body)
        }
    );

    createNewInverter = (body: InverterDto): Promise<ApiResponse> => this.createRequest<ApiResponse>(
        {
            url: `${BASE_URL}/api/inverters`,
            method: "POST",
            body: JSON.stringify(body)
        }
    );

    loadInverters = (): Promise<InverterListDto> => this.createRequest<InverterListDto>(
        {
            url: `${BASE_URL}/api/inverters`,
            method: "GET",
        }
    );

    updateInverter = (body: InverterDto): Promise<ApiResponse> => this.createRequest<ApiResponse>(
        {
            url: `${BASE_URL}/api/inverters`,
            method: "PUT",
            body: JSON.stringify(body)
        }
    );

    createNewMonitoredArea = (body: MonitoredAreaDto): Promise<ApiResponse> => this.createRequest<ApiResponse>(
        {
            url: `${BASE_URL}/api/monitoredAreas`,
            method: "POST",
            body: JSON.stringify(body)
        }
    );

    loadMonitoredAreas = (): Promise<MonitoredAreaListDto> => this.createRequest<MonitoredAreaListDto>(
        {
            url: `${BASE_URL}/api/monitoredAreas`,
            method: "GET",
        }
    );

    updateMonitoredArea = (body: MonitoredAreaDto): Promise<ApiResponse> => this.createRequest<ApiResponse>(
        {
            url: `${BASE_URL}/api/monitoredAreas`,
            method: "PUT",
            body: JSON.stringify(body)
        }
    );

    loadMeasurementOptions = (): Promise<MeasurementPickerDto> => this.createRequest<MeasurementPickerDto>(
        {
            url: `${BASE_URL}/api/measurement/displayOptions`,
            method: "GET",
        }
    );

    loadMeasurementData = (body: PickedMeasurementsDto): Promise<MeasurementDataDto> => this.createRequest<MeasurementDataDto>(
        {
            url: `${BASE_URL}/api/measurement/data`,
            method: "POST",
            body: JSON.stringify(body)
        }
    );


    private createRequest = <T>(requestOptions: HttpRequest) => {
        const headers = this.createHeaders();
        requestOptions = this.assignDefaultValues(headers, requestOptions);
        return fetch(requestOptions.url, requestOptions)
            .then(response => {
                return response.json().then
                (json => {
                    if (!response.ok) {
                        console.log("error response");
                        return Promise.reject(json)
                    }
                    console.log("success response");
                    return json as Promise<T>;
                })
            })
    };

    private assignDefaultValues = (headers: Headers, options: HttpRequest) => {
        const defaults = {headers: headers};
        const request = {} as Request;
        return Object.assign(request, defaults, options);
    };

    private createHeaders = () => {
        const headers = new Headers();
        headers.append("Content-Type", "application/json");
        this.appendAccessTokenIfInLocalStorage(headers);
        return headers;
    };

    private appendAccessTokenIfInLocalStorage = (headers: Headers) => {
        const token = localStorage.getItem("accessToken");
        if (token) {
            headers.append("Authorization", `Bearer ${token}`)
        }
    }
}

export const createApiRequestStore = () => new ApiRequestStore();

type HttpRequest = {
    url: string,
    method: string,
    body?: string
}