import Select from 'react-select';
import AsyncSelect from 'react-select/async';
import { OptionsOrGroups } from 'react-select';
import { getPriductCategories } from '@/lib/product-categories';
import { useEffect, useState, useRef } from 'react';

export interface ProductCategorySelectorProps {
    includeCategories: string[];
    excludeCategories: string[];
    includedProducts: string[];
    excludedProducts: string[];
    onIncludeCategoriesChange: (categories: string[]) => void;
    onExcludeCategoriesChange: (categories: string[]) => void;
    onIncludedProductsChange: (products: string[]) => void;
    onExcludedProductsChange: (products: string[]) => void;
    isUpdate?: boolean;
    showIncludeOnly?: boolean;
    showExcludeOnly?: boolean;
    freeItemProductId?: string;
    onFreeItemProductChange?: (productId: string) => void;
    freeItemCaseId?: number;
}

const ProductCategorySelector: React.FC<ProductCategorySelectorProps> = ({
    includeCategories,
    excludeCategories,
    includedProducts,
    excludedProducts,
    onIncludeCategoriesChange,
    onExcludeCategoriesChange,
    onIncludedProductsChange,
    onExcludedProductsChange,
    isUpdate = false,
    showIncludeOnly = false,
    showExcludeOnly = false,
    freeItemProductId,
    onFreeItemProductChange,
    freeItemCaseId,
}) => {
    const [productCategories, setProductCategories] = useState<any[]>([]);
    const [selectedExcludedProducts, setSelectedExcludedProducts] = useState<any[]>([]);
    const [selectedIncludedProducts, setSelectedIncludedProducts] = useState<any[]>([]);
    const [selectedFreeItemProduct, setSelectedFreeItemProduct] = useState<any>(null);
    const debounceTimeoutRef = useRef<any>(null);
    const freeItemDebounceTimeoutRef = useRef<any>(null);

    const fetchProductCategories = async () => {
        const resProductCat = await getPriductCategories();
        const formattedProductCatOption = Array.isArray(resProductCat)
            ? resProductCat.map((option: { category_name: string }) => ({
                  value: option.category_name,
                  label: option.category_name.charAt(0).toUpperCase() + option.category_name.slice(1),
              }))
            : [];
        setProductCategories(formattedProductCatOption);
    };

    useEffect(() => {
        fetchProductCategories();
    }, []);

    useEffect(() => {
        if (isUpdate) {
            if (excludedProducts && excludedProducts.length > 0) {
                getSelectedProducts(excludedProducts, setSelectedExcludedProducts);
            } else {
                setSelectedExcludedProducts([]);
            }

            if (includedProducts && includedProducts.length > 0) {
                getSelectedProducts(includedProducts, setSelectedIncludedProducts);
            } else {
                setSelectedIncludedProducts([]);
            }

            if (freeItemProductId) {
                getSelectedProducts([freeItemProductId], setSelectedFreeItemProduct);
            } else {
                setSelectedFreeItemProduct(null);
            }
        }
    }, [isUpdate, excludedProducts, includedProducts, freeItemProductId]);

    const getSelectedProducts = async (productIds: string[], setter: (products: any[]) => void) => {
        try {
            if (!productIds || productIds.length === 0) {
                setter([]);
                return;
            }

            const api_url = process.env.API_URL;
            const response = await fetch(`${api_url}api/products/product-list`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ products: productIds }),
                credentials: 'include',
            });

            if (!response.ok) {
                console.error('Response not OK:', response.status);
                setter([]);
                return;
            }

            const data = await response.json();

            const formattedData = (Array.isArray(data) ? data : [])
                .filter((item: any) => item && (item._id || item.id))
                .map((item: any) => ({
                    value: (item._id || item.id).toString(),
                    label: item.product_title || '',
                }));

            setter(formattedData);
        } catch (error) {
            console.error('Error fetching selected products:', error);
            setter([]);
        }
    };

    const loadOptions = async (inputValue: string, isForIncluded: boolean): Promise<OptionsOrGroups<any, any>> => {
        if (!inputValue || inputValue.length < 3) return [];

        if (debounceTimeoutRef.current) {
            clearTimeout(debounceTimeoutRef.current);
        }

        return new Promise((resolve) => {
            debounceTimeoutRef.current = setTimeout(async () => {
                try {
                    const api_url = process.env.API_URL;
                    const response = await fetch(`${api_url}api/products/product-list?q=${inputValue}`, {
                        method: 'GET',
                        headers: { 'Content-Type': 'application/json' },
                        credentials: 'include',
                    });
                    const data = await response.json();
                    const options = (Array.isArray(data) ? data : [])
                        .filter((item: any) => {
                            if (!item || !(item._id || item.id)) return false;
                            const productId = (item._id || item.id).toString();
                            if (isForIncluded && excludedProducts.includes(productId)) {
                                return false;
                            }
                            if (!isForIncluded && includedProducts.includes(productId)) {
                                return false;
                            }
                            return true;
                        })
                        .map((item: any) => ({
                            value: (item._id || item.id).toString(),
                            label: item.product_title || item.product_name || '',
                        }));
                    resolve(options);
                } catch (error) {
                    console.error('Error loading options:', error);
                    resolve([]);
                }
            }, 500);
        });
    };

    const loadIncludedProductsOptions = (inputValue: string) => loadOptions(inputValue, true);
    const loadExcludedProductsOptions = (inputValue: string) => loadOptions(inputValue, false);

    const loadFreeItemProductOptions = async (inputValue: string): Promise<OptionsOrGroups<any, any>> => {
        if (!inputValue || inputValue.length < 2) return [];

        if (freeItemDebounceTimeoutRef.current) {
            clearTimeout(freeItemDebounceTimeoutRef.current);
        }

        return new Promise((resolve) => {
            freeItemDebounceTimeoutRef.current = setTimeout(async () => {
                try {
                    const api_url = process.env.API_URL;
                    const response = await fetch(`${api_url}api/products/product-list?q=${inputValue}&product_status=publish`, {
                        method: 'GET',
                        headers: { 'Content-Type': 'application/json' },
                        credentials: 'include',
                    });
                    const data = await response.json();
                    const options = (Array.isArray(data) ? data : [])
                        .filter((item: any) => item && (item._id || item.id))
                        .map((item: any) => ({
                            value: (item._id || item.id).toString(),
                            label: item.product_title || '',
                        }));
                    resolve(options);
                } catch (error) {
                    console.error('Error loading free item product options:', error);
                    resolve([]);
                }
            }, 500);
        });
    };

    const handleFreeItemProduct = (selectedOption: any) => {
        const productId = selectedOption ? selectedOption.value : '';
        setSelectedFreeItemProduct(selectedOption);
        if (onFreeItemProductChange) {
            onFreeItemProductChange(productId);
        }
    };

    const handleIncludeCategories = (selectedOptions: any) => {
        const categories = selectedOptions ? selectedOptions.map((cat: any) => cat.value) : [];

        const validCategories = categories.filter((category: string) => !excludeCategories.includes(category));

        onIncludeCategoriesChange(validCategories);
    };

    const handleExcludeCategories = (selectedOptions: any) => {
        const categories = selectedOptions ? selectedOptions.map((cat: any) => cat.value) : [];

        const validCategories = categories.filter((category: string) => !includeCategories.includes(category));

        onExcludeCategoriesChange(validCategories);
    };

    const handleIncludedProducts = (selectedItems: any) => {
        const products = selectedItems ? selectedItems.map((p: any) => p.value) : [];

        const validProducts = products.filter((productId: string) => !excludedProducts.includes(productId));

        if (validProducts.length !== products.length) {
            const validSelectedItems = selectedItems ? selectedItems.filter((item: any) => validProducts.includes(item.value)) : [];
            setSelectedIncludedProducts(validSelectedItems);
        } else {
            setSelectedIncludedProducts(selectedItems || []);
        }

        onIncludedProductsChange(validProducts);
    };

    const handleExcludedProducts = (selectedItems: any) => {
        const products = selectedItems ? selectedItems.map((p: any) => p.value) : [];

        const validProducts = products.filter((productId: string) => !includedProducts.includes(productId));

        if (validProducts.length !== products.length) {
            const validSelectedItems = selectedItems ? selectedItems.filter((item: any) => validProducts.includes(item.value)) : [];
            setSelectedExcludedProducts(validSelectedItems);
        } else {
            setSelectedExcludedProducts(selectedItems || []);
        }

        onExcludedProductsChange(validProducts);
    };

    return (
        <>
            {!showExcludeOnly && (
                <div className="custom-select mt-4 flex items-center w-full justify-around">
                    <label htmlFor="include_categories" className="mb-0 w-[150px]">
                        Include Categories
                    </label>
                    <Select
                        placeholder="Select Categories"
                        options={productCategories.filter((cat: any) => !excludeCategories.includes(cat.value))}
                        value={includeCategories.map((category) => ({
                            value: category,
                            label: category,
                        }))}
                        onChange={handleIncludeCategories}
                        className="w-2/3 lg:w-[250px]"
                        classNamePrefix="user-form-select"
                        isMulti
                        isSearchable={true}
                    />
                </div>
            )}
            {!showIncludeOnly && (
                <div className="custom-select mt-4 flex items-center justify-around">
                    <label htmlFor="exclude_categories" className="mb-0 w-[150px]">
                        Exclude Categories
                    </label>
                    <Select
                        placeholder="Select Categories"
                        options={productCategories.filter((cat: any) => !includeCategories.includes(cat.value))}
                        value={excludeCategories.map((category) => ({
                            value: category,
                            label: category,
                        }))}
                        onChange={handleExcludeCategories}
                        className="w-2/3 lg:w-[250px]"
                        isMulti
                        isSearchable={true}
                        classNamePrefix="user-form-select"
                    />
                </div>
            )}
            {!showExcludeOnly && (
                <div className="custom-select mt-4 flex items-center justify-around">
                    <label htmlFor="included_products" className="mb-0 w-[150px]">
                        Included Products
                    </label>
                    <AsyncSelect
                        isMulti
                        loadOptions={loadIncludedProductsOptions}
                        className="w-2/3 lg:w-[250px]"
                        placeholder="Search for product"
                        value={selectedIncludedProducts}
                        onChange={handleIncludedProducts}
                        classNamePrefix="user-form-select"
                    />
                </div>
            )}
            {!showIncludeOnly && (
                <div className="custom-select mt-4 flex items-center justify-around">
                    <label htmlFor="excluded_products" className="mb-0 w-[150px]">
                        Excluded Products
                    </label>
                    <AsyncSelect
                        isMulti
                        loadOptions={loadExcludedProductsOptions}
                        className="w-2/3 lg:w-[250px]"
                        placeholder="Search for product"
                        value={selectedExcludedProducts}
                        onChange={handleExcludedProducts}
                        classNamePrefix="user-form-select"
                    />
                </div>
            )}
            {onFreeItemProductChange !== undefined && (
                <div className="custom-select mt-4 flex items-center justify-around border-t pt-4">
                    <label htmlFor="free_item_product" className="mb-0 w-[150px]">
                        Free Item Product
                    </label>
                    <AsyncSelect
                        loadOptions={loadFreeItemProductOptions}
                        className="w-2/3 lg:w-[250px]"
                        placeholder="Pilih produk untuk free item"
                        value={selectedFreeItemProduct}
                        onChange={handleFreeItemProduct}
                        classNamePrefix="user-form-select"
                        isClearable
                    />
                </div>
            )}
        </>
    );
};

export default ProductCategorySelector;
