import { jsx } from "react/jsx-runtime";
import { useCallback, useEffect, useMemo, useState } from "react";
import { ArrayItems, FormItem } from "@tachybase/components";
import { FormProvider, connect, createForm, createSchemaField, observer, onFormValuesChange, uid, useField, useFieldSchema } from "@tachybase/schema";
import { Input, Select, Space, Spin, Tag } from "antd";
import dayjs from "dayjs";
import { useTranslation } from "react-i18next";
import { useAPIClient } from "../../../api-client/index.mjs";
import { useCollectionManager_deprecated } from "../../../collection-manager/hooks/useCollectionManager_deprecated.mjs";
import { mergeFilter } from "../../../filter-provider/utils.mjs";
import { SchemaComponent, useCompile } from "../../index.mjs";
import hooks, { useAssociationFieldContext } from "./hooks.mjs";
const EMPTY = 'N/A';
const SchemaField = createSchemaField({
    components: {
        Space: Space,
        Input: Input,
        ArrayItems: ArrayItems,
        FormItem: FormItem
    }
});
const CascadeSelect = connect((props)=>{
    var _associationField_componentProps;
    const { data, mapOptions, onChange, value } = props;
    const [selectedOptions, setSelectedOptions] = useState([
        {
            key: void 0,
            children: [],
            value: null
        }
    ]);
    const [options, setOptions] = useState(data);
    const [loading, setLoading] = useState(false);
    const compile = useCompile();
    const api = useAPIClient();
    const service = hooks(props);
    const { options: collectionField, field: associationField } = useAssociationFieldContext();
    const resource = api.resource(collectionField.target);
    const { getCollectionJoinField, getInterface } = useCollectionManager_deprecated();
    const fieldNames = null == associationField ? void 0 : null == (_associationField_componentProps = associationField.componentProps) ? void 0 : _associationField_componentProps.fieldNames;
    const [change, setChange] = useState(false);
    const targetField = (null == collectionField ? void 0 : collectionField.target) && (null == fieldNames ? void 0 : fieldNames.label) && getCollectionJoinField("".concat(collectionField.target, ".").concat(fieldNames.label));
    const operator = useMemo(()=>{
        if (null == targetField ? void 0 : targetField.interface) {
            var _getInterface_filterable, _getInterface;
            return (null == (_getInterface = getInterface(targetField.interface)) ? void 0 : null == (_getInterface_filterable = _getInterface.filterable) ? void 0 : _getInterface_filterable.operators[0].value) || '$includes';
        }
        return '$includes';
    }, [
        targetField
    ]);
    const field = useField();
    useEffect(()=>{
        if (value && !change) {
            var _values_map;
            const values = Array.isArray(value) ? extractLastNonNullValueObjects(null == value ? void 0 : value.filter((v)=>v.value), true) : transformNestedData(value);
            const options = null == values ? void 0 : null == (_values_map = values.map) ? void 0 : _values_map.call(values, (v)=>({
                    key: v.parentId,
                    children: [],
                    value: v
                }));
            setSelectedOptions(options);
        }
    }, [
        value
    ]);
    const mapOptionsToTags = useCallback((options)=>{
        try {
            return null == options ? void 0 : options.filter((v)=>[
                    'number',
                    'string'
                ].includes(typeof v[fieldNames.value])).map((option)=>{
                var _targetField_uiSchema;
                let label = compile(option[fieldNames.label]);
                if (null == targetField ? void 0 : null == (_targetField_uiSchema = targetField.uiSchema) ? void 0 : _targetField_uiSchema.enum) if (Array.isArray(label)) label = label.map((item, index)=>{
                    var _targetField_uiSchema_enum_find, _targetField_uiSchema_enum;
                    const option = null == (_targetField_uiSchema_enum_find = (_targetField_uiSchema_enum = targetField.uiSchema.enum).find) ? void 0 : _targetField_uiSchema_enum_find.call(_targetField_uiSchema_enum, (i)=>i.value === item);
                    if (option) return /*#__PURE__*/ jsx(Tag, {
                        color: option.color,
                        style: {
                            marginRight: 3
                        },
                        children: (null == option ? void 0 : option.label) || item
                    }, index);
                    return /*#__PURE__*/ jsx(Tag, {
                        children: item
                    }, item);
                }).reverse();
                else {
                    var _targetField_uiSchema_enum_find, _targetField_uiSchema_enum;
                    const item = null == (_targetField_uiSchema_enum_find = (_targetField_uiSchema_enum = targetField.uiSchema.enum).find) ? void 0 : _targetField_uiSchema_enum_find.call(_targetField_uiSchema_enum, (i)=>i.value === label);
                    if (item) label = /*#__PURE__*/ jsx(Tag, {
                        color: item.color,
                        children: item.label
                    });
                }
                if ((null == targetField ? void 0 : targetField.type) === 'date') label = dayjs(label).format('YYYY-MM-DD');
                if (mapOptions) return mapOptions({
                    [fieldNames.label]: label || EMPTY,
                    [fieldNames.value]: option[fieldNames.value]
                });
                return {
                    ...option,
                    [fieldNames.label]: label || EMPTY,
                    [fieldNames.value]: option[fieldNames.value]
                };
            }).filter(Boolean);
        } catch (err) {
            console.error(err);
            return options;
        }
    }, [
        null == targetField ? void 0 : targetField.uiSchema,
        fieldNames
    ]);
    const handleGetOptions = async (filter)=>{
        var _service_params, _response_data;
        const response = await resource.list({
            pageSize: 200,
            params: null == service ? void 0 : service.params,
            filter: mergeFilter([
                null == service ? void 0 : null == (_service_params = service.params) ? void 0 : _service_params.filter,
                filter
            ]),
            tree: filter.parentId ? void 0 : true
        });
        return null == response ? void 0 : null == (_response_data = response.data) ? void 0 : _response_data.data;
    };
    const handleSelect = async (value, option, index)=>{
        setChange(true);
        const data = await handleGetOptions({
            parentId: null == option ? void 0 : option.id
        });
        const options = [
            ...selectedOptions
        ];
        options.splice(index + 1);
        options[index] = {
            ...options[index],
            value: option
        };
        if (null == option ? void 0 : option.id) options[index + 1] = {
            key: null == option ? void 0 : option.id,
            children: (null == data ? void 0 : data.length) > 0 ? data : null
        };
        setSelectedOptions(options);
        if ([
            'o2m',
            'm2m'
        ].includes(collectionField.interface)) {
            const fieldValue = Array.isArray(associationField.fieldValue) ? associationField.fieldValue : [];
            fieldValue[field.index] = option;
            associationField.fieldValue = fieldValue;
        } else associationField.value = option;
        null == onChange || onChange(options);
    };
    const onDropdownVisibleChange = async (visible, selectedValue, index)=>{
        if (visible) {
            var _selectedValue_value;
            setLoading(true);
            const result = await handleGetOptions({
                parentId: null == selectedValue ? void 0 : selectedValue.key
            });
            setLoading(false);
            setOptions(result);
            if (index === (null == selectedOptions ? void 0 : selectedOptions.length) - 1 && (null == selectedValue ? void 0 : null == (_selectedValue_value = selectedValue.value) ? void 0 : _selectedValue_value.id)) {
                var _selectedValue_value1, _selectedValue_value2;
                const data = await handleGetOptions({
                    parentId: null == selectedValue ? void 0 : null == (_selectedValue_value1 = selectedValue.value) ? void 0 : _selectedValue_value1.id
                });
                const options = [
                    ...selectedOptions
                ];
                options.splice(index + 1);
                options[index] = {
                    ...options[index],
                    value: null == selectedValue ? void 0 : selectedValue.value
                };
                options[index + 1] = {
                    key: null == selectedValue ? void 0 : null == (_selectedValue_value2 = selectedValue.value) ? void 0 : _selectedValue_value2.id,
                    children: (null == data ? void 0 : data.length) > 0 ? data : null
                };
                setSelectedOptions(options);
                null == onChange || onChange(options);
            }
        }
    };
    const onSearch = async (search, selectedValue)=>{
        const serachParam = search ? {
            [fieldNames.label]: {
                [operator]: search
            }
        } : {};
        setLoading(true);
        const result = await handleGetOptions({
            ...serachParam,
            parentId: null == selectedValue ? void 0 : selectedValue.key
        });
        setLoading(false);
        setOptions(result);
    };
    return /*#__PURE__*/ jsx(Space, {
        wrap: true,
        children: selectedOptions.map((value, index)=>{
            var _value_value, _value_value1, _value_value2;
            return value.children && /*#__PURE__*/ jsx(Select, {
                disabled: associationField.disabled,
                allowClear: true,
                showSearch: true,
                autoClearSearchValue: true,
                filterOption: false,
                filterSort: null,
                defaultValue: {
                    label: null == value ? void 0 : null == (_value_value = value.value) ? void 0 : _value_value[fieldNames.label],
                    value: null == value ? void 0 : null == (_value_value1 = value.value) ? void 0 : _value_value1[fieldNames.value]
                },
                labelInValue: true,
                onSearch: (search)=>onSearch(search, value),
                fieldNames: fieldNames,
                style: {
                    minWidth: 150
                },
                onChange: (value, option)=>handleSelect(value, option, index),
                options: loading ? [] : mapOptionsToTags(options),
                onDropdownVisibleChange: (open)=>onDropdownVisibleChange(open, value, index),
                notFoundContent: loading ? /*#__PURE__*/ jsx(Spin, {
                    size: "small"
                }) : null
            }, "".concat(null == (_value_value2 = value.value) ? void 0 : _value_value2.id, "+ ").concat(value.key, " + ").concat(fieldNames.label));
        })
    });
});
const AssociationCascadeSelect = connect((props)=>/*#__PURE__*/ jsx("div", {
        children: /*#__PURE__*/ jsx(CascadeSelect, {
            ...props
        })
    }));
