import {
    AppValue,
    BaseAppDataMap,
    BaseEventMap,
} from './types'
import {BehaviorSubject} from './BehaviorSubject'

export type BaseApp = App<BaseEventMap, BaseAppDataMap>

export const app = (): BaseApp|undefined => {
    return (window as any).exAppInstance
}

export class App<TEventMap extends BaseEventMap, TDataMap extends BaseAppDataMap> {
    private data: Partial<TDataMap> = {}

    private events: Partial<{
        [EventKey in keyof TEventMap]: BehaviorSubject<TEventMap[EventKey]>
    }> = {}

    constructor() {
        (window as any).exAppInstance = this
    }

    event<TEvent extends keyof TEventMap>(event: TEvent): BehaviorSubject<TEventMap[TEvent]> {
        return this.events[event] || (this.events[event] = new BehaviorSubject)
    }

    async fire<TEvent extends keyof TEventMap>(event: TEvent, arg: TEventMap[TEvent]): Promise<void> {
        this.events[event]?.next(arg)
    }

    initialize(data: TDataMap) {
        this.data = data
    }

    get(key: keyof TDataMap): AppValue|undefined {
        return this.data[key]
    }

    set<TKey extends keyof TDataMap>(key: TKey, value: TDataMap[TKey]): (typeof value) {
        return (this.data[key] = value)
    }

    url(path?: string): string {
        if ( !path ) path = ''
        if ( !path.startsWith('/') ) path = `/${path}`

        let url = this.get('appUrl')
        if ( url.endsWith('/') ) url = url.slice(0, -1)

        return `${url}${path}`
    }

    host(): string {
        let url = this.url()
        if ( url.startsWith('https://') ) url = url.substring(8)
        else if ( url.startsWith('http://') ) url = url.substring(7)
        return (url.split('/')[0] || '').split(':')[0] || ''
    }
}
