let d: any = null
let w: any = null

interface DeviceQueryConfig {
    min?: number;
    max?: number;
    enable?: boolean;
}
interface QueryConfig {
    mobile?: DeviceQueryConfig;
    tablet?: DeviceQueryConfig;
    laptop?: DeviceQueryConfig;
    desktop?: DeviceQueryConfig;
}
class StringResponsiveQueryDevice {
    public min?: number = undefined;
    public max?: number = undefined;
    public enable: boolean = true;
    constructor(min?: number, max?: number) {
        this.min = min ?? undefined;
        this.max = max ?? undefined;
    }
    setEnable(enable: boolean = true) {
        this.enable = enable;
    }
    setRange(min?: number, max?: number) {
        this.min = min ?? undefined;
        this.max = max ?? undefined;
    }
}
class StringResponsiveDeviceEvent {
    private eventsIn: Array<Function> = new Array<Function>();
    private eventsOut: Array<Function> = new Array<Function>();
    private stringResponsive: StringResponsive
    private state: StringResponsiveState
    constructor(stringResponsive: StringResponsive, state: StringResponsiveState){
        this.stringResponsive = stringResponsive
        this.state = state
    }
    addIn(event: Function) {
        if (!this.eventsIn.includes(event)) {
            this.eventsIn.push(event);
        }
        if (this.stringResponsive.state == this.state) {
            event()
        }
    }
    removeIn(event: Function) {
        const index = this.eventsIn.indexOf(event);
        if (index !== -1) {
            this.eventsIn.splice(index, 1);
        }
    }
    callIn() {
        this.eventsIn.forEach(event => {
            event()
        })
    }
    addOut(event: Function) {
        if (!this.eventsOut.includes(event)) {
            this.eventsOut.push(event);
        }
        if (this.stringResponsive.state != this.state) {
            event()
        }
    }