const InternalCascadeSelect = observer((props)=>{
    const { options: collectionField } = useAssociationFieldContext();
    const selectForm = useMemo(()=>createForm(), []);
    const { t } = useTranslation();
    const field = useField();
    const fieldSchema = useFieldSchema();
    useEffect(()=>{
        const id = uid();
        selectForm.addEffects(id, ()=>{
            onFormValuesChange((form)=>{
                if ('m2o' === collectionField.interface) {
                    var _form_values;
                    const value = extractLastNonNullValueObjects(null == (_form_values = form.values) ? void 0 : _form_values[fieldSchema.name]);
                    setTimeout(()=>{
                        form.setValuesIn(fieldSchema.name, value);
                        props.onChange(value);
                        field.value = value;
                    });
                } else {
                    var _form_values1;
                    const value = extractLastNonNullValueObjects(null == (_form_values1 = form.values) ? void 0 : _form_values1.select_array).filter((v)=>v && Object.keys(v).length > 0);
                    setTimeout(()=>{
                        field.value = value;
                        props.onChange(value);
                    });
                }
            });
        });
        return ()=>{
            selectForm.removeEffects(id);
        };
    }, []);
    const toValue = ()=>{
        if (Array.isArray(field.value) && field.value.length > 0) return field.value;
        return [
            {}
        ];
    };
    const defaultValue = toValue();
    useEffect(()=>{
        var _selectForm_values_select_array, _selectForm_values;
        const isChange = null == (_selectForm_values = selectForm.values) ? void 0 : null == (_selectForm_values_select_array = _selectForm_values.select_array) ? void 0 : _selectForm_values_select_array.filter((value)=>value && Object.keys(value).length);
        if ('m2o' !== collectionField.interface && props.value && !isChange.length) {
            const value = extractLastNonNullValueObjects(defaultValue).filter((v)=>v && Object.keys(v).length > 0);
            selectForm.setValues({
                select_array: value
            });
        }
    }, [
        props.value
    ]);
    const schema = {
        type: 'object',
        properties: {
            select_array: {
                type: 'array',
                'x-component': 'ArrayItems',
                'x-decorator': 'FormItem',
                default: defaultValue,
                items: {
                    type: 'void',
                    'x-component': 'Space',
                    properties: {
                        sort: {
                            type: 'void',
                            'x-decorator': 'FormItem',
                            'x-component': 'ArrayItems.SortHandle'
                        },
                        select: {
                            type: 'string',
                            'x-decorator': 'FormItem',
                            'x-component': AssociationCascadeSelect,
                            'x-component-props': {
                                ...props
                            }
                        },
                        remove: {
                            type: 'void',
                            'x-decorator': 'FormItem',
                            'x-component': 'ArrayItems.Remove'
                        }
                    }
                },
                properties: {
                    add: {
                        type: 'void',
                        title: t('Add new'),
                        'x-component': 'ArrayItems.Addition'
                    }
                }
            }
        }
    };
    return /*#__PURE__*/ jsx(FormProvider, {
        form: selectForm,
        children: 'm2o' === collectionField.interface ? /*#__PURE__*/ jsx(SchemaComponent, {
            components: {
                FormItem: FormItem
            },
            schema: {
                ...fieldSchema,
                default: field.value,
                title: '',
                'x-component': AssociationCascadeSelect,
                'x-component-props': {
                    ...props
                }
            }
        }) : /*#__PURE__*/ jsx(SchemaField, {
            schema: schema
        })
    });
}, {
    displayName: 'InternalCascadeSelect'
});
function extractLastNonNullValueObjects(data, flag) {
    let result = [];
    if (!Array.isArray(data)) return data;
    for (const sublist of data){
        let lastNonNullValue = null;
        if (Array.isArray(sublist)) {
            for(let i = (null == sublist ? void 0 : sublist.length) - 1; i >= 0; i--)if (sublist[i].value) {
                lastNonNullValue = sublist[i].value;
                break;
            }
            if (lastNonNullValue) result.push(lastNonNullValue);
        } else {
            lastNonNullValue = (null == sublist ? void 0 : sublist.value) ? sublist.value : null;
            if (lastNonNullValue) if (flag) {
                var _result_push;
                null == result || null == (_result_push = result.push) || _result_push.call(result, lastNonNullValue);
            } else result = lastNonNullValue;
            else {
                var _result_push1;
                null == result || null == (_result_push1 = result.push) || _result_push1.call(result, sublist);
            }
        }
    }
    return result;
}
function transformNestedData(inputData) {
    const resultArray = [];
    function recursiveTransform(data) {
        if (null == data ? void 0 : data.parent) {
            const { parent } = data;
            recursiveTransform(parent);
        }
        const { parent, ...other } = data;
        resultArray.push(other);
    }
    if (inputData) recursiveTransform(inputData);
    return resultArray;
}
export { InternalCascadeSelect, transformNestedData };
