import { useCallback, useEffect, useState } from "react";
import { useFieldSchema } from "@tachybase/schema";
import { dayjs, flatten, getValuesByPath } from "@tachybase/utils/client";
import lodash from "lodash";
import { findFilterTargets } from "../block-provider/hooks/index.mjs";
import { useCollectionManager_deprecated, useCollection_deprecated } from "../collection-manager/index.mjs";
import { removeNullCondition } from "../schema-component/index.mjs";
import { findFilterOperators } from "../schema-component/antd/form-item/SchemaSettingOptions.mjs";
import { useFilterBlock } from "./FilterProvider.mjs";
var utils_FilterBlockType = /*#__PURE__*/ function(FilterBlockType) {
    FilterBlockType[FilterBlockType["FORM"] = 0] = "FORM";
    FilterBlockType[FilterBlockType["TABLE"] = 1] = "TABLE";
    FilterBlockType[FilterBlockType["TREE"] = 2] = "TREE";
    FilterBlockType[FilterBlockType["COLLAPSE"] = 3] = "COLLAPSE";
    return FilterBlockType;
}({});
const mergeFilter = function(filters) {
    let op = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : '$and';
    const items = filters.filter((f)=>{
        if (f && 'object' == typeof f && !Array.isArray(f)) return Object.values(f).filter((v)=>void 0 !== v).length;
    });
    if (0 === items.length) return {};
    if (1 === items.length) return items[0];
    return {
        [op]: items
    };
};
const getSupportFieldsByAssociation = (inheritCollectionsChain, block)=>{
    var _block_associatedFields;
    return null == (_block_associatedFields = block.associatedFields) ? void 0 : _block_associatedFields.filter((field)=>null == inheritCollectionsChain ? void 0 : inheritCollectionsChain.some((collectionName)=>collectionName === field.target));
};
const getSupportFieldsByForeignKey = (filterBlockCollection, block)=>{
    var _block_foreignKeyFields;
    return null == (_block_foreignKeyFields = block.foreignKeyFields) ? void 0 : _block_foreignKeyFields.filter((foreignKeyField)=>filterBlockCollection.fields.some((field)=>'belongsTo' !== field.type && field.foreignKey === foreignKeyField.name));
};
const useSupportedBlocks = (filterBlockType)=>{
    const { getDataBlocks } = useFilterBlock();
    const fieldSchema = useFieldSchema();
    const collection = useCollection_deprecated();
    const { getAllCollectionsInheritChain } = useCollectionManager_deprecated();
    if (0 === filterBlockType || 3 === filterBlockType) return getDataBlocks().filter((block)=>isSameCollection(block.collection, collection));
    if (1 === filterBlockType || 2 === filterBlockType) return getDataBlocks().filter((block)=>{
        var _getSupportFieldsByAssociation, _getSupportFieldsByForeignKey;
        return fieldSchema['x-uid'] !== block.uid && (isSameCollection(block.collection, collection) || (null == (_getSupportFieldsByAssociation = getSupportFieldsByAssociation(getAllCollectionsInheritChain(collection.name, collection.dataSource), block)) ? void 0 : _getSupportFieldsByAssociation.length) || (null == (_getSupportFieldsByForeignKey = getSupportFieldsByForeignKey(collection, block)) ? void 0 : _getSupportFieldsByForeignKey.length));
    });
};
const transformToFilter = (values, fieldSchema, getCollectionJoinField, collectionName)=>{
    const { operators } = findFilterOperators(fieldSchema);
    values = flatten(values, {
        breakOn (param) {
            let { value, path } = param;
            if ([
                '$match',
                '$notMatch',
                '$anyOf',
                '$noneOf',
                '$childIn',
                '$childNotIn',
                '$dateBetween',
                '$in',
                '$notIn'
            ].includes(operators[path])) return true;
            const collectionField = getCollectionJoinField("".concat(collectionName, ".").concat(path));
            if (null == collectionField ? void 0 : collectionField.target) {
                if (Array.isArray(value)) return true;
                const targetKey = collectionField.targetKey || 'id';
                if (value && null != value[targetKey]) return true;
            }
            return false;
        }
    });
    const result = {
        $and: Object.keys(values).map((key)=>{
            const defKey = key;
            let value = lodash.get(values, key);
            const collectionField = getCollectionJoinField("".concat(collectionName, ".").concat(key));
            if (null == collectionField ? void 0 : collectionField.target) {
                value = getValuesByPath(value, collectionField.targetKey || 'id');
                key = "".concat(key, ".").concat(collectionField.targetKey || 'id');
            }
            if (!value) return null;
            if ('$isTruly' === operators[key] || '$isFalsy' === operators[key]) {
                if ('true' === value) return {
                    [key]: {
                        $isTruly: true
                    }
                };
                else if ('false' === value) return {
                    [key]: {
                        $isFalsy: true
                    }
                };
            } else if ('$dateBetween' === operators[key]) {
                if (Array.isArray(value)) {
                    for(const index in value)if (value[index]) {
                        if ('string' != typeof value[index] && !(value[index] instanceof Date)) value[index] = dayjs(value[index]).toISOString();
                    }
                }
            }
            return {
                [key]: {
                    [operators[key] || operators[defKey] || '$eq']: value
                }
            };
        }).filter(Boolean)
    };
    return result;
};
const useAssociatedFields = ()=>{
    const { fields } = useCollection_deprecated();
    return fields.filter((field)=>isAssocField(field)) || [];
};
const isAssocField = (field)=>[
        'o2o',
        'oho',
        'obo',
        'm2o',
        'createdBy',
        'updatedBy',
        'o2m',
        'm2m',
        'linkTo',
        'chinaRegion'
    ].includes(null == field ? void 0 : field.interface);
