import Grid from "@mui/material/Grid";
import {useAlert} from "../../../hooks/useAlert";
import * as React from "react";
import {useCallback, useEffect, useState} from "react";
import {Cocktail} from "../../../components/cocktails/Cocktail";
import {Fab, Skeleton} from "@mui/material";
import Box from "@mui/material/Box";
import {requests} from "../../../requests";
import {NoResult} from "../../../components/cocktails/NoResult";
import {FilterBlock} from "../../../components/cocktails/FilterBlock";
import {api} from "../../../lib/clients/api";
import {CocktailInfoModal} from "../../../components/cocktails/CocktailInfoModal";
import {useUser} from "../../../hooks/useUser";
import {blue} from "@mui/material/colors";
import UpIcon from "@mui/icons-material/KeyboardArrowUp";
import {sortList} from "../../../components/cocktails/sortingList";
import {getComparator} from "../../../components/core/getComparator";
import Button from "@mui/material/Button";
import Paper from "@mui/material/Paper";
import CheckMarks from "../../../components/cocktails/CheckMarks";
import {useSelect} from "../../../hooks/useSelect";

const filterList = (rows, filter, allowIngredients) => {
    let regExp = new RegExp("(.*?)" + filter.search + "(.*?)", "i");
    const sortingObj = sortList.find((s) => s.name === filter.sorting);
    const sortingValues = sortingObj.id.split("|");
    return rows
        .filter((row) => {
            const nameReg = row.name.split(" ").map((n) => n.match(regExp) !== null).includes(true);
            const ingredientReg = row.components
                .split(", ")
                .map((r) => r.match(regExp) !== null)
                .includes(true);
            return nameReg || ingredientReg;
        })
        .filter((row) => filter.onlyFavourite ? row.rating.favourite : true)
        .filter((row) => filter.glass.length === 0 || filter.glass.includes(row.glass))
        .filter((row) => filter.category.length === 0 || filter.category.includes(row.category))
        .filter((row) => filter.alcohol.length === 0 || filter.alcohol.includes(row.alcoholic))
        .filter((row) => {
            if (filter.tags.length === 0) {
                return true;
            }

            if (row.tags.length === 0) {
                return false;
            }
            return row.tags.split(",").find((tag) => filter.tags.includes(tag))
        })
        .filter((row) => {
            if (filter.iCount.length === 0) {
                return true;
            }
            const arr = row.components.split(", ");
            const count = arr.filter((n) => !allowIngredients.includes(n)).length;
            const filt = filter.ingredient.length === 0 || arr.filter((n) => filter.ingredient.includes(n)).length > 0;

            return filter.iCount === count && filt;
        })
        .filter((row) => {
            if (filter.inMenu === "") {
                return row;
            }
            const filterValue = filter.inMenu === "Есть в меню";
            return filterValue === row.inMenu;
        })
        .sort(getComparator(sortingValues[1], sortingValues[0], "name"))
}

const emptyFilter = {
    search: "",
    hidden: true,
    onlyFavourite: false,
    glass: [],
    category: [],
    alcohol: [],
    tags: [],
    iCount: [],
    ingredient: [],
    inMenu: "",
    sorting: "Название по возрастанию"
}

