export class TWRestQuery {
    private _action: any;
    private _where: Array<{
        column: string;
        operator: string;
        value: any;
    }> = [];
    private _columns: Array<any> = [];
    private _limit: number = 1000;
    private _offset: number = 0;
    private _language: string = "";
    private _resolveForeignKeys: Boolean = false;
    private _tableName: string = "";

    /**
     * Regex patterns used inside this class
     *
     * @static
     * @memberof IntelligentQuery
     */
    static regex = {
        where: /^([^=]*)=([\w]{2,3}):{{([^}]*)}}/gm
    }

    constructor() {
    }

    get resolveForeignKeys() {
        return this._resolveForeignKeys;
    }

    get action() {
        return this._action;
    }

    get where() {
        return this._where;
    }

    get limit() {
        return this._limit;
    }

    get offset() {
        return this._offset;
    }

    get columns() {
        return this._columns;
    }

    /*get prototype() {
        return this._prototype;
    }*/

    static get(columns: Array<any> = []): TWRestQuery {
        let tmpQuery = new TWRestQuery();
        tmpQuery._columns = columns;
        tmpQuery._action = "select";
        return tmpQuery;
    }

    static put(): TWRestQuery {
        let tmpQuery = new TWRestQuery();
        tmpQuery._action = "save";
        return tmpQuery;
    }

    static resolveRegex(pattern: RegExp, str: string) {
        let m;
        let tmpResult = [];
        while ((m = pattern.exec(str)) !== null) {
            if (m.index === pattern.lastIndex) {
                pattern.lastIndex++;
            }
            tmpResult.push(m);
        }

        return tmpResult;
    }

    from(tableName: any): TWRestQuery {
        this._tableName = tableName;
        return this;
    }

    toString() {
        return this.encode();
    }

    encode() {
        let key = this._tableName;
        let tmpUrlParts = [this._limit + "-" + this._offset];

        // Add columns
        if (this._columns && this._columns.length) {
            tmpUrlParts.push(this._columns.join('&'));
        }
        else {
            tmpUrlParts.push('*');
        }

        // Add where part
        if (this._where && this._where.length) {
            let tmpWhereArr = [];
            for (let x = 0; x < this._where.length; x++) {
                let tmpWhere = this._where[x];
                tmpWhereArr.push(`${tmpWhere.column}=${tmpWhere.operator}:{{${tmpWhere.value}}}`);
            }
            tmpUrlParts.push(tmpWhereArr.join('&'));
        }

        let tmpUrl = tmpUrlParts.join('/');
        return [key, btoa(tmpUrl)].join('/');
    }

    static decode(url: string) {
        let tmpSplit = url.split('/');
        let tmpTable = tmpSplit[0];
        if (tmpSplit.length > 1) {
            let tmpParams = tmpSplit[1];
            let tmpDecodedParams = atob(tmpParams);
            let tmpSplitParams = tmpDecodedParams.split('/');
            let tmpLimitOffset = String(tmpSplitParams[0]).split('-');
            let tmpLimit = parseInt(tmpLimitOffset[0]);
            let tmpOffset = parseInt(tmpLimitOffset[1]);

            let tmpColumns = tmpSplitParams[1];
            let tmpWhere = (tmpSplitParams[2]) ? TWRestQuery.decodeWhere(tmpSplitParams[2]) : [];

            let tmpQuery = new TWRestQuery();
            tmpQuery.setTableName(tmpTable);

            for (let x = 0; x < tmpWhere.length; x++) {
                let tmpWherePart = tmpWhere[x];
                tmpQuery.addWhere(tmpWherePart.column, tmpWherePart.operator, tmpWherePart.value);
            }

            tmpQuery.setLimit(tmpLimit, tmpOffset);

            console.log(`
          Limit offset: ${tmpLimitOffset}
          Columns: ${tmpColumns}
          Where: ${tmpWhere}
          ToString: ${tmpQuery.toString()}
          =============================================        
          `);
        }




        return url;
    }

    addWhere(column: string, operator: string, value: any) {
        this.where.push({
            column: column,
            operator: operator,
            value: value
        });
        return this;
    }

    static decodeWhere(whereString: string): Array<{ column: string; operator: string; value: any; }> {
        if (!whereString) return [];
        let tmpReturnResult = [];
        let tmpSplit = whereString.split('&');
        if (tmpSplit.length) {
            for (let x = 0; x < tmpSplit.length; x++) {
                let tmpRegexResult = TWRestQuery.resolveRegex(TWRestQuery.regex.where, tmpSplit[x]);
                if (tmpRegexResult.length) {
                    let tmpColumn = tmpRegexResult[0][1] || null;
                    let tmpOperator = tmpRegexResult[0][2] || null;
                    let tmpValue = tmpRegexResult[0][3] || null;

                    if (tmpColumn && tmpOperator && tmpValue) {
                        tmpReturnResult.push({
                            column: tmpColumn,
                            operator: tmpOperator,
                            value: tmpValue
                        })
                    }
                }
            }
        }
        return tmpReturnResult;
    }

    setWhere(filter: any): TWRestQuery {
        this._where = filter;
        return this;
    }

    setTableName(tableName: string) {
        this._tableName = tableName;
    }

    filterByLanguage(language: string): TWRestQuery {
        this._language = language;
        return this;
    }

    setResolveForeignKeys(val: Boolean = true): TWRestQuery {
        this._resolveForeignKeys = val;
        return this;
    }
    setLimit(limit: number, offset: number) {
        this._limit = limit;
    }

    /*post(): Promise<TWGenericList> {
      return new Promise((resolve, reject) => {
      });
    }
  
    get(): Promise<TWGenericList> {
      return new Promise((resolve, reject) => {
      });
    }*/

}
