import React, {useContext, useState, useEffect, useRef, useMemo} from "react";

import {WappContext, withWapp} from "wapplr-react/dist/common/Wapp";
import getUtils from "wapplr-react/dist/common/Wapp/getUtils";

import Menu from "../Menu";
import AppContext from "../App/context";
import {withMaterialStyles} from "../Template/withMaterial";

import Typography from "@material-ui/core/Typography";
import MaterialList from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemAvatar from "@material-ui/core/ListItemAvatar";
import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction";
import ListItemText from "@material-ui/core/ListItemText";
import MaterialCard from "@material-ui/core/Card";
import CardHeader from "@material-ui/core/CardHeader";
import CardMedia from "@material-ui/core/CardMedia"
import CardContent from "@material-ui/core/CardContent"

import Avatar from "../Avatar";
import Dialog from "../Dialog";
import Pagination from "../Pagination";
import PageInfo from "../Pagination/PageInfo";
import PostContext from "../Post/context";
import getDefaultMenu, {getMenuProps} from "../Post/menu";

import getStatus from "../../utils/getStatus";

import materialStyle from "./materialStyle";
import style from "./style.css";
import clsx from "clsx";

function Card(props) {

    const context = useContext(WappContext);
    const appContext = useContext(AppContext);

    const {wapp, req} = context;

    const {
        style,
        posts,
        user,
        statusManager,
        dialog,
        utils,
        name,
        onClick,
        breakPoint = 991,
    } = props;

    const [narrow, _setNarrow] = useState(false);
    const container = useRef();

    useEffect(function didMount(){

        function setNarrow(value){
            if (narrow !== value){
                _setNarrow(value)
            }
        }

        function onResize() {
            if (container.current) {
                if (container.current.offsetWidth > breakPoint) {
                    setNarrow(false);
                } else {
                    setNarrow(true);
                }
            } else {
                if (window.innerWidth > breakPoint) {
                    setNarrow(false);
                } else {
                    setNarrow(true);
                }
            }
        }

        function addResizeListeners() {
            if (container.current && typeof ResizeObserver !== "undefined") {
                const resizeObserver = new ResizeObserver((entries) => {
                    onResize(entries);
                });
                resizeObserver.observe(container.current);
                return function removeEventListener(){
                    resizeObserver.disconnect();
                }
            } else {
                window.addEventListener("resize", onResize);
                return function removeEventListener(){
                    window.removeEventListener("resize", onResize);
                }
            }
        }

        const removeResizeListeners = addResizeListeners();

        onResize();

        return function willUnmount() {
            removeResizeListeners();
        }

    }, [narrow, breakPoint, wapp.globals.WAPP]);

    const userId = user?._id;

    const memoContent = useMemo(()=>{

        return(
            <>
                {posts.map(function (post, i){

                    const wappRequest = req.wappRequest;
                    const {path} = wappRequest;

                    const status = getStatus({user, post, appContext, statusManager, name});
                    const menuActions = {};

                    const menu = getDefaultMenu({
                        statusManager,
                        ...getMenuProps({
                            appContext,
                            menuActions,
                            dialog,
                            utils,
                            name,
                            post,
                            redirects: {
                                onDeleteSuccess: path,
                                onBanSuccess: path,
                                onApproveSuccess: path,
                                onFeaturedSuccess: path,
                                onRemoveFeaturedSuccess: path,
                            }
                        }),
                        getEditHref: function (p) {
                            const r = (p?.post?._id) ? "/" + p.post._id + "/edit" : "/";
                            return r + "?redirect=" + path;
                        }
                    });

                    menu.forEach((m)=>{delete m.featured});

                    const getAuthorObject = () =>{
                        return (post?._id && post?._author === post?._id && post?.name) ? post : (post?._author?._id) ? post?._author : null;
                    };

                    const avatarClick = (/*e*/) => {
                        const author = getAuthorObject();
                        wapp.getTargetObject().history.push({pathname: appContext.routes.userRoute + "/" + author._id, search:"", hash:""})
                    };

                    const getTitle = () => {
                        if (post.title){
                            return post.title;
                        }
                        if (post.name?.first && post.name?.last) {
                            return post.name.first +" "+ post.name.last;
                        }
                        return post.name?.first || "No title";
                    };

                    return (
                        <div
                            className={style.card}
                            key={i}
                        >
                            <MaterialCard
                                classes={{
                                    container: clsx(materialStyle.cardItem, style.cardItem),
                                    root: style.cardItemRoot
                                }}
                            >
                                <CardHeader
                                    avatar={
                                        <div className={style.avatarContainer} onClick={avatarClick}>
                                            <Avatar user={(post._author && post._author === post._id) ? post : post._author}/>
                                        </div>
                                    }
                                    action={
                                        <Menu
                                            parentRoute={appContext.routes[name+"Route"]}
                                            menu={menu}
                                            menuProperties={{user, post}}
                                            effect={function ({actions}) {
                                                menuActions.actions = actions;
                                            }}
                                            menuKey={"menu_"+appContext.routes[name+"Route"]+"/"+post._id+"_"+i}
                                        />
                                    }
                                    title={
                                        <div
                                            className={style.title}
                                            onClick={(e) => onClick(e, post)}
                                        >
                                            {getTitle()}
                                        </div>
                                    }
                                    subheader={
                                        <>
                                            {(post.subtitle) ?
                                                <span
                                                    className={clsx(style.block, style.subtitle)}
                                                    onClick={(e) => onClick(e, post)}
                                                >
                                            {post.subtitle}
                                        </span> : null
                                            }
                                            {(status) ?
                                                <span
                                                    className={clsx(style.block, style.statusText)}
                                                    onClick={(e) => onClick(e, post)}
                                                >
                                                {status}
                                            </span>
                                                : null
                                            }
                                        </>
                                    }
                                    classes={{
                                        content: style.cardHeaderContent
                                    }}
                                />
                                {(post.gallery?.length && post.gallery[0] && post.gallery[0].image) ?
                                    <CardMedia className={style.cardMedia} />
                                    : null
                                }
                                {(post.content_extract) ?
                                    <CardContent>
                                        <Typography
                                            variant={"body2"}
                                            color={"textSecondary"}
                                            component={"p"}
                                            className={style.cardContent}
                                            onClick={(e) => onClick(e, post)}
                                        >
                                            {post.content_extract}
                                        </Typography>
                                    </CardContent>
                                    : null
                                }
                            </MaterialCard>
                        </div>
                    )
                })}
            </>
        )
        // eslint-disable-next-line
    }, [

        userId,
        statusManager,
        name,
        dialog,
        onClick,
        utils,
        req.wappRequest,
        wapp,

        style.card,
        style.cardItem,
        style.cardItemRoot,
        style.avatarContainer,
        style.title,
        style.block,
        style.subtitle,
        style.statusText,
        style.cardHeaderContent,
        style.cardMedia,
        style.cardContent,
    ]);

    return (
        <div
            ref={container}
            className={clsx(
                style.cardsContainer,
                {[style.narrow]: narrow},
            )}
        >
            {memoContent}
        </div>
    )
}

