import * as ObjectUtil from './object.ts';
import * as StringUtil from './string.ts';

export function getOrigin(): string {
    const loc = window.location;
    return loc.origin || `${loc.protocol}//${loc.hostname}${loc.port ? ':' + loc.port : ''}`;
}

export function concatUri(contextUri: string, path: string): string {
    contextUri = contextUri || '';
    if (!path || path === '/') {
        return contextUri;
    }
    if (contextUri.endsWith('/')) {
        contextUri = contextUri.substring(0, contextUri.length - 1);
    }
    if (!path.startsWith('/')) {
        path = '/' + path;
    }
    return contextUri + path;
}

export function getHeader(headers: Record<string, string>, name: string, defaultValue?: string): string {
    if (headers && name) {
        return headers[name] || headers[name.toLowerCase()] || defaultValue;
    }
    return undefined;
}

export function getParameterString(): string {
    let href = window.location.href;
    let index = href.indexOf('?');
    if (index >= 0) {
        let parameterString = href.substring(index + 1);
        parameterString = decodeURIComponent(parameterString);
        index = parameterString.indexOf('#');
        if (index >= 0) {
            parameterString = parameterString.substring(0, index);
        }
        return parameterString;
    }
    return '';
}

export function getParameters(): Record<string, string | string[]> {
    let params: Record<string, string | string[]> = {};
    let parameterString = getParameterString();
    if (parameterString) {
        let array = parameterString.split('&');
        for (let parameter of array) {
            let index = parameter.indexOf('=');
            if (index > 0) {
                let paramName = parameter.substring(0, index);
                let paramValue = parameter.substring(index + 1);
                if (params[paramName]) {
                    if (!Array.isArray(params[paramName])) {
                        params[paramName] = [params[paramName]];
                    }
                    (params[paramName] as string[]).push(paramValue);
                } else {
                    params[paramName] = paramValue;
                }
            }
        }
    }
    return params;
}

export function getParamValue(name: string): string | string[] {
    let parameterString = getParameterString();
    if (parameterString) {
        let value: string[] = [];
        let array = parameterString.split('&');
        for (let parameter of array) {
            let index = parameter.indexOf('=');
            if (index > 0) {
                let paramName = parameter.substring(0, index);
                if (paramName === name) {
                    value.push(parameter.substring(index + 1));
                }
            }
        }
        if (value.length === 1) {
            return value[0];
        } else if (value.length > 1) {
            return value;
        }
    }
    return undefined;
}

export function toParameterString(obj: object): string {
    let s = '';
    if (obj) {
        Object.keys(obj).forEach(key => {
            let value = (obj as any)[key];
            if (ObjectUtil.isNotNull(value)) {
                let toKeyValueString = function (k: string, v: any): string {
                    if (typeof v === 'function') {
                        v = v();
                    }
                    if (typeof v === 'object') {
                        if (v instanceof Date) {
                            v = (v as any).formatDateTime();
                        } else if (typeof (v as any).toString === 'function') {
                            v = (v as any).toString();
                        } else {
                            v = null;
                        }
                    }
                    if (ObjectUtil.isNotNull(v) && v !== '') {
                        return '&' + k + '=' + encodeURIComponent(v);
                    }
                    return '';
                }
                if (Array.isArray(value)) {
                    for (let v of value) {
                        s += toKeyValueString(key, v);
                    }
                } else {
                    s += toKeyValueString(key, value);
                }
            }
        });
        if (s.length) {
            s = s.substring(1);
        }
    }
    return s;
}

export function appendParams(url: string, params: object): string {
    let parameterString = toParameterString(params);
    if (parameterString.length) {
        return url + (url.includes('?') ? '&' : '?') + parameterString;
    }
    return url;
}

export function appendRandomParam(url: string): string {
    let params = {} as any;
    let key = '_' + StringUtil.random(8);
    params[key] = new Date().getTime();
    return appendParams(url, params);
}

export function getAnchor(): string {
    const anchor = window.location.hash;
    if (anchor) {
        const index = anchor.indexOf('#');
        if (index >= 0) {
            return anchor.substring(index + 1);
        }
    }
    return '';
}

export function getUrl(withOrigin: boolean, withAnchor: boolean, withParameter: boolean): string {
    let url = '';
    if (withOrigin) {
        url += getOrigin();
    }
    url += window.location.pathname;
    if (withAnchor) {
        url += window.location.hash;
    }
    if (withParameter) {
        url += getParameterString();
    }
    return url;
}

export function isIntranetHostname(hostname: string): boolean {
    if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '0:0:0:0:0:0:0:1') {
        return true;
    }
    if (hostname.startsWith('192.168.') || hostname.startsWith('10.')) {
        return true;
    } else if (hostname.startsWith('172.')) {
        let seg = hostname.substring(4, hostname.indexOf('.', 4));
        let value = parseInt(seg);
        return 16 <= value && value <= 31;
    }
    return false;
}

export function isUrl(s: string): boolean {
    const regex = '^((https|http|ftp)?://)'
        + '?(([0-9a-z_!~*\'(\).&=+$%-]+: )?[0-9a-z_!~*\'(\).&=+$%-]+@)?'
        + '(([0-9]{1,3}.){3}[0-9]{1,3}'
        + '|'
        + '([0-9a-z_!~*\'()-]+.)*'
        + '([0-9a-z][0-9a-z-]{0,61})?[0-9a-z].'
        + '[a-z]{2,6})'
        + '(:[0-9]{1,4})?'
        + '((/?)|'
        + '(/[0-9a-z_!~*\'(\).;?:@&=+$,%#-]+)+/?)$';
    return new RegExp(regex).test(s);
}

export function isMobile(): boolean {
    let userAgent = navigator.userAgent.toLowerCase();
    return userAgent.includes('android') || userAgent.includes('iphone') || userAgent.includes('ipad');
}

export function isWechat(): boolean {
    let userAgent = navigator.userAgent.toLowerCase();
    return userAgent.includes('micromessenger');
}

export function getExtension(url: string, withDot: boolean): string {
    if (url) {
        let index = url.indexOf('?');
        if (index >= 0) {
            url = url.substring(0, index);
        }
        index = url.lastIndexOf('.');
        if (index >= 0) {
            return url.substring((withDot) ? index : index + 1).toLowerCase();
        }
    }
    return '';
}

export function pushState(url: string): boolean {
    if (window.history.pushState) {
        if (url.startsWith('/')) {
            url = getOrigin() + url;
        }
        window.history.pushState({}, '', url);
        return true;
    }
    return false;
}

export function replaceState(url: string): boolean {
    if (window.history.replaceState) {
        if (url.startsWith('/')) {
            url = getOrigin() + url;
        }
        window.history.replaceState({}, '', url);
        return true;
    }
    return false;
}

export function getPathVariables(pattern: string, url: string): Record<string, string> {
    const variableNames: string[] = [];
    const regexPattern = pattern.replace(/\$\{([^}]+)}/g, (substring: string, variableName: string) => {
        variableNames.push(variableName);
        return '([^/]+)';
    });
    const variables = {} as any;
    const fullRegex = new RegExp(`^${regexPattern}$`);
    const match = url.match(fullRegex);
    if (match) {
        for (let i = 0; i < variableNames.length; i++) {
            variables[variableNames[i]] = decodeURIComponent(match[i + 1]);
        }
    }
    return variables;
}
