import React from 'react';
import { Checkbox, TableBody } from '@mui/material';
import { DataColumnExtra, TableContext, TableMessages } from '../types/table.type';
import {
    TableBodyFixedCell,
    TableBodyFixedContent,
    TableBodyRow,
    TableBodyRowHeight,
    TableBodySummaryFixedCell,
    TableBodySummaryFixedContent,
    TableBodySummaryRow
} from './style';
import { DataTableBodyCell } from './body.cell';
import { guid } from 'sync-ql';
import { DataRow } from '../types/body.type';
import { DataTableBodySummary } from './body.summary';

interface DataColumn extends DataColumnExtra {
    sticky?: number,
}

export interface DataTableBodyProps {
    tableRef: any,
    context: TableContext,
    messages: TableMessages,
    selectable: boolean,
    virtualization?: { from: number, to: number },
    onDataChange: (column: DataColumn, row: DataRow, value: any) => void
}

export const DataTableBody: React.FC<DataTableBodyProps> = ({ tableRef, context, messages, selectable, virtualization, onDataChange }) => {
    const bodyRef = React.useRef<any>();
    const [forceUpdate, setForceUpdate] = React.useState(false);
    const [selectedRow, setSelectedRow] = React.useState('');

    context.forceUpdateBody = () => {
        setForceUpdate(!forceUpdate);
    }
    const getStyle = (column: DataColumn) => {
        const result: React.CSSProperties = {};

        if (column) {
            if (column.width) {
                result.width = column.width;
            }
            if (column.minWidth) {
                result.minWidth = column.minWidth;
            }
            if (column.maxWidth) {
                result.maxWidth = column.maxWidth;
            }
            if (column.fix === 'left') {
                result.left = column.sticky
                    ? column.sticky + 40
                    : 40;
                result.zIndex = 1000;
                result.position = 'sticky';
                result.backgroundImage = 'linear-gradient(rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.05))';
            }
            if (column.fix === 'right') {
                result.right = column.sticky
                    ? column.sticky + 40
                    : 40;
                result.zIndex = 1000;
                result.position = 'sticky';
                result.backgroundImage = 'linear-gradient(rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.05))';
            }
        }
        return result;
    }
    const getCellStyle = (column: DataColumn) => {
        if (column) {
            const result = getStyle(column);

            if (column.cell && column.cell.style) {
                Object.keys(column.cell.style).forEach((k: any) => {
                    (result as any)[k] = (column as any).cell.style[k]
                })
            }
            return result;
        }
        return {} as React.CSSProperties;
    }
    const getSummaryStyle = (column: DataColumn) => {
        if (column) {
            const result = getCellStyle(column);

            if (column.summary && column.summary.style) {
                Object.keys(column.summary.style).forEach(k => {
                    (result as any)[k] = (column as any).summary.style[k]
                })
            }
            return result;
        }
        return {} as React.CSSProperties;
    }
    const getCellAlign = (column: DataColumn) => {
        return column.cell && column.cell.align
            ? column.cell.align
            : column.align;
    }
    const getSummaryAlign = (column: DataColumn) => {
        return column.summary && column.summary.align
            ? column.summary.align
            : getCellAlign(column);
    }
    const handleChange = (column: DataColumn, row: DataRow) =>
        (value: any) => {
            onDataChange(column, row, value)
        }
    const handleEditting = (column: DataColumn, row: DataRow) =>
        (value: boolean) => {
            if (row) {
                (context as any).editting.row = value ? row['<key>'] : '';
                (context as any).editting.column = value ? column.name : '';

                context.forceUpdateBody();
            }
        }
    const handleSelectionChange = (row: DataRow) =>
        (event: React.ChangeEvent<HTMLInputElement>) => {
            const value = event.target.checked;

            if (value) {
                context.selection = { [(row as any)['<key>']]: row }
                context.forceUpdateToolbar();
                setSelectedRow((row as any)['<key>']);
            }
            else {
                context.selection = {}
                context.forceUpdateToolbar();
                setSelectedRow('')
            }
        }
    const getVirtualization = () => {
        const pageSize = !!virtualization
            ? 1000
            : context.paginator.pageSize;
        const currentPage = context.paginator.currentPage;

        if (context.data && context.data.rows && pageSize > 0) {
            const startLimit = Math.min(
                context.data.rows.length,
                (currentPage - 1) * pageSize
            );
            const endLimit = Math.min(
                context.data.rows.length,
                (currentPage) * pageSize
            );
            const start = Math.min(
                context.data.rows.length,
                virtualization
                    ? virtualization.from + startLimit
                    : startLimit
            );
            const end = Math.min(
                context.data.rows.length,
                virtualization
                    ? Math.min(virtualization.to + startLimit, endLimit)
                    : endLimit
            );
            const top = !!virtualization && start > startLimit
                ? Math.max(0, TableBodyRowHeight * (start - startLimit))
                : 0;
            const bottom = !!virtualization && end < endLimit
                ? TableBodyRowHeight * (endLimit - end)
                : 0;
            const height = tableRef && tableRef.current
                ? tableRef.current.clientHeight - TableBodyRowHeight - (context.hasSummary ? TableBodyRowHeight : 0)
                : 0
            return {
                top,
                start,
                end,
                bottom: Math.max(bottom, height - (top + (end - start) * TableBodyRowHeight + bottom)),
                spacer: tableRef && tableRef.current
            }

        }
        return null;
    }
    const getCell = (row: DataRow, column: DataColumnExtra, index: number) => {
        const value = row[column.name];
        const modification = context.modifications[(row as any)['<key>']];
        const modified = modification &&
            modification.original && modification.changed &&
            modification.original[column.name] !== modification.changed[column.name];
        const editting = row['<key>'] === context.editting.row && column.name === context.editting.column;

        return (
            !column.hidden &&
            <DataTableBodyCell
                key={column.name}
                tableRef={tableRef}
                align={getCellAlign(column)}
                style={getCellStyle(column)}
                row={row}
                column={column}
                index={index}
                editting={editting}
                modified={modified}
                messages={messages}
                value={
                    column.cell && typeof column.cell.factory === 'function'
                        ? column.cell.factory
                        : value
                }
                options={column.set as any}
                onChange={handleChange(column, row)}
                onEditting={handleEditting(column, row)} />
        )
    }
    const getRows = () => {
        const result: React.ReactNode[] = [];
        const virtualization = getVirtualization();

        if (!!virtualization) {
            result.push(
                <TableBodyRow tabIndex={-1} key="T">
                    {
                        !!virtualization && virtualization.top > 0 &&
                        <td>
                            <div style={{ height: `${virtualization.top}px` }} />
                        </td>
                    }
                </TableBodyRow>
            )
            for (let i = virtualization.start; i < virtualization.end; i++) {
                const index = i - virtualization.start + 1;
                const row = i < context.data.rows.length && context.data.rows[i]
                    ? !context.data.rows[i]['<key>']
                        ? context.data.rows[i] = {
                            ...context.data.rows[i],
                            ['<key>']: guid()
                        }
                        : context.data.rows[i]
                    : null;

                result.push(
                    <TableBodyRow tabIndex={-1} key={row ? row['<key>'] : `row-${index}`} ref={bodyRef}>
                        <TableBodyFixedCell style={{ left: 0 }} >
                            <TableBodyFixedContent>
                                {
                                    !!selectable &&
                                    <Checkbox
                                        style={{ padding: '4px', margin: '2px 0px' }}
                                        checked={row && selectedRow === row['<key>']}
                                        onChange={row ? handleSelectionChange(row) : () => { }}
                                    />
                                }
                            </TableBodyFixedContent>
                        </TableBodyFixedCell>
                        {
                            row &&
                            context.columns.map((column) => getCell(row, column, i))
                        }
                        <TableBodyFixedCell style={{ right: 0 }} >
                            <TableBodyFixedContent />
                        </TableBodyFixedCell>
                    </TableBodyRow>
                )
            }
            result.push(
                <TableBodyRow tabIndex={-1} key="B">
                    {
                        !!virtualization && virtualization.bottom > 0 &&
                        <td>
                            <div style={{ height: `${virtualization.bottom}px` }} />
                        </td>
                    }
                </TableBodyRow>
            )
        }
        return result;
    }

    return (
        <TableBody>
            {getRows()}
            {
                context.hasSummary && context.data && context.data.rows && context.data.rows.length > 0 &&
                <TableBodySummaryRow>
                    <TableBodySummaryFixedCell style={{ left: 0 }} >
                        <TableBodySummaryFixedContent />
                    </TableBodySummaryFixedCell>
                    {
                        context.columns.map((column) => (
                            !column.hidden &&
                            <DataTableBodySummary
                                key={column.name}
                                align={getSummaryAlign(column)}
                                style={getSummaryStyle(column)}
                                context={context}
                                column={column} />
                        ))
                    }
                    <TableBodySummaryFixedCell style={{ right: 0 }} >
                        <TableBodySummaryFixedContent />
                    </TableBodySummaryFixedCell>
                </TableBodySummaryRow>
            }

        </TableBody>
    )
}