function List(props) {

    const {posts, user, statusManager, dialog, utils, name, onClick} = props;

    const context = useContext(WappContext);
    const appContext = useContext(AppContext);

    const {req, wapp} = context;

    return (
        <MaterialList dense={true}>
            {posts.map(function (post, i){

                const wappRequest = req.wappRequest;
                const {path} = wappRequest;

                const status = getStatus({user, post, appContext, statusManager, name});
                const menuActions = {};

                const menu = getDefaultMenu({
                    statusManager,
                    ...getMenuProps({
                        appContext,
                        menuActions,
                        dialog,
                        utils,
                        name,
                        post,
                        redirects: {
                            onDeleteSuccess: path,
                            onBanSuccess: path,
                            onApproveSuccess: path,
                            onFeaturedSuccess: path,
                            onRemoveFeaturedSuccess: path,
                        }
                    }),
                    getEditHref: function (p) {
                        const r = (p?.post?._id) ? "/" + p.post._id + "/edit" : "/";
                        return r + "?redirect=" + path;
                    }
                });

                menu.forEach((m)=>{delete m.featured});

                function getAuthorObject() {
                    return (post?._id && post?._author === post?._id && post?.name) ? post : (post?._author?._id) ? post?._author : null;
                }

                const avatarClick = (/*e*/) => {
                    const author = getAuthorObject();
                    wapp.getTargetObject().history.push({pathname: appContext.routes.userRoute + "/" + author._id, search:"", hash:""})
                };

                return (
                    <ListItem
                        key={i}
                        classes={{
                            container: clsx(materialStyle.listItem, style.listItem),
                            root: style.listItemRoot
                        }}
                        onClick={(e) => onClick(e, post)}
                    >
                        <ListItemAvatar>
                            <div className={style.avatarContainer} onClick={avatarClick}>
                                <Avatar user={post._author}/>
                            </div>
                        </ListItemAvatar>
                        <ListItemText
                            primary={post.title || "No title"}
                            secondary={
                                <React.Fragment>
                                    {(post.subtitle) ? <span className={style.block}>{post.subtitle}</span> : null}
                                    {(status) ? <span className={style.block}>{status}</span> : null}
                                </React.Fragment>
                            }
                            classes={{
                                primary: style.title,
                                secondary: style.subtitle,
                            }}
                        />
                        <ListItemSecondaryAction>
                            <Menu
                                parentRoute={appContext.routes[name+"Route"]}
                                menu={menu}
                                menuProperties={{user, post}}
                                effect={function ({actions}) {
                                    menuActions.actions = actions;
                                }}
                            />
                        </ListItemSecondaryAction>
                    </ListItem>
                )
            })}
        </MaterialList>
    )
}

