/*
 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { ClassFilter, NotClassFilter, SuiteAndItNameFilter, TestTypesFilter, NestFilter } from './Filter';
import { TAG, TESTTYPE, LEVEL, SIZE, KEYSET } from '../../Constant';
const STRESS_RULE = /^[1-9]\d*$/;

class ConfigService {
    constructor(attr) {
        this.id = attr.id;
        this.supportAsync = true; // 默认异步处理测试用例
        this.random = false;
        this.filterValid = [];
        this.filter = 0;
        this.flag = false;
        this.suite = null;
        this.itName = null;
        this.testType = null;
        this.level = null;
        this.size = null;
        this.class = null;
        this.notClass = null;
        this.timeout = null;
        // 遇错即停模式配置
        this.breakOnError = false;
        // 压力测试配置
        this.stress = null;
        this.skipMessage = false;
        this.runSkipped = '';
        this.filterXdescribe = [];
    }

    init(coreContext) {
        this.coreContext = coreContext;
    }

    isNormalInteger(str) {
        const n = Math.floor(Number(str));
        return n !== Infinity && String(n) === String(str) && n >= 0;
    }


    getStress() {
        if (this.stress === undefined || this.stress === '' || this.stress === null) {
            return 1;
        }
        return !this.stress.match(STRESS_RULE) ? 1 : Number.parseInt(this.stress);
    }

    basicParamValidCheck(params) {
        let size = params.size;
        if (size !== undefined && size !== '' && size !== null) {
            let sizeArray = ['small', 'medium', 'large'];
            if (sizeArray.indexOf(size) === -1) {
                this.filterValid.push('size:' + size);
            }
        }
        let level = params.level;
        if (level !== undefined && level !== '' && level !== null) {
            let levelArray = ['0', '1', '2', '3', '4'];
            if (levelArray.indexOf(level) === -1) {
                this.filterValid.push('level:' + level);
            }
        }
        let testType = params.testType;
        if (testType !== undefined && testType !== '' && testType !== null) {
            let testTypeArray = ['function', 'performance', 'power', 'reliability', 'security',
                'global', 'compatibility', 'user', 'standard', 'safety', 'resilience'];
            if (testTypeArray.indexOf(testType) === -1) {
                this.filterValid.push('testType:' + testType);
            }
        }
    }

    filterParamValidCheck(params) {
        let timeout = params.timeout;
        if (timeout !== undefined && timeout !== '' && timeout !== null) {
            if (!this.isNormalInteger(timeout)) {
                this.filterValid.push('timeout:' + timeout);
            }
        }

        let paramKeys = ['dryRun', 'random', 'breakOnError', 'coverage', 'skipMessage'];
        for (const key of paramKeys) {
            if (params[key] !== undefined && params[key] !== 'true' && params[key] !== 'false') {
                this.filterValid.push(`${key}:${params[key]}`);
            }
        }

        // 压力测试参数验证,正整数
        if (params.stress !== undefined && params.stress !== '' && params.stress !== null) {
            if (!params.stress.match(STRESS_RULE)) {
                this.filterValid.push('stress:' + params.stress);
            }
        }

        let nameRule = /^[A-Za-z]{1}[\w#,.]*$/;
        let paramClassKeys = ['class', 'notClass'];
        for (const key of paramClassKeys) {
            if (params[key] !== undefined && params[key] !== '' && params[key] !== null) {
                let classArray = params[key].split(',');
                classArray.forEach(item => !item.match(nameRule) ? this.filterValid.push(`${key}:${params[key]}`) : null);
            }
        }
    }

    setConfig(params) {
        this.basicParamValidCheck(params);
        this.filterParamValidCheck(params);
        try {
            this.class = params.class;
            this.notClass = params.notClass;
            this.flag = params.flag || { flag: false };
            this.suite = params.suite;
            this.itName = params.itName;
            this.filter = params.filter;
            this.testType = params.testType;
            this.level = params.level;
            this.size = params.size;
            this.timeout = params.timeout;
            this.dryRun = params.dryRun;
            this.breakOnError = params.breakOnError;
            this.random = params.random === 'true' ? true : false;
            this.stress = params.stress;
            this.coverage = params.coverage;
            this.skipMessage = params.skipMessage;
            this.runSkipped = params.runSkipped;
            this.filterParam = {
                testType: TESTTYPE,
                level: LEVEL,
                size: SIZE
            };
            this.parseParams();
        } catch (err) {
            console.info(`${TAG}setConfig error: ${err.message}`);
        }
    }

    parseParams() {
        if (this.filter != null) {
            return;
        }
        let testTypeFilter = 0;
        let sizeFilter = 0;
        let levelFilter = 0;
        if (this.testType != null) {
            testTypeFilter = this.testType.split(',')
                .map(item => this.filterParam.testType[item] || 0)
                .reduce((pre, cur) => pre | cur, 0);
        }
        if (this.level != null) {
            levelFilter = this.level.split(',')
                .map(item => this.filterParam.level[item] || 0)
                .reduce((pre, cur) => pre | cur, 0);
        }
        if (this.size != null) {
            sizeFilter = this.size.split(',')
                .map(item => this.filterParam.size[item] || 0)
                .reduce((pre, cur) => pre | cur, 0);
        }
        this.filter = testTypeFilter | sizeFilter | levelFilter;
        console.info(`${TAG}filter params:${this.filter}`);
    }

    isCurrentSuite(description) {
        if (this.suite !== undefined && this.suite !== '' && this.suite !== null) {
            let suiteArray = this.suite.split(',');
            return suiteArray.indexOf(description) !== -1;
        }
        return false;
    }

    filterSuite(currentSuiteName) {
        let filterArray = [];
        if (this.suite !== undefined && this.suite !== '' && this.suite !== null) {
            filterArray.push(new SuiteAndItNameFilter(currentSuiteName, '', this.suite));
        }
        if (this.class !== undefined && this.class !== '' && this.class !== null) {
            filterArray.push(new ClassFilter(currentSuiteName, '', this.class));
        }
        if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) {
            filterArray.push(new NotClassFilter(currentSuiteName, '', this.notClass));
        }

        let result = filterArray.map(item => item.filterSuite()).reduce((pre, cur) => pre || cur, false);
        return result;
    }

    filterDesc(currentSuiteName, desc, fi, coreContext) {
        let filterArray = [];
        if (this.itName !== undefined && this.itName !== '' && this.itName !== null) {
            filterArray.push(new SuiteAndItNameFilter(currentSuiteName, desc, this.itName));
        }
        if (this.class !== undefined && this.class !== '' && this.class !== null) {
            filterArray.push(new ClassFilter(currentSuiteName, desc, this.class));
        }
        if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) {
            filterArray.push(new NotClassFilter(currentSuiteName, desc, this.notClass));
        }
        if (typeof (this.filter) !== 'undefined' && this.filter !== 0 && fi !== 0) {
            filterArray.push(new TestTypesFilter('', '', fi, this.filter));
        }
        let result = filterArray.map(item => item.filterIt()).reduce((pre, cur) => pre || cur, false);
        return result;
    }

    filterWithNest(desc, filter) {
        let filterArray = [];
        const nestFilter = new NestFilter();
        const targetSuiteArray = this.coreContext.getDefaultService('suite').targetSuiteArray;
        const targetSpecArray = this.coreContext.getDefaultService('suite').targetSpecArray;
        const suiteStack = this.coreContext.getDefaultService('suite').suitesStack;
        let isFilter = nestFilter.filterNestName(targetSuiteArray, targetSpecArray, suiteStack, desc);
        const isFullRun = this.coreContext.getDefaultService('suite').fullRun;
        if (typeof (this.filter) !== 'undefined' && this.filter !== 0 && filter !== 0) {
            filterArray.push(new TestTypesFilter('', '', filter, this.filter));
            return filterArray.map(item => item.filterIt()).reduce((pre, cur) => pre || cur, false);
        }
        if (isFilter && !isFullRun) {
            return true;
        }
        return nestFilter.filterNotClass(this.notClass, suiteStack, desc);

    }

    isRandom() {
        return this.random || false;
    }

    isBreakOnError() {
        return this.breakOnError !== 'true' ? false : true;
    }

    setSupportAsync(value) {
        this.supportAsync = value;
    }

    isSupportAsync() {
        return this.supportAsync;
    }

    translateParams(parameters) {
        const keySet = new Set(KEYSET);
        let targetParams = {};
        for (const key in parameters) {
            if (keySet.has(key)) {
                var newKey = key.replace('-s ', '');
                targetParams[newKey] = parameters[key];
            }
        }
        return targetParams;
    }
    translateParamsToString(parameters) {
        const keySet = new Set(KEYSET);
        let targetParams = '';
        for (const key in parameters) {
            if (keySet.has(key)) {
                targetParams += ' ' + key + ' ' + parameters[key];
            }
        }
        return targetParams.trim();
    }

    execute() {
    }

    checkIfSuiteInSkipRun(desc) {
        return this.runSkipped.split(',').some(item => {
            return item === desc || item.startsWith(desc + '.') || item.startsWith(desc + '#') || desc.startsWith(item + '.') || this.runSkipped === 'skipped';
        });
    }

    checkIfSpecInSkipRun(desc) {
        return this.runSkipped.split(',').some(item => {
            if (item.includes('#')) {
                return item === desc;
            } else {
                return desc.startsWith(item + '.') || desc.startsWith(item + '#') || this.runSkipped === 'skipped';
            }
        }
        );
    }
}

export {
    ConfigService
};
