import React, { ErrorInfo, ReactElement, useEffect } from 'react';
import clsx from 'clsx';
import Drawer from '@mui/material/Drawer';
import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar';
import List from '@mui/material/List';
import IconButton from '@mui/material/IconButton';
import { useStyles } from './style';
import { MapsList } from './maps-list';
import { createIntl, createIntlCache, FormattedMessage, IntlProvider } from 'react-intl';
import { useQuery, useMutation, useQueryClient } from 'react-query';
import { activeInstance } from '../../redux/clientSlice';
import { useSelector } from 'react-redux';
import Client, { Label } from '../../classes/client';
import ActionDispatcher from './action-dispatcher';
import { ActionType } from './action-chooser';
import AccountMenu from './account-menu';
import HelpMenu from './help-menu';
import LanguageMenu from './language-menu';
import AppI18n, { Locales } from '../../classes/app-i18n';

import ListItemIcon from '@mui/material/ListItemIcon';

import AddCircleTwoTone from '@mui/icons-material/AddCircleTwoTone';
import CloudUploadTwoTone from '@mui/icons-material/CloudUploadTwoTone';
import DeleteOutlineTwoTone from '@mui/icons-material/DeleteOutlineTwoTone';
import LabelTwoTone from '@mui/icons-material/LabelTwoTone';
import PersonOutlineTwoTone from '@mui/icons-material/PersonOutlineTwoTone';
import PublicTwoTone from '@mui/icons-material/PublicTwoTone';
import ScatterPlotTwoTone from '@mui/icons-material/ScatterPlotTwoTone';
import ShareTwoTone from '@mui/icons-material/ShareTwoTone';
import StarTwoTone from '@mui/icons-material/StarTwoTone';
import Tooltip from '@mui/material/Tooltip';
import Button from '@mui/material/Button';
import Link from '@mui/material/Link';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import ListItemSecondaryAction from '@mui/material/ListItemSecondaryAction';

import logoIcon from './logo-small.svg';
import poweredByIcon from './pwrdby-white.svg';
import LabelDeleteConfirm from './maps-list/label-delete-confirm';
import ReactGA from 'react-ga4';
import { withStyles } from '@mui/styles';


export type Filter = GenericFilter | LabelFilter;

export interface GenericFilter {
    type: 'public' | 'all' | 'starred' | 'shared' | 'label' | 'owned';
}

export interface LabelFilter {
    type: 'label';
    label: Label;
}

interface ToolbarButtonInfo {
    filter: GenericFilter | LabelFilter;
    label: string;
    icon: React.ReactElement;
}

