import {
    TransportConfiguration,
    PostMessageBusTransport,
    AppPeer
} from "@talentsoft-opensource/integration-com-layer";
import {
    AppService,
    WidgetContext,
    PartnerUrl,
    RequestOptionsWithPartner,
    AppHeaderActionConfiguration
} from "@talentsoft-opensource/integration-widget-component";
import {
    GenericHttpResponse,
    HttpResponse,
    RequestOptions,
    TrackEventOptions
} from "@talentsoft-opensource/integration-widget-contract";
import { WidgetDefinition } from "./widget-definition";

export function getAppService(definition: WidgetDefinition) {
    const appPeer = getAppPeer(definition.name);
    const appService = wrapAppPeer(appPeer);
    return appService;
}

type HostApiMethod =
    | keyof Omit<AppService, "on" | "loadData">
    | "call";

const HOST_API: Record<HostApiMethod, string> = {
    getContext: "getContext",
    expand: "expand",
    reduce: "reduce",
    restoreSize: "restoreSize",
    call: "call",
    openUrlInNewTab: "openUrlInNewTab",
    openUrlInCurrentTab: "openUrlInCurrentTab",
    getPreloadedResources: "getPreloadedResources",
    requestExternalResource: "requestExternalResource",
    requestInternalResource: "requestInternalResource",
    requestInternalResourceAsArrayBuffer: "requestInternalResourceAsArrayBuffer",
    setHeaderActionConfiguration: "setHeaderActionConfiguration",
    downloadExternalResource: "downloadExternalResource",
    trackEvent: "trackEvent",
};

function getAppPeer(name: string) {
    const transport = createClientTransport(name);
    const app = AppPeer.new(transport, "host", HOST_API, 20000);
    app.init();
    return app;
}

function createClientTransport(name: string) {
    const destinations = {
        host: window.parent,
        [name]: window
    };
    const config: TransportConfiguration = {
        locationId: name,
        locationResolver: (id: string) => destinations[id]
    };
    const transport = new PostMessageBusTransport(config);
    transport.init();
    return transport;
}

function wrapAppPeer<
    T extends {
        [name: string]: string;
    }
>(app: AppPeer<T>): AppService {
    const host = app.host;
    const appService: AppService = {
        getContext: host.getContext as (id: string) => Promise<WidgetContext>,
        on: app.on as any,
        restoreSize: host.restoreSize as (appid: string) => Promise<void>,
        expand: host.expand as (appid: string) => Promise<void>,
        reduce: host.reduce as (appid: string) => Promise<void>,
        openUrlInNewTab: host.openUrlInNewTab as (
            url: PartnerUrl
        ) => Promise<void>,
        openUrlInCurrentTab: host.openUrlInCurrentTab as (
            url: PartnerUrl
        ) => Promise<void>,
        loadData: host.call as (partnerName: string) => Promise<object[]>,
        getPreloadedResources: host.getPreloadedResources as (
            language: string
        ) => Promise<Record<string, string>>,
        requestExternalResource: host.requestExternalResource as (
            options: RequestOptionsWithPartner
        ) => Promise<HttpResponse>,
        requestInternalResource: host.requestInternalResource as (
            options: RequestOptions
        ) => Promise<HttpResponse>,
        requestInternalResourceAsArrayBuffer: host.requestInternalResourceAsArrayBuffer as (
            options: RequestOptions
        ) => Promise<GenericHttpResponse<ArrayBuffer>>,
        setHeaderActionConfiguration: host.setHeaderActionConfiguration as (
            appConfig: AppHeaderActionConfiguration
        ) => Promise<void>,
        downloadExternalResource: host.downloadExternalResource as (
            options: RequestOptionsWithPartner
        ) => void,
        trackEvent: host.trackEvent as (trackEventOptions: TrackEventOptions
        ) => void,
    };
    return appService;
}
