import { Paths } from "amisa-paths";
import { MainStateManager } from "../MainStateManager";


type IPathManagerConfig = (c: Paths) => void;

type HttpType = 'http' | 'https';
export const testUrlAddress = '80.210.62.172';
export const testPortAddress = '3303';

export class AmisaManager {
    static #amisaManagerSetting: any;
    private static readonly token: symbol = Symbol.for('a');

    public static get setting(): MainStateManager {
        return this.#amisaManagerSetting[this.token];
    }

    static #temp: MainStateManager | undefined;
    static #init = () => {
        Object.defineProperty(Object.prototype, this.token, {
            enumerable: false,
            configurable: false,
            get: () => { return this.#temp },
        });
    }
    static #getPort = (port: number) => {
        if (port) {
            return `:${port}`;
        }
        return '';
    }
    static #projectKey = (projectKey: string) => {
        if (!projectKey) {
            throw Error('project key not initialize');
        }
        return projectKey;
    }
    static #getBaseUrl = (url: string) => {
        if (url || url.length < 3) {
            return `${url.replace('/', '').replace(':', '')}`;
        }
        throw Error('url not initialize');
    }
    static #getUrl = (baseUrlHttpType: HttpType, baseUrl: string, baseUrlPort: number): string => {
        const baseUrlFinal = `${baseUrlHttpType}://${this.#getBaseUrl(baseUrl)}${this.#getPort(baseUrlPort)}`;
        if (!baseUrlFinal || baseUrlFinal.length < 6) {
            throw Error('base url not initialize');
        }
        return baseUrlFinal;
    }
    static #pathMaager = (c: IPathManagerConfig): Paths => {
        const pathManager = new Paths();
        c(pathManager);
        return pathManager;
    }
    static #mainInit = () => {
        this.#amisaManagerSetting = {};
        this.#temp = new MainStateManager();

        if ((Object.prototype as any)[AmisaManager.token] === undefined) {
            this.#init();
        }
        this.#ConfigureProtoType();
    }
    public static ConfigureServices(baseUrlHttpType: HttpType, baseUrl: string, baseUrlPort: number, projectKey: string, c: IPathManagerConfig): void {
        this.#mainInit();

        const getUrl = this.#getUrl(baseUrlHttpType, baseUrl, baseUrlPort);
        const getProjectKey = this.#projectKey(projectKey);
        const getPathManager = this.#pathMaager(c);

        this.#temp!.initializeServices(getUrl, getProjectKey, getPathManager);
    }

    static #isStringOfLength = <Min extends number, Max extends number>(
        str: string,
        min: Min,
        max: Max
    ): str is StringOfLength<Min, Max> => str.length >= min && str.length <= max;
    static #myString = <Min extends number, Max extends number>(
        input: unknown,
        min: Min,
        max: Max
    ): StringOfLength<Min, Max> => {
        if (typeof input !== 'string') {
            throw new Error('invalid input');
        }

        if (!this.#isStringOfLength(input, min, max)) {
            throw new Error('invalid input');
        }

        return input;
    }

    static #ConfigureProtoType() {
        if (String.prototype.assignLength === undefined) {
            Object.defineProperty(String.prototype, 'assignLength', {
                value: (min: number, max: number) => {
                    var self: any = this;
                    self['min'] = min;
                    self['max'] = max;
                },
                enumerable: false,
            });
        }
        if (Object.prototype.getProp === undefined) {
            Object.defineProperty(Object.prototype, 'getProp', {
                value: function (prop: string) {
                    var key, self = this;

                    if (typeof prop !== 'string') {
                        console.error(prop, 'is not a apt value', self);
                    }

                    for (key in self) {
                        if (key.toLowerCase() == prop.toLowerCase()) {
                            return self[key];
                        }
                    }
                },
                //this keeps jquery happy
                enumerable: false,
            });
        }

        if (Object.prototype.setProp === undefined) {
            Object.defineProperty(Object.prototype, 'setProp', {
                value: function (prop: string, value: any) {
                    var key,
                        self = this;

                    if (typeof prop !== 'string') {
                        console.error(prop, 'is not a apt value to set', self);
                    }

                    for (key in self) {
                        if (key.toLowerCase() == prop.toLowerCase()) {
                            self[key] = value;
                        }
                    }
                },
                //this keeps jquery happy
                enumerable: false,
            });
        }

        if (Object.prototype.getPropValue === undefined) {
            Object.defineProperty(Object.prototype, 'getPropValue', {
                value: function (prop: string, defaultValue: any) {
                    var key,
                        self = this;

                    if (typeof prop !== 'string' || prop === '') {
                        console.error(prop, 'is not a apt value', self);
                        return undefined;
                    }

                    if (!self) {
                        console.error(prop, 'is not a apt object', self);
                        return undefined;
                    }

                    for (key in self) {
                        if (key.toLowerCase() == prop.toLowerCase() && self[key]) {
                            return self[key];
                        }
                    }

                    return defaultValue;
                },
                //this keeps jquery happy
                enumerable: false,
            });
        }

        if (Object.prototype.getPropsValue === undefined) {
            Object.defineProperty(Object.prototype, 'getPropsValue', {
                value: function (prop1: string, prop2: string, defaultValue: any) {
                    var key,
                        self = this;

                    if (!self) {
                        console.error(prop1, prop2, 'is not a apt object', self);
                        return undefined;
                    }

                    if (typeof prop1 !== 'string' || prop1 === '') {
                        console.error(prop1, 'is not a apt value', self);
                        return undefined;
                    } else if (typeof prop2 !== 'string' || prop2 === '') {
                        console.error(prop2, 'is not a apt value', self);
                        return undefined;
                    }

                    for (key in self) {
                        if (key.toLowerCase() == prop1.toLowerCase() && self[key]) {
                            return self[key];
                        }
                    }
                    for (key in self) {
                        if (key.toLowerCase() == prop2.toLowerCase() && self[key]) {
                            return self[key];
                        }
                    }

                    return defaultValue;
                },
                //this keeps jquery happy
                enumerable: false,
            });
        }
    };
}

export default AmisaManager;