import { WidgetSize } from "@talentsoft-opensource/integration-widget-component";
import {
    TransportConfiguration,
    HostPeer
} from "@talentsoft-opensource/integration-com-layer";
import { HostEventApi } from "./service-host";

export interface HostedWidget {
    id: string;
    size: WidgetSize;
    enlargeable: boolean;
    url: string;
    title: string;
    params: Record<string, string>;
}

function getWindowFromId(targetId: string, hostName: string): Window {
    if (targetId === hostName) {
        return window;
    }

    const iframe = document.getElementById(targetId) as HTMLIFrameElement;
    if (!iframe) {
        throw new Error(`iframe not found: ${targetId}`);
    }
    return iframe.contentWindow!;
}

export function getTransportConfig(hostName: string): TransportConfiguration {
    const hostConfig: TransportConfiguration = {
        locationId: hostName,
        locationResolver: function(targetId) {
            return getWindowFromId(targetId, hostName);
        }
    };
    return hostConfig;
}

export type HostedWidgetCollection = Record<string, HostedWidget>;

export interface IWidgetCollectionController {
    getWidget(id: string): HostedWidget;
    expand(id: string): void;
    reduce(id: string): void;
    restoreSize(id: string): void;
    setEnlargeable(id: string, enlargeable: boolean): void;
}

export class WidgetCollectionController implements IWidgetCollectionController {
    public hostPeer?: HostPeer<HostEventApi>;
    public widgetGetter?: () => HostedWidgetCollection;
    public widgetSetter?: (w: HostedWidgetCollection) => void;

    constructor() {}

    private getHostPeer(): HostPeer<HostEventApi> {
        if (!this.hostPeer) {
            throw new Error(
                "Host peer is not available in the WidgetCollectionController"
            );
        }
        return this.hostPeer!;
    }

    private getHostedWidgets(): HostedWidgetCollection {
        if (!this.widgetGetter) {
            throw new Error("widgetGetter is not provided.");
        }
        return this.widgetGetter();
    }

    private setHostedWidgets(widgets: HostedWidgetCollection) {
        if (!this.widgetSetter) {
            throw new Error("widgetSetter is not provided");
        }
        this.widgetSetter(widgets);
    }

    private checkId(id: string) {
        const widget = this.getHostedWidgets()[id];
        if (!widget) {
            throw new Error(`unknown widget: ${id}`);
        }
    }

    getWidget(id: string): HostedWidget {
        this.checkId(id);
        return this.getHostedWidgets()[id];
    }

    private deepclone(): HostedWidgetCollection {
        const collection = this.getHostedWidgets();
        const ids = Object.keys(collection);
        const result: HostedWidgetCollection = {};
        ids.forEach(id => {
            result[id] = { ...collection[id] };
        });
        return result;
    }

    expand = (id: string) => {
        this.checkId(id);
        const collection = this.deepclone();
        Object.values(collection).forEach(widget => {
            widget.size = WidgetSize.Minimized;
            this.getHostPeer().events.onSizeChangedToMinimized.notify(
                widget.id
            );
        });
        collection[id].size = WidgetSize.Enlarged;
        this.getHostPeer().events.onSizeChangedToEnlarged.notify(id);
        this.setHostedWidgets(collection);
    };

    reduce(id: string) {
        this.checkId(id);
        const collection = this.deepclone();
        Object.values(collection).forEach(widget => {
            widget.size = WidgetSize.Normal;
            this.getHostPeer().events.onSizeChangedToNormal.notify(widget.id);
        });
        this.setHostedWidgets(collection);
    }

    restoreSize(id: string) {
        this.checkId(id);
        const collection = this.deepclone();
        Object.values(collection).forEach(widget => {
            widget.size = WidgetSize.Normal;
            this.getHostPeer().events.onSizeChangedToNormal.notify(widget.id);
        });
        this.setHostedWidgets(collection);
    }

    setEnlargeable(id: string, enlargeable: boolean): void {
        this.checkId(id);
        const collection = this.deepclone();
        collection[id].enlargeable = enlargeable;
        this.setHostedWidgets(collection);
    }
}
