import React from 'react';
import {
    SvgIcon,
    Button,
    Menu,
    Divider,
    ListItemIcon,
    MenuItem
} from '@mui/material';
import {
    DataColumnFix,
    DataSortType
} from '../types/column.type';
import { DataTableHeadCell } from './head.cell';
import { DataColumnExtra, TableContext, TableMessages } from '../types/table.type';
import { DataTableFilters } from './filters';
import { ExternalFilter, FiltersStore } from '../types/filter.type';
import {
    FilterPopover,
    TableHeader,
    TableHeaderFixedCell,
    TableHeadFixedContent,
    TableHeadRow
} from './style';
import { NoData, QueryRequest } from '../../services';
import { Data } from './filter.data';
import { IconColor } from '../types/style.types';

const cache = {
    timer: NoData as NodeJS.Timeout
}

interface DataColumn extends DataColumnExtra {
    sticky?: number,
}

export interface DataTableHeadProps {
    tableRef: any,
    context: TableContext,
    messages: TableMessages,
    onRestore: () => void,
    onFiltersChange: (query: QueryRequest) => void
    children?: React.ReactNode | React.ReactNode[] | any
}

export const DataTableHead: React.FC<DataTableHeadProps> = ({ tableRef, context, messages, onRestore, onFiltersChange }) => {
    const headRef = React.useRef<any>();
    const [updated, setUpdated] = React.useState(false);
    const [filtersOpen, setFiltersOpen] = React.useState(false);
    const [forceUpdate, setForceUpdate] = React.useState(false);
    const [menuAnchor, setMenuAnchor] = React.useState<null | HTMLElement>(null);

    context.forceUpdateHead = () => {
        setForceUpdate(!forceUpdate);
    }
    const handleHeadersResize = React.useCallback(() => {
        clearTimeout(cache.timer);

        cache.timer = setTimeout(() => {
            context.forceUpdateHead();
        }, 200)
    }, []);
    React.useEffect(() => {
        window.addEventListener("resize", handleHeadersResize);

        return () => {
            window.removeEventListener("resize", handleHeadersResize, true);
        };
    })
    React.useEffect(() => {
        sortColumns(context.columns);
        setUpdated(false);
    }, [context.columns])


    const sortColumns = (columns: DataColumn[]) => {
        const contextColumns = [...columns];
        columns.splice(0, columns.length);

        if (contextColumns) {
            let left = 0;
            let right = 0;

            for (let c = 0; c < contextColumns.length; c++) {
                const column = contextColumns[c];

                switch (column.fix) {
                    case 'left':
                        {
                            columns.splice(left, 0, column);
                            left++
                        }
                        break;
                    case 'right':
                        {
                            columns.push(column);
                            right++
                        }
                        break;
                    default:
                        {
                            columns.splice(columns.length - right, 0, column);
                        }
                        break;
                }
            }
            if (headRef && headRef.current) {
                const children = headRef.current['children'] as any[];

                if (children) {
                    if ((columns.length + 2) !== children.length) {
                        if (!updated) {
                            setTimeout(() => setUpdated(true))
                        }
                    }
                    else {
                        let left = 0;

                        for (let c = 1; c < children.length - 1 && columns[c - 1].fix === 'left'; c++) {
                            const child = children[c];
                            const column = columns[c - 1];

                            if (!column.hidden) {
                                column.sticky = left;
                                left += child.clientWidth;
                            }
                        }
                        let right = 0;

                        for (let c = children.length - 2; c >= 1 && columns[c - 1].fix === 'right'; c--) {
                            const child = children[c];
                            const column = columns[c - 1];

                            if (!column.hidden) {
                                column.sticky = right;
                                right += child.clientWidth;
                            }
                        }
                    }
                }
            }
        }
        context.forceUpdateHead();
        context.forceUpdateBody();
    }

    const handleFixChange = (column: DataColumn) =>
        (fix: DataColumnFix) => {
            column.fix = fix;
            sortColumns(context.columns);
        }
    const handleSortChange = (column: DataColumn) =>
        (sort: DataSortType) => {
            if (context.paginator) {
                context.paginator.currentPage = 1;
            }
            context.columns.forEach(c => {
                if (c !== column) {
                    delete c.sort;
                }
            })
            column.sort = sort;
            context.forceUpdateHead();
            onFiltersChange(Data.createQueryRequest(context));
        }
    const handleHiddenChange = (column: DataColumn) =>
        (hidden: boolean) => {
            column.hidden = hidden;
            sortColumns(context.columns);
        }
    const handleOpenMenu = (event: React.MouseEvent<HTMLButtonElement>) => {
        setMenuAnchor(event.currentTarget);
    }
    const handleCloseMenu = () => {
        setMenuAnchor(null);
    }
    const handleShow = (column: DataColumn) => {
        handleHiddenChange(column)(false);
        sortColumns(context.columns);
        setMenuAnchor(null);
    }
    const handleRestore = () => {
        if (onRestore) {
            onRestore();

            sortColumns(context.columns);
        }
        setMenuAnchor(null);
    }
    const handleFiltersChange = (filters: FiltersStore) => {
        context.filters = filters;
        context.forceUpdateHead();
    }
    const handleExternalFilterChange = (filter: ExternalFilter) => {
        context.externalFilter = filter;
        context.forceUpdateHead();
    }
    const handleApplyFilters = () => {
        if (context.paginator) {
            context.paginator.currentPage = 1;
        }
        onFiltersChange(Data.createQueryRequest(context));
        setFiltersOpen(false);
    }
    const handleFiltersClose = () => {
        setFiltersOpen(false);
    }
    const hiddenColumns = context.columns.filter(c => !!c.hidden)

    return (
        <TableHeader>
            <TableHeadRow ref={headRef}>
                <TableHeaderFixedCell style={{ left: 0 }} >
                    <TableHeadFixedContent>
                        <Button
                            style={{ padding: '2px', minWidth: '36px', maxWidth: '36px', minHeight: '36px', maxHeight: '36px' }}
                            onClick={handleOpenMenu}>

                            <MenuIcon />
                        </Button>
                    </TableHeadFixedContent>
                </TableHeaderFixedCell>
                {
                    context.columns.map(column => (
                        !column.hidden &&
                        <DataTableHeadCell
                            key={column.name}
                            column={column}
                            messages={messages.headers}
                            hideSort={!!context.modifications && Object.keys(context.modifications).length > 0}
                            onFixChange={handleFixChange(column)}
                            onSortChange={handleSortChange(column)}
                            onHiddenChange={handleHiddenChange(column)}>
                        </DataTableHeadCell>
                    ))
                }
                <TableHeaderFixedCell style={{ right: 0 }}>
                    <TableHeadFixedContent>
                        {
                            (context.externalFilter || (context.filters && Object.keys(context.filters).length > 0)) &&
                            <FilterPopover arrow
                                open={filtersOpen}
                                content={
                                    <DataTableFilters
                                        messages={messages.filters}
                                        columns={context.columns}
                                        filters={context.filters}
                                        external={context.externalFilter}
                                        onChange={handleFiltersChange}
                                        onExternalChange={handleExternalFilterChange}
                                        onApply={handleApplyFilters}
                                        onClose={handleFiltersClose} />
                                }
                                placement="left"
                                onClose={handleFiltersClose}>

                                <Button
                                    style={{ padding: '2px', minWidth: '36px', maxWidth: '36px', minHeight: '36px', maxHeight: '36px' }}
                                    disabled={!!context.modifications && Object.keys(context.modifications).length > 0}
                                    onClick={() => setFiltersOpen(!filtersOpen)}>

                                    <SearchIcon color={!!context.modifications && Object.keys(context.modifications).length > 0 ? 'disabled' : 'primary'} />
                                </Button>
                            </FilterPopover>
                        }
                    </TableHeadFixedContent>
                </TableHeaderFixedCell>
            </TableHeadRow>
            <Menu
                anchorEl={menuAnchor}
                anchorOrigin={{
                    vertical: 'bottom',
                    horizontal: 'left',
                }}
                transformOrigin={{
                    vertical: 'top',
                    horizontal: 'left',
                }}
                keepMounted
                open={Boolean(menuAnchor)}
                onClose={handleCloseMenu}>
                {
                    hiddenColumns && hiddenColumns.map(column => (
                        <MenuItem onClick={() => handleShow(column)} key={column.name}>
                            <ListItemIcon>
                                <ShowIcon />
                            </ListItemIcon>
                            {
                                column.label
                            }
                        </MenuItem>
                    ))
                }
                {
                    hiddenColumns && hiddenColumns.length > 0 &&
                    <Divider />
                }
                <MenuItem onClick={handleRestore}>
                    <ListItemIcon>
                        <RestoreIcon />
                    </ListItemIcon>
                    {messages.headers.restore}
                </MenuItem>
            </Menu>
        </TableHeader>
    )
}

const MenuIcon = () => (
    <SvgIcon color="primary" width="24" height="24" overflow="hidden" viewBox="0 0 24 24">
        <g>
            <path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />
        </g>
    </SvgIcon>
)
const ShowIcon = () => (
    <SvgIcon fontSize="small" width="24" height="24" overflow="hidden" viewBox="0 0 24 24">
        <g>
            <path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z" />
        </g>
    </SvgIcon>
)
const RestoreIcon = () => (
    <SvgIcon fontSize="small" width="24" height="24" overflow="hidden" viewBox="0 0 24 24">
        <g>
            <path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z" />
        </g>
    </SvgIcon>
)
const SearchIcon = ({ color }: { color: IconColor }) => (
    <SvgIcon color={color} fontSize="small" width="24" height="24" overflow="hidden" viewBox="0 0 24 24">
        <g>
            <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" />
        </g>
    </SvgIcon>
)