import { Fail, Failure, Ok } from '../../fail';
import { Http, HttpResponseType } from '../../http';

/** Represents a MapBox access token. Use it to access the MapBox Rest API's */
export interface MapBoxAccessToken {
    /** Access token. Can be used in calls to the MapBox API. This is what should be used
     * in MapBox API calls.
     */
    token: string;

    /** MapBox scopes the token is valid for. */
    scopes: string[];

    /** Url this access token is valid for. The token will not work if used from another url. */
    allowedUrl: string;
}

/** Error response used when the backend (that {@link MapBoxApiClient} calls) detects invalid request parameters. */
export interface MapBoxAccessTokenValidationFailure {
    /** HTTP status code */
    status: 400;
    /** title */
    title: string;
    /** Gives reason for failure */
    errors: {
        [key: string]: string[];
    };
}

/** Error response used when the backend (that {@link MapBoxApiClient} calls) has issues calling MapBox upstream. */
export interface MapBoxAccessTokenUpstreamProblem {
    /** HTTP status code */
    status: 502;
    /** Details  */
    detail: string;
    /** Title  */
    title: string;
}

/** Represents a MapBox access token response. */
export type MapBoxAccessTokenResponse =
    | MapBoxAccessToken
    | Failure<MapBoxAccessTokenValidationFailure | MapBoxAccessTokenUpstreamProblem>;

/** Api to access MapBox functionality. */
export interface MapBoxApiClient {
    /**
     * Gets a MapBox access token for the specified hostname. The token can then be used in direct calls to the MapBox REST API.
     * See MapBox documentation on how to use the token.
     * @param hostname - The hostname to get the access token for. If not specified, `window.location.hostname` is used.
     * @returns A MapBox access token or a failure response. Use {@link isFailure} to check if the response is a failure.
     */
    getAccessToken(hostname?: string): Promise<MapBoxAccessTokenResponse>;
}

/** Api to access MapBox functionality in the Twinfinity backend. */
export class TwinfinityMapBoxApiClient implements MapBoxApiClient {
    public constructor(private readonly _baseUrl: URL) {}

    public async getAccessToken(hostname = window.location.hostname): Promise<MapBoxAccessTokenResponse> {
        const response = await Http.get<MapBoxAccessToken>(
            `${this._baseUrl}_ps/api/mapbox/token?hostname=${hostname}`,
            HttpResponseType.json
        );
        if (response.status !== 200) return Fail(await response.json());
        return Ok(response.value);
    }
}
