import {useCallback, useEffect, useRef, useState} from "@wordpress/element";
import {__} from "@wordpress/i18n";
import MultiSelect from "../../multiselect";
import {GetPosts} from "../../../../rest/wp-objects";
import {handleError} from "../../../../helpers/notifications";

export default function WPObjectsMultiSelect({
                                                 limit,
                                                 setLimit,
                                                 isDataSet,
                                                 postType,
                                                 additionalQueryParams,
                                                 onJetEngineFieldsUpdate,
                                                 onJetEngineMetaBoxFieldsUpdate,
                                                 validateField,
                                                 errors,
                                                 setLoading,
                                                 saving,
                                                 addNotification,
                                                 showAllOption = false
                                             }) {
    const [objects, setObjects] = useState([]);
    const [savedObjects, setSavedObjects] = useState([]);
    const [pagination, setPagination] = useState({
        page: 1,
        perPage: 10,
        total: 0,
    });

    /**
     * Update WP objects list - only when data is actually set
     */
    useEffect(() => {
        if (isDataSet && postType) {
            // Saved objects
            getSavedObjects(postType, limit);
            // Load wp objects
            getWpObjects(postType, {
                page: 1,
                perPage: pagination.perPage,
            }, true);
        }
    }, [isDataSet, postType]);

    /**
     * Get WP objects
     *
     * @param {string} type Post type
     * @param {object} params Query params
     * @param {boolean} reset Reset or append
     */
    const getWpObjects = async (type, params, reset = false) => {
        setLoading(prev => prev + 1);
        // Default params
        const reqParams = {
            page: params?.page || 1,
            per_page: params?.perPage || 10,
        };
        // Add search param
        if (params?.search) {
            reqParams.lbaic_title_search = params.search;
        }
        // If we have specific IDs to fetch (for saved values), add them to the request
        if (params?.include?.length) {
            reqParams.include = params.include;
            // Adjust the per_page to have all saved posts
            if (reqParams.per_page < params.include.length) {
                reqParams.per_page = params.include.length;
            }
        }
        // Add additional query params
        if (additionalQueryParams) {
            const {include, ...moreParams} = additionalQueryParams;
            // More params
            Object.assign(reqParams, moreParams);
            // `Include` param
            if (include && include.length) {
                reqParams.include = [
                    ...(reqParams.include?.length > 0 ? reqParams.include : []),
                    ...include
                ];
            }
        }
        try {
            // Get posts
            const res = await GetPosts(type, reqParams);
            // Prepare options
            const items = res.items?.length ? res.items : [];
            // Update state
            if (reset) {
                setObjects([...items]);
            } else {
                setObjects(prevState => [...prevState, ...items]);
            }
            // JetEngine fields
            if (res.jet_engine_custom_fields?.items?.length) {
                onJetEngineFieldsUpdate(res.jet_engine_custom_fields.items);
            } else {
                onJetEngineFieldsUpdate([]);
            }
            // JetEngine meta box fields
            if (typeof onJetEngineMetaBoxFieldsUpdate === 'function') {
                if (res.jet_engine_meta_box_fields?.items?.length) {
                    onJetEngineMetaBoxFieldsUpdate(res.jet_engine_meta_box_fields.items);
                } else {
                    onJetEngineMetaBoxFieldsUpdate([]);
                }
            }
            // Pagination info
            setPagination(prevState => ({
                ...prevState,
                page: reqParams.page,
                total: res.total,
            }));
        } catch (e) {
            handleError(e, addNotification, {
                title: __("Failed to get objects.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Please check and try again.", 'limb-chatbot'),
            });
        }
        setLoading(prev => prev - 1);
    }

    /**
     * Get saved objects
     *
     * @param {string} type Post type
     * @param {number[]} ids Posts ids
     * @return {Promise<void>}
     */
    const getSavedObjects = async (type, ids) => {
        const idsArray = Array.isArray(ids) ? ids : [];
        if (ids === 'all' || !idsArray.length) {
            setSavedObjects([]);
            return;
        }
        setLoading(prev => prev + 1);
        try {
            const res = await GetPosts(type, {
                per_page: idsArray.length,
                include: idsArray,
            });
            if (res.items?.length) {
                setSavedObjects(res.items);
            } else {
                setSavedObjects([]);
            }
        } catch (e) {
            handleError(e, addNotification, {
                title: __("Failed to get saved objects.", 'limb-chatbot'),
                description: e.message ? __(e.message, 'limb-chatbot') : __("Please check and try again.", 'limb-chatbot'),
            });
        }
        setLoading(prev => prev - 1);
    }

    const search = useCallback(async (params) => {
        return await getWpObjects(postType, params, true);
    }, [postType]);

    const loadMore = useCallback(async (params) => {
        return await getWpObjects(postType, params);
    }, [postType]);

    const allOption = {
        label: __("All", 'limb-chatbot'),
        value: 'all',
    };

    const options = showAllOption
        ? [
            allOption,
            ...objects.map(item => ({
                label: item.title,
                value: item.id,
            }))
        ]
        : objects.map(item => ({
            label: item.title,
            value: item.id,
        }));

    const savedValueOptions = savedObjects.map(item => ({
        label: item.title,
        value: item.id,
    }));

    const normalizedSavedValueOptions = showAllOption && limit === 'all'
        ? [allOption, ...savedValueOptions]
        : savedValueOptions;

    const normalizedValue = showAllOption && limit === 'all'
        ? ['all']
        : Array.isArray(limit)
            ? limit
            : [];

    const handleSetLimit = (newValue) => {
        if (!Array.isArray(newValue) || !newValue.length) {
            setLimit([]);
            return;
        }

        if (showAllOption && newValue.includes('all')) {
            if (limit === 'all') {
                const filtered = newValue.filter(item => item !== 'all');
                setLimit(filtered.length ? filtered : 'all');
            } else {
                setLimit('all');
            }
            return;
        }

        setLimit(newValue);
    }

    const handleValidate = (value) => {
        if (typeof validateField === 'function') {
            if (showAllOption && Array.isArray(value) && value.includes('all')) {
                validateField('all');
            } else {
                validateField(value || []);
            }
        }
    }

    return <MultiSelect
        value={normalizedValue}
        setValue={handleSetLimit}
        options={options}
        savedValueOptions={normalizedSavedValueOptions}
        placeholder={__("Posts", 'limb-chatbot')}
        searchable
        onSearch={search}
        onLoadMore={loadMore}
        pagination={pagination}
        setPagination={setPagination}
        validate={handleValidate}
        errorMessage={errors}
        disabled={!postType || saving}
    />
}