function Posts(props) {

    const context = useContext(WappContext);
    const appContext = useContext(AppContext);
    const postContext = useContext(PostContext);

    const {subscribe, materialStyle, name = "post", type = "list"} = props;
    const {wapp, req} = context;
    const utils = useMemo(()=>getUtils(context), [context]);

    let {
        user,
        post,
        /*parentRoute,*/
        statusManager,
    } = postContext;

    if (!statusManager){
        statusManager = wapp.getTargetObject().postTypes.findPostType({name: name}).statusManager;
    }

    if (!user) {
        user = utils.getRequestUser()
    }

    wapp.styles.use(style);

    const findData = utils.getGlobalState("res.responses."+name+"FindMany") || {};

    const [posts, setPosts] = useState(findData.items || []);
    const [pageInfo, setPageInfo] = useState(findData.pageInfo || {});

    async function onRequestResolved({value}) {
        const keys = [name+"FindMany"];
        const response = value;
        let foundEnabledKeys = false;

        let newPageInfo = null;
        let foundData = null;

        keys.forEach(function (requestName) {
            if (!foundEnabledKeys && response && response[requestName]){
                foundEnabledKeys = true;
                if (requestName === name+"FindMany"){
                    const findData = response[requestName] || {};
                    if (!newPageInfo) {
                        newPageInfo = findData.pageInfo || {};
                        foundData = findData;
                    }
                }
            }
        });

        if (foundData && newPageInfo && JSON.stringify(newPageInfo) !== JSON.stringify(pageInfo)) {
            const items = foundData.items || [];
            await setPosts([...items]);
            await setPageInfo({...newPageInfo});
            window.scrollTo({
                top: 0,
                left: 0,
                behavior: 'smooth'
            })
        }

    }

    useEffect(function (){
        const unsub = subscribe.requestResolved(onRequestResolved);
        return function useUnsubscribe(){
            unsub();
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [post]);

    const onClick = useMemo(()=>function (e, post) {

        wapp.getTargetObject().history.push({
            search:"",
            hash:"",
            ...wapp.getTargetObject().history.parsePath(appContext.routes[name+"Route"]+"/"+post._id)
        });

        e.preventDefault();

    }, [appContext.routes, name, wapp]);

    const dialog = useMemo(()=>{
        return {
            actions: {}
        };
    }, []);

    const dialogEffect = function ({actions}) {
        dialog.actions = actions;
    };

    const listProps = {style, posts, user, statusManager, dialog, utils, name, onClick};

    return (
        <div className={
            clsx(
                materialStyle.root,
                style.posts,
                {
                    [style.cardType] : !(type === "list")
                }
            )
        }>
            {(posts?.length) ?
                <div className={style.page}>
                    <PageInfo data={pageInfo} />
                    {(type === "list") ? <List {...listProps}/> : <Card {...listProps}/>}
                    <Pagination data={pageInfo} />
                    <Dialog effect={dialogEffect} />
                </div>
                :
                <div className={style.page}>
                    {(req.wappRequest.query.search) ? <PageInfo data={pageInfo} /> : null}
                    <div className={style.thereAreNoEntries}>
                        <Typography variant={"subtitle1"}>
                            {appContext.messages.thereAreNoEntries}
                        </Typography>
                    </div>
                </div>
            }
        </div>
    )
}

const WappComponent = withWapp(Posts);

const StyledComponent = withMaterialStyles(materialStyle, WappComponent);

export default StyledComponent;