    removeOut(event: Function) {
        const index = this.eventsOut.indexOf(event);
        if (index !== -1) {
            this.eventsOut.splice(index, 1);
        }
    }
    callOut() {
        this.eventsOut.forEach(event => {
            event()
        })
    }
}
enum StringResponsiveState { Mobile, Tablet, Laptop, Desktop }
class StringResponsive {
    private static instance: StringResponsive;
    private mobileQuery: StringResponsiveQueryDevice
    private tabletQuery: StringResponsiveQueryDevice
    private laptopQuery: StringResponsiveQueryDevice
    private desktopQuery: StringResponsiveQueryDevice
    private mobileMatchMedia: MediaQueryList
    private tabletMatchMedia: MediaQueryList
    private laptopMatchMedia: MediaQueryList
    private desktopMatchMedia: MediaQueryList
    public mobile: StringResponsiveDeviceEvent
    public tablet: StringResponsiveDeviceEvent
    public laptop: StringResponsiveDeviceEvent
    public desktop: StringResponsiveDeviceEvent
    private onMobileEvent
    private onTabletEvent
    private onLaptopEvent
    private onDesktopEvent
    private _state: StringResponsiveState = StringResponsiveState.Mobile
    public get state() {
        return this._state;
    }
    private constructor() {
        d = document
        w = window
        this.mobileQuery = new StringResponsiveQueryDevice(undefined, 359);
        this.tabletQuery = new StringResponsiveQueryDevice(360, 1079);
        this.laptopQuery = new StringResponsiveQueryDevice(1080, 1365);
        this.desktopQuery = new StringResponsiveQueryDevice(1366, undefined);
        this.mobileMatchMedia = window.matchMedia("screen and (max-width: 359px)")
        this.tabletMatchMedia = window.matchMedia("screen and (min-width: 360px) and (min-width: 1079px)")
        this.laptopMatchMedia = window.matchMedia("screen and (min-width: 1080px) and (min-width: 1365px)")
        this.desktopMatchMedia = window.matchMedia("screen and (min-width: 1366px)")
        this.onMobileEvent = this.onMobileQuery.bind(this)
        this.onTabletEvent = this.onTabletQuery.bind(this)
        this.onLaptopEvent = this.onLaptopQuery.bind(this)
        this.onDesktopEvent = this.onDesktopQuery.bind(this)
        this.setupQueries()
        this.matchMedia()
        this.mobile = new StringResponsiveDeviceEvent(this, StringResponsiveState.Mobile)
        this.tablet = new StringResponsiveDeviceEvent(this, StringResponsiveState.Tablet)
        this.laptop = new StringResponsiveDeviceEvent(this, StringResponsiveState.Laptop)
        this.desktop = new StringResponsiveDeviceEvent(this, StringResponsiveState.Desktop)
    }
    public static getInstance(): StringResponsive {
        if (!StringResponsive.instance) {
            StringResponsive.instance = new StringResponsive();
        }

        return StringResponsive.instance;
    }
    public setQuery(config: QueryConfig) {
        if (config.mobile) {
            this.mobileQuery.setEnable(config.mobile.enable ?? this.mobileQuery.enable);
            this.mobileQuery.setRange(config.mobile.min == undefined ? this.mobileQuery.min : config.mobile.min, config.mobile.max ?? this.mobileQuery.max);
        }
        if (config.tablet) {
            this.tabletQuery.setEnable(config.tablet.enable ?? this.tabletQuery.enable);
            this.tabletQuery.setRange(config.tablet.min == undefined ? this.tabletQuery.min : config.tablet.min, config.tablet.max ?? this.tabletQuery.max);
        }
        if (config.laptop) {
            this.laptopQuery.setEnable(config.laptop.enable ?? this.laptopQuery.enable);
            this.laptopQuery.setRange(config.laptop.min == undefined ? this.laptopQuery.min : config.laptop.min, config.laptop.max ?? this.laptopQuery.max);
        }
        if (config.desktop) {
            this.desktopQuery.setEnable(config.desktop.enable ?? this.desktopQuery.enable);
            this.desktopQuery.setRange(config.desktop.min == undefined ? this.desktopQuery.min : config.desktop.min, config.desktop.max ?? this.desktopQuery.max);
        }
        this.setupQueries()
        this.matchMedia()
        console.log(this.state)
    }
    private setupQueries() {
        this.mobileMatchMedia.onchange = null
        if (this.mobileQuery.enable) {
            if (this.mobileQuery.min != undefined && this.mobileQuery.max != undefined) {
                this.mobileMatchMedia = window.matchMedia(`screen and (min-width: ${this.mobileQuery.min}px) and (max-width: ${this.mobileQuery.max}px)`)
            } else {
                if (this.mobileQuery.min != undefined) {
                    this.mobileMatchMedia = window.matchMedia(`screen and (min-width: ${this.mobileQuery.min}px)`)
                }
                if (this.mobileQuery.max != undefined) {
                    this.mobileMatchMedia = window.matchMedia(`screen and (max-width: ${this.mobileQuery.max}px)`)

                }
            }
            this.mobileMatchMedia.onchange = this.onMobileEvent
        }
        this.tabletMatchMedia.onchange = null
        if (this.tabletQuery.enable) {
            if (this.tabletQuery.min != undefined && this.tabletQuery.max != undefined) {
                this.tabletMatchMedia = window.matchMedia(`screen and (min-width: ${this.tabletQuery.min}px) and (max-width: ${this.tabletQuery.max}px)`)
            } else {
                if (this.tabletQuery.min != undefined) {
                    this.tabletMatchMedia = window.matchMedia(`screen and (min-width: ${this.tabletQuery.min}px)`)
                }
                if (this.tabletQuery.max != undefined) {
                    this.tabletMatchMedia = window.matchMedia(`screen and (max-width: ${this.tabletQuery.max}px)`)

                }
            }
            this.tabletMatchMedia.onchange = this.onTabletEvent
        }
        this.laptopMatchMedia.onchange = null
        if (this.laptopQuery.enable) {
            if (this.laptopQuery.min != undefined && this.laptopQuery.max != undefined) {
                this.laptopMatchMedia = window.matchMedia(`screen and (min-width: ${this.laptopQuery.min}px) and (max-width: ${this.laptopQuery.max}px)`)
            } else {
                if (this.laptopQuery.min != undefined) {
                    this.laptopMatchMedia = window.matchMedia(`screen and (min-width: ${this.laptopQuery.min}px)`)
                }
                if (this.laptopQuery.max != undefined) {
                    this.laptopMatchMedia = window.matchMedia(`screen and (max-width: ${this.laptopQuery.max}px)`)

                }
            }
            this.laptopMatchMedia.onchange = this.onLaptopEvent
        }
        this.desktopMatchMedia.onchange = null
        if (this.desktopQuery.enable) {
            if (this.desktopQuery.min != undefined && this.desktopQuery.max != undefined) {
                this.desktopMatchMedia = window.matchMedia(`screen and (min-width: ${this.desktopQuery.min}px) and (max-width: ${this.desktopQuery.max}px)`)
            } else {
                if (this.desktopQuery.min != undefined) {
                    this.desktopMatchMedia = window.matchMedia(`screen and (min-width: ${this.desktopQuery.min}px)`)
                }
                if (this.desktopQuery.max != undefined) {
                    this.desktopMatchMedia = window.matchMedia(`screen and (max-width: ${this.desktopQuery.max}px)`)

                }
            }
            this.desktopMatchMedia.onchange = this.onDesktopEvent
        }
    }
    private matchMedia() {
        if (this.mobileMatchMedia.matches && this.mobileQuery.enable) {
            this._state = StringResponsiveState.Mobile
        }
        if (this.tabletMatchMedia.matches && this.tabletQuery.enable) {
            this._state = StringResponsiveState.Tablet
        }
        if (this.laptopMatchMedia.matches && this.laptopQuery.enable) {
            this._state = StringResponsiveState.Laptop
        }
        if (this.desktopMatchMedia.matches && this.desktopQuery.enable) {
            this._state = StringResponsiveState.Desktop
        }
    }
    private onMobileQuery(event: MediaQueryListEvent) {
        if (event.matches) {
            this._state = StringResponsiveState.Mobile
            this.mobile.callIn()
        } else {
            this.mobile.callOut()
        }
    }
    private onTabletQuery(event: MediaQueryListEvent) {
        if (event.matches) {
            this._state = StringResponsiveState.Tablet
            this.tablet.callIn()
        } else {
            this.tablet.callOut()
        }
    }
    private onLaptopQuery(event: MediaQueryListEvent) {

        if (event.matches) {
            this._state = StringResponsiveState.Laptop
            this.laptop.callIn()
        } else {
            this.laptop.callOut()
        }
    }
    private onDesktopQuery(event: MediaQueryListEvent) {
        if (event.matches) {
            this._state = StringResponsiveState.Desktop
            this.desktop.callIn()
        } else {
            this.desktop.callOut()
        }
    }
}

export default StringResponsive