const CocktailsPageContent = ({all}) => {
    const {user} = useUser();
    const {createError, createSuccess} = useAlert();
    const [allowIngredients, setAllowIngredients] = useState([])
    const [rows, setRows] = useState([]);
    const [filter, setFilter] = useState(emptyFilter)
    const [chips, setChips] = useState([])
    const [page, setPage] = useState(-1);
    const [load, setLoad] = useState(false);
    const [isEnd, setIsEnd] = useState(false);
    const [isNew, setIsNew] = useState(true);

    const {selectCocktail, getCocktail, getOpenCocktail} = useSelect();

    const loading = useCallback(() => {
        const size = Math.floor((window.innerWidth) / 350) * 5;
        if (load || (!isNew && isEnd)) {
            return false;
        }
        setLoad(true);
        const request = {
            ...filter,
            all: all,
            sort: sortList.find((s) => s.name === filter.sorting).id,
            page: page + 1,
            size: size,
            iCount: Array.isArray(filter.iCount) ? null : filter.iCount
        }
        api().post(requests.cocktails.menu, request)
            .then((r) => {
                if (r.data.length === 0) {
                    if(isNew) {
                        setRows([]);
                    }
                    setIsEnd(true);
                    setLoad(false);
                    return;
                }
                const cocktails = isNew ? r.data : rows.concat(r.data);
                setRows(cocktails);
                setIsNew(false);
                setPage(page + 1);
                setLoad(false);
            })
            .catch((r) => {
                setLoad(false);
                createError("Ошибка загрузки данных от сервера Status:" + r.status)
            })
        // eslint-disable-next-line
    }, [load, isEnd, page]);
    useEffect(() => {
        const handleScroll = () => {
            const {scrollTop, scrollHeight, clientHeight} = document.documentElement;
            if (scrollTop + clientHeight >= scrollHeight - 100) {
                loading();
            }
        }
        window.addEventListener('scroll', handleScroll);
        return () => window.removeEventListener('scroll', handleScroll);
    }, [loading]);
    useEffect(() => {
        api().get(requests.bar.ingredientSimple)
            .then((r) => {
                const arr = r.data.filter((i) => i.isHave)
                    .map((i) => i.name)
                setAllowIngredients(arr)
            })
            .catch(() => createError("Ошибка получения ингредиентов"))
        // eslint-disable-next-line
    }, [])
    useEffect(() => {
        loading();
    }, [filter])
    useEffect(() => {
        if (!all) {
            return;
        }
        const ingredients = new Set();
        rows.map((c) => c.components)
            .map((c) => c.split(", "))
            .map((c) => c.filter((i) => !allowIngredients.includes(i)))
            .filter((nhc) => nhc.length === 1)
            .map((fc) => fc[0])
            .forEach((i) => ingredients.add(i))
        setChips(Array.from(ingredients).sort(getComparator()));
    }, [rows, allowIngredients])

    const renderSkeleton = () => {
        return Array.from({length: 3}, () => null)
            .map((v, index) => <Skeleton sx={{m: 2}}
                                         key={index}
                                         variant="rounded"
                                         width={350}
                                         height={690}/>);
    }
    const handleChangeRating = (row, value) => {
        const newState = rows.map((r) => {
            if (row.id === r.id) {
                let newRating = r.rating;
                newRating.rating = value
                return {
                    ...r,
                    rating: newRating
                }
            }
            return r;
        })
        api().post(`${requests.cocktails.rating}${row.id}&rating=${value}`)
            .then(() => {
                setRows(newState);
                createSuccess("Спасибо за оценку!")
            }).catch(() => createError("Ошибка сохранения"))

    }
    const handleFilterChange = (filterName, value) => {
        const newState = {
            ...filter,
            [filterName]: value
        }
        setFilter(newState)
        setIsNew(true);
        setIsEnd(false);
        setPage(-1);
    }
    const handleFavourite = (row) => {
        const value = !row.rating.favourite;
        const newState = rows.map((r) => {
            if (r.id === row.id) {
                let newRating = r.rating;
                newRating.favourite = value;
                return {
                    ...r,
                    rating: newRating
                }
            }
            return r;
        });
        let url = `${requests.cocktails.favourite}${row.id}`;
        let request = value ? api().put(url) : api().delete(url);

        request
            .then(() => {
                setRows(newState);
                createSuccess("Спасибо за оценку!")
            }).catch(() => createError("Ошибка сохранения"))
    }
    const handleFilterClear = () => {
        setFilter(emptyFilter);
    }
    const handleSelectCocktail = (row) => {
        selectCocktail(row.id)
        // setSelectedCocktail(row.id)
        // setOpen(true)
    }
    const handleEditMenu = (row, value) => {
        const newState = rows.map((r) => {
            if (r.id !== row.id) {
                return r;
            }
            if (all) {
                return {
                    ...r,
                    inMenu: value
                }
            }
            return null
        }).filter((r) => r !== null);

        api().post(`${requests.cocktails.menu}?id=${row.id}&value=${value}`)
            .then(() => setRows(newState))
            .catch(() => createError("Ошибка сохранения данных"))
    }
    const editMenuBlock = (row) => {
        if (user.role === "USER" || user.role === "ADMIN_NOT_BARMEN") {
            return null;
        }
        return (
            <Button color={row.inMenu ? 'error' : 'success'} variant='contained'
                    onClick={() => handleEditMenu(row, !row.inMenu)}>
                {(row.inMenu ? 'Удалить из' : 'Добавить в') + ' меню'}
            </Button>
        )
    }

    return (
        <Box>
            {/*<Loading loading={load}/>*/}
            {/*Модальное окно информации о коктейле*/}
            <CocktailInfoModal row={getCocktail()} open={getOpenCocktail()}/>
            {/*Блок фильтров*/}
            <FilterBlock
                filter={filter}
                handleFilterChange={handleFilterChange}
                handleClearFilter={handleFilterClear}
                barmen={user.role !== 'USER'}
                all={all}
            />

            {/*todo: доделать фильтр по количеству недостающих ингредиентов*/}
            {/*{*/}
            {/*    (all && filter.iCount === 1) && (*/}
            {/*        <Paper sx={{mt: 1}}>*/}
            {/*            <CheckMarks rows={chips} name={"Выбор ингредиента"} filterName={"ingredient"}*/}
            {/*                        filterValue={filter.ingredient}*/}
            {/*                        handleChange={handleFilterChange}*/}
            {/*                        identity*/}
            {/*            />*/}
            {/*        </Paper>*/}
            {/*    )*/}
            {/*}*/}
            <Box>
                {/*Основное содержимое*/}
                <Grid container rowSpacing={2} columnSpacing={{xs: 1, sm: 1, md: 2}} sx={{m: 1}}>
                    {rows.length > 0 && rows.map((row) => {
                        return (
                            <Cocktail key={row.id} row={row} handleFavourite={handleFavourite}
                                      handleChangeRating={handleChangeRating}
                                      handleSelect={handleSelectCocktail}
                                      editMenuBlock={editMenuBlock}
                            />
                        )
                    })}
                    {load && renderSkeleton()}
                    {rows.length === 0 && (<NoResult/>)}
                </Grid>
            </Box>
            <Fab sx={{
                alpha: '30%',
                position: 'sticky',
                left: 'calc(100% - 16px)',
                bottom: '16px',
                color: 'common.white',
                bgcolor: blue[600],
                '&:hover': {
                    bgcolor: blue[600],
                },
            }}
                 onClick={() => window.window.scrollTo(0, 0)}
                 aria-label='Expand'
                 color='inherit'>
                <UpIcon/>
            </Fab>
        </Box>
    );
}

export default CocktailsPageContent;