import { useMemo, useCallback, useRef, useState } from '@wordpress/element';
import { Popover, Button, Modal, SelectControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';

const generateId = () => {
    const randomStr = Math.random().toString(36).substring(2, 8);
    return `lcpDatapoint-${randomStr}`;
};

// Helper function to determine text color based on background
const getContrastColor = (hexcolor) => {
    if (!hexcolor) return 'inherit';
    const r = parseInt(hexcolor.slice(1, 3), 16);
    const g = parseInt(hexcolor.slice(3, 5), 16);
    const b = parseInt(hexcolor.slice(5, 7), 16);
    const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
    return (yiq >= 128) ? 'black' : 'white';
};

const ColorCellRenderer = (props) => {
    if (!props.value) return '';
    return (
        <div 
            style={{
                backgroundColor: props.value,
                color: getContrastColor(props.value),
                width: '100%',
                height: '100%',
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                padding: '4px',
                borderRadius: '4px'
            }}
        >
            {props.value}
        </div>
    );
};


const ParentCellRenderer = (props) => {
    if (!props.data || !props.data.ID) {
        return null;
    }

    // Create options from all available rows except current
    const options = [
        { label: __('None', 'lcp-visualize'), value: '' }
    ];
    
    // Get all rows from the grid
    props.api.forEachNode(node => {
        if (node.data && 
            node.data.ID && 
            node.data.ID !== props.data.ID) {
            options.push({
                label: node.data.Label || node.data.ID,
                value: node.data.ID
            });
        }
    });

    const handleChange = (newValue) => {
        if (props.context && props.context.handleParentChange) {
            props.context.handleParentChange(props.data, newValue);
        }
    };

    return (
        <SelectControl
            value={props.data.Parent || ''}
            options={options}
            onChange={handleChange}
        />
    );
};




const ColumnHeaderComponent = (props) => {
    const [isModalOpen, setIsModalOpen] = useState(false);
    const [headerName, setHeaderName] = useState(props.displayName);
    
    const dataTypeOptions = [
        { label: __('Text', 'lcp'), value: 'lcpText' },
        { label: __('Number', 'lcp'), value: 'lcpNumber' },
        { label: __('Color', 'lcp'), value: 'lcpColor' },
        { label: __('Date/Time', 'lcp'), value: 'lcpDate' }
    ];

    const handleTypeChange = (newType) => {
        props.setColumnType(props.column.colId, newType);
    };

    const handleHeaderChange = (newHeader) => {
        if (props.onHeaderChange && newHeader !== props.displayName) {
            props.onHeaderChange(props.column.colId, newHeader);
        }
    };

    const handleSave = () => {
        handleHeaderChange(headerName);
        setIsModalOpen(false);
    };

    const handleCancel = () => {
        setHeaderName(props.displayName);
        setIsModalOpen(false);
    };

    return (
        <div style={{ display: 'flex', alignItems: 'center', gap: '8px', height: '100%' }}>
            <span>{props.displayName}</span>
            <Button
                isSmall
                variant="tertiary"
                onClick={() => setIsModalOpen(true)}
                icon={
                    <svg 
                        width="16" 
                        height="16" 
                        viewBox="0 0 24 24" 
                        xmlns="http://www.w3.org/2000/svg" 
                        style={{ fill: 'currentColor' }}
                    >
                        <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" />
                    </svg>
                }
            />
            {isModalOpen && (
                <Modal
                    title={__('Column Settings', 'lcp')}
                    onRequestClose={handleCancel}
                    style={{ width: '400px' }}
                >
                    <div style={{ padding: '20px' }}>
                        <div style={{ marginBottom: '20px' }}>
                            <label style={{ display: 'block', marginBottom: '8px' }}>
                                {__('Column Header', 'lcp')}
                            </label>
                            <input
                                type="text"
                                value={headerName}
                                onChange={(e) => setHeaderName(e.target.value)}
                                style={{
                                    width: '100%',
                                    padding: '8px',
                                    borderRadius: '4px',
                                    border: '1px solid #757575'
                                }}
                                disabled={props.column.colId === 'ID'}
                            />
                        </div>
                        <SelectControl
                            label={__('Data Type', 'lcp')}
                            value={props.currentType || 'lcpText'}
                            options={dataTypeOptions}
                            onChange={handleTypeChange}
                            disabled={props.column.colId === 'ID'}
                        />
                        <div style={{ marginTop: '20px', display: 'flex', justifyContent: 'flex-end', gap: '8px' }}>
                            <Button
                                variant="secondary"
                                onClick={handleCancel}
                            >
                                {__('Cancel', 'lcp')}
                            </Button>
                            <Button
                                variant="primary"
                                onClick={handleSave}
                            >
                                {__('Save', 'lcp-visualize')}
                            </Button>
                        </div>
                    </div>
                </Modal>
            )}
        </div>
    );
};

const LCPDataGrid = ({ 
    chartData = [], 
    onDataChange,
    columnTypes,
    onColumnTypeChange,
    attributes,
    setAttributes 
}) => {
    const gridRef = useRef();
    const [contextMenu, setContextMenu] = useState(null);

    // Helper function to guess column type based on value
    const guessColumnType = useCallback((value) => {
        if (typeof value === 'number') return 'lcpNumber';
        if (typeof value === 'string') {
            if (/^#([0-9A-F]{3}){1,2}$/i.test(value)) return 'lcpColor';
            if (!isNaN(Date.parse(value))) return 'lcpDate';
        }
        return 'lcpText';
    }, []);

    // Handle parent change
    const handleParentChange = useCallback((data, newParent) => {
        const newData = chartData.map(item => 
            item.ID === data.ID ? { ...item, Parent: newParent } : item
        );
        onDataChange(newData);
    }, [chartData, onDataChange]);

    // Use columnTypes from attributes if available, otherwise use direct columnTypes prop
    const effectiveColumnTypes = attributes?.columnTypes || columnTypes || {};

    // Convert any old column types to new format
    const migratedColumnTypes = useMemo(() => {
        const typeMap = {
            'textColumn': 'lcpText',
            'numericColumn': 'lcpNumber',
            'colorColumn': 'lcpColor',
            'dateColumn': 'lcpDate'
        };

        return Object.entries(effectiveColumnTypes).reduce((acc, [key, value]) => {
            acc[key] = typeMap[value] || value;
            return acc;
        }, {});
    }, [effectiveColumnTypes]);
    
    const handleColumnTypeChange = useCallback((colId, newType) => {
        if (setAttributes) {
            setAttributes({
                columnTypes: {
                    ...migratedColumnTypes,
                    [colId]: newType
                }
            });
        } else if (onColumnTypeChange) {
            onColumnTypeChange(colId, newType);
        }
    }, [migratedColumnTypes, setAttributes, onColumnTypeChange]);

    // Define column type configurations
    const gridColumnTypes = useMemo(() => ({
        lcpNumber: {
            filter: 'agNumberColumnFilter',
            filterParams: {
                buttons: ['apply', 'reset'],
                closeOnApply: true
            },
            valueParser: params => {
                if (!params.newValue) return '';
                const parsed = parseFloat(params.newValue);
                return isNaN(parsed) ? '' : parsed;
            }
        },
        lcpText: {
            filter: 'agTextColumnFilter',
            filterParams: {
                buttons: ['apply', 'reset'],
                closeOnApply: true
            }
        },
        lcpColor: {
            filter: 'agTextColumnFilter',
            filterParams: {
                buttons: ['apply', 'reset'],
                closeOnApply: true
            },
            cellRenderer: ColorCellRenderer,
            valueParser: params => {
                if (!params.newValue) return '';
                return /^#([0-9A-F]{3}){1,2}$/i.test(params.newValue) ? 
                    params.newValue.toUpperCase() : '';
            }
        },
        lcpDate: {
            filter: 'agDateColumnFilter',
            filterParams: {
                buttons: ['apply', 'reset'],
                closeOnApply: true
            },
            valueParser: params => {
                if (!params.newValue) return '';
                const date = new Date(params.newValue);
                return isNaN(date.getTime()) ? '' : date.toISOString();
            }
        }
    }), []);

    const handleHeaderChange = useCallback((oldHeader, newHeader) => {
        if (oldHeader === newHeader || !chartData.length) return;

        // Update the chartData with the new header
        const newData = chartData.map(row => {
            const { [oldHeader]: value, ...rest } = row;
            return {
                ...rest,
                [newHeader]: value
            };
        });

        onDataChange(newData);
    }, [chartData, onDataChange]);

    // Generate column definitions based on chartData
    const columnDefs = useMemo(() => {
        if (!chartData.length) return [];

        // Get all unique keys from the data
        const allKeys = Array.from(new Set(
            chartData.flatMap(item => Object.keys(item))
        )).filter(key => key !== 'Parent'); // Remove Parent from regular columns

        // Create column definitions for regular columns
        const regularColumns = allKeys.map(key => {
            const sampleValue = chartData.find(item => item[key] !== undefined)?.[key];
            const defaultType = guessColumnType(sampleValue);
            const currentType = migratedColumnTypes[key] || defaultType;

            return {
                field: key,
                headerName: key,
                hide: key === 'ID',
                headerComponent: ColumnHeaderComponent,
                headerComponentParams: {
                    displayName: key,
                    onHeaderChange: handleHeaderChange,
                    setColumnType: handleColumnTypeChange,
                    currentType: currentType
                },
                type: currentType,
                editable: key !== 'ID',
                sortable: true,
                filter: true
            };
        });

        // Add Parent column with ParentCellRenderer
        const parentColumn = {
            field: 'Parent',
            headerName: __('Parent', 'lcp-visualize'),
            cellRenderer: ParentCellRenderer,
            cellRendererParams: {
                context: {
                    handleParentChange
                }
            },
            editable: false,
            sortable: true,
            filter: true,
            minWidth: 200
        };

        return [...regularColumns, parentColumn];
    }, [chartData, migratedColumnTypes, handleColumnTypeChange, handleHeaderChange, guessColumnType, handleParentChange]);

    const defaultColDef = useMemo(() => ({
        flex: 1,
        minWidth: 100,
        editable: true,
        sortable: true,
        filter: true,
        resizable: true
    }), []);

    const rowData = useMemo(() => {
        return chartData.map(point => ({
            ...point,
            ID: point.ID || generateId()
        }));
    }, [chartData]);

    const handleContextMenu = useCallback((event) => {
        event.preventDefault();
        const target = event.target;
        const rowCell = target.closest('.ag-cell');
        const headerCell = target.closest('.ag-header-cell');
        
        if (rowCell) {
            const rect = rowCell.getBoundingClientRect();
            const rowNode = gridRef.current.api.getRowNode(rowCell.parentElement.getAttribute('row-index'));
            if (!rowNode || !rowNode.data || !rowNode.data.ID) return;
            
            setContextMenu({
                type: 'row',
                position: {
                    top: event.clientY,
                    left: event.clientX,
                },
                rowIndex: rowNode.rowIndex,
                totalRows: gridRef.current.api.getDisplayedRowCount()
            });
        } else if (headerCell) {
            const rect = headerCell.getBoundingClientRect();
            const colId = headerCell.getAttribute('col-id');
            if (!colId) return;
            
            setContextMenu({
                type: 'column',
                position: {
                    top: event.clientY,
                    left: event.clientX,
                },
                colId: colId
            });
        }
    }, []);

    const handleRowAction = useCallback((action) => {
        const newData = [...chartData];
        const rowIndex = contextMenu.rowIndex;

        // Create empty row with all existing columns
        const emptyRow = { ID: generateId() };
        if (chartData.length > 0) {
            const columns = Array.from(new Set(
                chartData.flatMap(item => Object.keys(item))
            ));
            
            columns.forEach(col => {
                if (col === 'ID') return;
                const sampleValue = chartData.find(item => item[col] !== undefined)?.[col];
                
                switch (typeof sampleValue) {
                    case 'number':
                        emptyRow[col] = 0;
                        break;
                    case 'boolean':
                        emptyRow[col] = false;
                        break;
                    default:
                        emptyRow[col] = '';
                }
            });
        }

        switch (action) {
            case 'add-above':
                newData.splice(rowIndex, 0, emptyRow);
                break;
            case 'add-below':
                newData.splice(rowIndex + 1, 0, emptyRow);
                break;
            case 'delete':
                newData.splice(rowIndex, 1);
                break;
        }

        onDataChange(newData);
        setContextMenu(null);
    }, [chartData, onDataChange, contextMenu]);

    const handleColumnAction = useCallback((action) => {
        if (!contextMenu || !contextMenu.colId) return;
        
        const newData = [...chartData];
        const colId = contextMenu.colId;
        
        switch (action) {
            case 'delete':
                // Remove the column from all rows
                newData.forEach(row => {
                    const { [colId]: removed, ...rest } = row;
                    Object.assign(row, rest);
                });
                break;
            case 'add-left':
            case 'add-right':
                // Get all existing column names
                const existingColumns = Object.keys(chartData[0] || {});
                
                // Find the next available column number
                let nextNumber = 1;
                while (existingColumns.includes(`Column${nextNumber}`)) {
                    nextNumber++;
                }
                
                const newColId = `Column${nextNumber}`;
                const insertIndex = columnDefs.findIndex(col => col.field === colId);
                const finalIndex = action === 'add-right' ? insertIndex + 1 : insertIndex;
                
                // Add the new column to all rows
                newData.forEach(row => {
                    row[newColId] = '';
                });
                break;
        }
        
        onDataChange(newData);
        setContextMenu(null);
    }, [chartData, onDataChange, contextMenu, columnDefs]);

    const handleCellValueChanged = useCallback((params) => {
        if (!params.data || !params.data.ID) return;
        
        const newData = chartData.map(item => 
            item.ID === params.data.ID ? params.data : item
        );
        
        onDataChange(newData);
    }, [chartData, onDataChange]);

   

    return (
        <div 
            className="ag-theme-alpine" 
            style={{ height: '400px', width: '100%' }}
            onContextMenu={handleContextMenu}
        >

            <AgGridReact
                ref={gridRef}
                rowData={rowData}
                columnDefs={columnDefs}
                defaultColDef={defaultColDef}
                columnTypes={gridColumnTypes}
                onCellValueChanged={handleCellValueChanged}
                suppressRowClickSelection={true}
                rowSelection="multiple"
                animateRows={true}
                context={{
                    handleParentChange
                }}
            />
            {contextMenu && (
                <Popover
                    position="bottom left"
                    onClose={() => setContextMenu(null)}
                    anchorRect={{
                        top: contextMenu.position.top,
                        left: contextMenu.position.left,
                        width: 0,
                        height: 0,
                    }}
                >
                    <div style={{ padding: '8px', display: 'flex', flexDirection: 'column', gap: '4px' }}>
                        {contextMenu.type === 'row' && (
                            <>
                                <Button
                                    variant="secondary"
                                    onClick={() => handleRowAction('add-above')}
                                >
                                    {__('Add Row Above', 'lcp-visualize')}
                                </Button>
                                <Button
                                    variant="secondary"
                                    onClick={() => handleRowAction('add-below')}
                                >
                                    {__('Add Row Below', 'lcp-visualize')}
                                </Button>
                                <Button
                                    variant="secondary"
                                    onClick={() => handleRowAction('delete')}
                                >
                                    {__('Delete Row', 'lcp-visualize')}
                                </Button>
                            </>
                        )}
                        {contextMenu.type === 'column' && (
                            <>
                                <Button
                                    variant="secondary"
                                    onClick={() => handleColumnAction('add-left')}
                                >
                                    {__('Add Column Left', 'lcp-visualize')}
                                </Button>
                                <Button
                                    variant="secondary"
                                    onClick={() => handleColumnAction('add-right')}
                                >
                                    {__('Add Column Right', 'lcp-visualize')}
                                </Button>
                                <Button
                                    variant="secondary"
                                    onClick={() => handleColumnAction('delete')}
                                >
                                    {__('Delete Column', 'lcp-visualize')}
                                </Button>
                            </>
                        )}
                    </div>
                </Popover>
            )}
        </div>
    );
};

export default LCPDataGrid;