const isSameCollection = (c1, c2)=>c1.name === c2.name && c1.dataSource === c2.dataSource;
const useFilterAPI = ()=>{
    const fieldSchema = useFieldSchema();
    const { getDataBlocks } = useFilterBlock();
    const { targets, uid } = findFilterTargets(fieldSchema);
    const dataBlocks = getDataBlocks();
    const [isConnected, setIsConnected] = useState(()=>targets && targets.some((target)=>dataBlocks.some((dataBlock)=>dataBlock.uid === target.uid)));
    const targetsKeys = Object.keys(targets || {});
    useEffect(()=>{
        setIsConnected(targets && targets.some((target)=>dataBlocks.some((dataBlock)=>dataBlock.uid === target.uid)));
    }, [
        targetsKeys.length,
        dataBlocks
    ]);
    const doFilter = useCallback(function(value) {
        let field = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 'id', operator = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : '$eq';
        dataBlocks.forEach((block)=>{
            var _block_service_params, _block_service_params_, _block_service_params1;
            const target = targets.find((target)=>target.uid === block.uid);
            if (!target) return;
            if (lodash.isFunction(field)) field = field(target);
            if (lodash.isFunction(operator)) operator = operator(target);
            const param = (null == (_block_service_params = block.service.params) ? void 0 : _block_service_params[0]) || {};
            const storedFilter = (null == (_block_service_params1 = block.service.params) ? void 0 : null == (_block_service_params_ = _block_service_params1[1]) ? void 0 : _block_service_params_.filters) || {};
            if (void 0 !== value) storedFilter[uid] = {
                $and: [
                    {
                        [field]: {
                            [operator]: value
                        }
                    }
                ]
            };
            else delete storedFilter[uid];
            const mergedFilter = mergeFilter([
                ...Object.values(storedFilter).map((filter)=>removeNullCondition(filter)),
                block.defaultFilter
            ]);
            block.doFilter({
                ...param,
                page: 1,
                filter: mergedFilter
            }, {
                filters: storedFilter
            });
        });
    }, [
        dataBlocks
    ]);
    return {
        isConnected,
        doFilter
    };
};
const isInFilterFormBlock = (fieldSchema)=>{
    while(fieldSchema){
        if (fieldSchema['x-filter-targets']) return 'FilterFormBlockProvider' === fieldSchema['x-decorator'];
        fieldSchema = fieldSchema.parent;
    }
    return false;
};
export { utils_FilterBlockType as FilterBlockType, getSupportFieldsByAssociation, getSupportFieldsByForeignKey, isAssocField, isInFilterFormBlock, isSameCollection, mergeFilter, transformToFilter, useAssociatedFields, useFilterAPI, useSupportedBlocks };
