import {
    utils, Schema, Entity, EntityProperty, Structure,
    dataTypesMap, convert2RefType, LEVEL_ENUM,
} from '../..';
import { Resolver } from '../Entity';
import { Display } from '../EntityProperty';

export const filterProperty = (key: 'inTable' | 'inFilter' | 'inForm' | 'inDetail') => (property: EntityProperty) => {
    if (property.display)
        return property.display[key];
    else
        return !['id', 'createdTime', 'updatedTime'].includes(property.name);
};
/**
 * 生成格式器的代码
 * 后来没有用到
 * @param property 实体属性
 */
export function getFormatter(property: EntityProperty) {
    const typeKey = property.typeKey;
    if (typeKey === '#/basicTypes/DateTime')
        return ` formatter="date('YYYY-MM-DD HH:mm:ss')"`;
    else if (typeKey === '#/basicTypes/Date')
        return ` formatter="date('YYYY-MM-DD')"`;
    else if (typeKey === '#/basicTypes/Date')
        return ` formatter="date('HH:mm:ss')"`;
    else if (dataTypesMap[typeKey].type === 'enum') {
        return ` :formatter="$utils['Enum']('${dataTypesMap[typeKey].name}')"`;
    }
    return '';
}

/**
 * 生成表达式的代码
 * @param property 实体属性
 * @param expression 表达式
 */
export function getExpression(property: EntityProperty, expression: string) {
    const typeKey = property.typeKey;
    if (typeKey === '#/basicTypes/DateTime')
        return `$utils['FormatDate'](${expression}, 'YYYY-MM-DD HH:mm:ss')`;
    else if (typeKey === '#/basicTypes/Date')
        return `$utils['FormatDate'](${expression}, 'YYYY-MM-DD')`;
    else if (typeKey === '#/basicTypes/Date')
        return `$utils['FormatDate'](${expression}, 'HH:mm:ss')`;
    if (dataTypesMap[typeKey].type === 'enum')
        return `$utils['Enum']('${dataTypesMap[typeKey].name}', ${expression})`;
    else
        return `${expression || "''"}`;
}

/**
 * 根据数据结构名称获取数据结构实例
 * @param structureName 数据结构名称
 */
export function getStructureByName(structureName: string) {
    return Object.values(dataTypesMap).find((item) => item.name === structureName);
}

/**
 * 获取数据结构的 schema
 * @param structureName 数据结构名称
 */
export function getSchemaOfStructure(structureName: string) {
    const structure = Object.values(dataTypesMap).find((item) => item.name === structureName) as Structure;
    return {
        $ref: structure?.schemaRef,
        typeKey: structure?.schemaRef,
    };
}

/**
 * 从 Resolver 中获取变量
 * @param resolver
 * @param paramName
 */
export function getParamFromResolver(resolver: Resolver, paramName: string) {
    const params = resolver.interface.logic.params;
    return params.find((item) => item.name === paramName);
}

/**
 * 生成泛型 Schema
 * @param {String} name 泛型名称，如 ScopeOf
 * @param {*} typeParamMap {'T': {$ref:'#/**'}}
 * @param {*} dataTypesMap
 * @returns 泛型
 */
export function genGenericTypeSchema(name: string, typeParamMap: { [name: string]: { $ref: string } }) {
    const scopeClass = dataTypesMap[`#/genericTypes/${name}`];
    let schema = {};
    if (scopeClass) {
        schema = {
            type: 'genericType',
            typeKey: `#/genericTypes/${name}`,
            typeInstantiation: {
                typeName: name,
                typeParams: scopeClass.typeParams.map((typeParam) => ({
                    typeParamName: typeParam.typeParamName,
                    typeParamValue: typeParamMap[typeParam.typeParamName],
                })),
            },
        };
    }
    return convert2RefType(schema);
}

export function genVariable(name: string, schema: Schema | string, level: LEVEL_ENUM) {
    schema = typeof schema === 'object' ? schema : { $ref: schema };

    return {
        level,
        type: 'Identifier',
        name,
        schema,
    };
}

export function getFirstDisplayedProperty(entity: Entity, display: keyof Display = 'inTable') {
    let property = entity.propertyList.find((property) => property.editable);
    if (!property)
        property = entity.propertyList[0];
    return property;
}

/**
 * 生成接口 Param
 * @param paramIdOrName 参数 id 或引用名称
 * @param expression 表达式
 * @param schemaChildren 数据结构
 */
export function genInterParam(paramIdOrName: string, expression: string, schemaRefs: Array<string> = []) {
    const arr = expression.split('.');

    let expressionNode: any;
    arr.forEach((name, index) => {
        const currentNode = {
            level: LEVEL_ENUM.expressionNode,
            type: 'Identifier',
            name,
            schemaRef: schemaRefs[index],
        };
        if (expressionNode) {
            expressionNode = {
                level: LEVEL_ENUM.expressionNode,
                type: 'MemberExpression',
                object: expressionNode,
                property: {
                    level: LEVEL_ENUM.expressionNode,
                    type: 'Identifier',
                    name,
                    schemaRef: schemaRefs[index],
                    code: schemaRefs[index] === '' ? '' : undefined,
                },
            };
        } else {
            expressionNode = currentNode;
        }
    });

    expressionNode.parentAttr = 'CallInterParamValue';

    return {
        parentAttr: 'params',
        level: LEVEL_ENUM.param,
        type: 'CallInterParam',
        callInterParam: paramIdOrName,
        callInterParamValue: expressionNode,
    };
}

/**
 * 命名组，主要承载一次 mergeBlock 中的逻辑名称
 */
export interface NameGroup {
    interface?: string,
    structure?: string,
    load?: string,
    remove?: string,
    modify?: string,
    submit?: string,
    lowerEntity?: string,
    [key: string]: string,
}

function capFirstLetter(word: string) {
    if (!word)
        return word;

    return word[0].toUpperCase() + word.slice(1);
}
/**
 * 生成数据查询唯一的命名组
 * @param viewName 页面名称
 * @param componentName 组件名称
 * @param suffix 其它后缀，比如实体名等等
 * @param defaultInView 是否在页面逻辑中用 load 简写
 */
export function genUniqueQueryNameGroup(
    existingNameSets: {
        viewLogic: Set<string>,
        interface: Set<string>,
        structure: Set<string>,
    },
    viewName: string, componentName: string = '', defaultInView: boolean = true, suffix: string = '',
) {
    const result: NameGroup = {};

    result.load = utils.unique(`load${defaultInView ? '' : capFirstLetter(componentName)}${suffix ? capFirstLetter(suffix) : ''}`, existingNameSets.viewLogic);
    result.interface = utils.unique(`load${capFirstLetter(viewName)}${componentName ? capFirstLetter(componentName) : ''}${suffix ? capFirstLetter(suffix) : ''}`, existingNameSets.interface);
    result.structure = utils.unique(utils.firstUpperCase(result.interface + 'Structure'), existingNameSets.structure);

    return result;
}