const MapsPage = (): ReactElement => {
    const classes = useStyles();
    const [filter, setFilter] = React.useState<Filter>({ type: 'all' });
    const client: Client = useSelector(activeInstance);
    const queryClient = useQueryClient();
    const [activeDialog, setActiveDialog] = React.useState<ActionType | undefined>(undefined);
    const [labelToDelete, setLabelToDelete] = React.useState<number | null>(null);
    // Reload based on user preference ...
    const userLocale = AppI18n.getUserLocale();

    const cache = createIntlCache();
    const intl = createIntl({
        defaultLocale: userLocale.code,
        locale: Locales.EN.code,
        messages: userLocale.message
    }, cache)

    useEffect(() => {
        document.title = intl.formatMessage({
            id: 'maps.page-title',
            defaultMessage: 'My Maps | WiseMapping',
        });
        ReactGA.send({ hitType: 'pageview', page: window.location.pathname, title: 'Maps List' });
    }, []);

    const mutation = useMutation((id: number) => client.deleteLabel(id), {
        onSuccess: () => {
            queryClient.invalidateQueries('labels');
            queryClient.invalidateQueries('maps');
        },
        onError: (error) => {
            console.error(`Unexpected error ${error}`);
        },
    });

    const handleMenuClick = (filter: Filter) => {
        queryClient.invalidateQueries('maps');
        setFilter(filter);
    };

    const handleLabelDelete = (id: number) => {
        mutation.mutate(id);
    };

    const { data } = useQuery<unknown, ErrorInfo, Label[]>('labels', () => {
        return client.fetchLabels();
    });

    const labels: Label[] = data ? data : [];
    const filterButtons: ToolbarButtonInfo[] = [
        {
            filter: { type: 'all' },
            label: intl.formatMessage({ id: 'maps.nav-all', defaultMessage: 'All' }),
            icon: <ScatterPlotTwoTone color="secondary" />,
        },
        {
            filter: { type: 'owned' },
            label: intl.formatMessage({ id: 'maps.nav-onwned', defaultMessage: 'Owned' }),
            icon: <PersonOutlineTwoTone color="secondary" />,
        },
        {
            filter: { type: 'starred' },
            label: intl.formatMessage({ id: 'maps.nav-starred', defaultMessage: 'Starred' }),
            icon: <StarTwoTone color="secondary" />,
        },
        {
            filter: { type: 'shared' },
            label: intl.formatMessage({ id: 'maps.nav-shared', defaultMessage: 'Shared with me' }),
            icon: <ShareTwoTone color="secondary" />,
        },
        {
            filter: { type: 'public' },
            label: intl.formatMessage({ id: 'maps.nav-public', defaultMessage: 'Public' }),
            icon: <PublicTwoTone color="secondary" />,
        },
    ];

    labels.forEach((l) =>
        filterButtons.push({
            filter: { type: 'label', label: l },
            label: l.title,
            icon: <LabelTwoTone style={{ color: l.color ? l.color : 'inherit' }} />,
        })
    );

    return (
        <IntlProvider
            locale={userLocale.code}
            defaultLocale={Locales.EN.code}
            messages={userLocale.message}
        >
            <div className={classes.root}>
                <AppBar
                    position="fixed"
                    className={clsx(classes.appBar, {
                        [classes.appBarShift]: open,
                    })}
                    variant="outlined"
                    elevation={0}
                >
                    <Toolbar>
                        <Tooltip
                            arrow={true}
                            title={intl.formatMessage({
                                id: 'maps.create-tooltip',
                                defaultMessage: 'Create a new mindmap',
                            })}
                        >
                            <Button
                                color="primary"
                                data-testid="create"
                                size="medium"
                                variant="contained"
                                type="button"
                                disableElevation={true}
                                startIcon={<AddCircleTwoTone />}
                                className={classes.newMapButton}
                                onClick={() => setActiveDialog('create')}
                            >
                                <FormattedMessage id="action.new" defaultMessage="New map" />
                            </Button>
                        </Tooltip>

                        <Tooltip
                            arrow={true}
                            title={intl.formatMessage({
                                id: 'maps.import-desc',
                                defaultMessage: 'Import from other tools',
                            })}
                        >
                            <Button
                                color="primary"
                                size="medium"
                                variant="outlined"
                                type="button"
                                disableElevation={true}
                                startIcon={<CloudUploadTwoTone />}
                                className={classes.importButton}
                                onClick={() => setActiveDialog('import')}
                            >
                                <FormattedMessage id="action.import" defaultMessage="Import" />
                            </Button>
                        </Tooltip>
                        <ActionDispatcher
                            action={activeDialog}
                            onClose={() => setActiveDialog(undefined)}
                            mapsId={[]}
                            fromEditor
                        />

                        <div className={classes.rightButtonGroup}>
                            <LanguageMenu />
                            <HelpMenu />
                            <AccountMenu />
                        </div>
                    </Toolbar>
                </AppBar>
                <Drawer
                    variant="permanent"
                    className={clsx(classes.drawer, {
                        [classes.drawerOpen]: open,
                    })}
                    classes={{
                        paper: clsx({
                            [classes.drawerOpen]: open,
                        }),
                    }}
                >
                    <div style={{ padding: '20px 0 20px 15px' }} key="logo">
                        <img src={logoIcon} alt="logo" />
                    </div>

                    <List component="nav">
                        {filterButtons.map((buttonInfo) => {
                            return (
                                <StyleListItem
                                    icon={buttonInfo.icon}
                                    label={buttonInfo.label}
                                    filter={buttonInfo.filter}
                                    active={filter}
                                    onClick={handleMenuClick}
                                    onDelete={setLabelToDelete}
                                    key={`${buttonInfo.filter.type}:${buttonInfo.label}`}
                                />
                            );
                        })}
                    </List>

                    <div
                        style={{ position: 'absolute', bottom: '10px', left: '20px' }}
                        key="power-by"
                    >
                        <Link href="http://www.wisemapping.org/">
                            <img src={poweredByIcon} alt="Powered By WiseMapping" />
                        </Link>
                    </div>
                </Drawer>
                <main className={classes.content}>
                    <div className={classes.toolbar} />
                    <MapsList filter={filter} />
                </main>
            </div>
            {labelToDelete && <LabelDeleteConfirm
                onClose={() => setLabelToDelete(null)}
                onConfirm={() => {
                    handleLabelDelete(labelToDelete);
                    setLabelToDelete(null);
                }}
                label={labels.find(l => l.id === labelToDelete)}
            />}
        </IntlProvider>
    );
};

interface ListItemProps {
    icon: React.ReactElement;
    label: string;
    filter: Filter;
    active?: Filter;
    onClick: (filter: Filter) => void;
    onDelete?: (id: number) => void;
}

// https://stackoverflow.com/questions/61486061/how-to-set-selected-and-hover-color-of-listitem-in-mui
const CustomListItem = withStyles({
    root: {
        "&$selected": {
            backgroundColor: "rgb(210, 140, 5)",
            color: "white",
            "& .MuiListItemIcon-root": {
                color: "white"
            }
        },
        "&$selected:hover": {
            backgroundColor: "rgb(210, 140, 5)",
            color: "white",
            "& .MuiListItemIcon-root": {
                color: "white"
            }
        },
    },
    selected: {}
})(ListItemButton);

const StyleListItem = (props: ListItemProps) => {
    const icon = props.icon;
    const label = props.label;
    const filter = props.filter;
    const activeFilter = props.active;
    const onClick = props.onClick;
    const onDeleteLabel = props.onDelete;
    const isSelected =
        activeFilter &&
        activeFilter.type == filter.type &&
        (activeFilter.type != 'label' ||
            (activeFilter as LabelFilter).label == (filter as LabelFilter).label);
    const handleOnClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, filter: Filter) => {
        event.stopPropagation();
        onClick(filter);
    };

    const handleOnDelete = (
        event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
        filter: Filter
    ) => {
        event.stopPropagation();
        if (!onDeleteLabel) {
            throw 'Illegal state exeption';
        }
        onDeleteLabel((filter as LabelFilter).label.id);
    };

    return (
        <CustomListItem selected={isSelected} onClick={(e) => handleOnClick(e, filter)}>
            <ListItemIcon>{icon}</ListItemIcon>
            <ListItemText style={{ color: 'white' }} primary={label} />
            {filter.type == 'label' && (
                <ListItemSecondaryAction>
                    <IconButton
                        edge="end"
                        aria-label="delete"
                        onClick={(e) => handleOnDelete(e, filter)}
                        size="large">
                        <DeleteOutlineTwoTone color="secondary" />
                    </IconButton>
                </ListItemSecondaryAction>
            )}
        </CustomListItem>
    );
};

export default MapsPage;
