
import React, { useState, useEffect, useRef } from 'react';
import { Settings, RefreshCw, Hexagon, FileText, Binary, Hash } from 'lucide-react';
import { MEMORY_SIZE } from '../types';

interface MemoryViewerProps {
    memoryView: React.MutableRefObject<DataView>;
}

type ViewMode = 'float' | 'int16' | 'int32' | 'byte' | 'hex' | 'ascii';

export const MemoryViewer: React.FC<MemoryViewerProps> = ({ memoryView }) => {
    const [viewMode, setViewMode] = useState<ViewMode>('float');
    const [startAddr, setStartAddr] = useState(0);
    const [rows, setRows] = useState(20);
    const [, setTick] = useState(0); // For forcing re-render

    // Auto-refresh memory view
    useEffect(() => {
        const interval = setInterval(() => {
            setTick(t => t + 1);
        }, 100); // 10Hz refresh
        return () => clearInterval(interval);
    }, []);

    const getStride = () => {
        switch (viewMode) {
            case 'float': return 4;
            case 'int32': return 4;
            case 'int16': return 2;
            default: return 1;
        }
    };

    const getCols = () => {
        switch (viewMode) {
            case 'float':
            case 'int32': return 4; // 4 items per row
            case 'int16': return 8; // 8 items per row
            default: return 16; // 16 bytes per row
        }
    };

    const stride = getStride();
    const cols = getCols();
    const rowSize = stride * cols;
    const totalRows = Math.ceil(MEMORY_SIZE / rowSize);

    // Pagination / Scroll Helper
    const onScroll = (e: React.UIEvent<HTMLDivElement>) => {
        const top = e.currentTarget.scrollTop;
        const rowHeight = 24; // approx
        const startRow = Math.floor(top / rowHeight);
        // Optimization: Just render what's needed? 
        // For now, let's keep it simple: render from startAddr relative to scroll if virtual, 
        // or just use a fixed window if we don't assume full scroll height.
        // Let's implement full scroll height logic:
        // Actually simplicity first: User can jump addresses.
    };

    const renderCell = (addr: number) => {
        if (addr >= MEMORY_SIZE) return <span className="text-gray-800">-</span>;
        try {
            const view = memoryView.current;
            let val: string | number = '';
            let color = 'text-gray-400';

            switch (viewMode) {
                case 'float':
                    val = view.getFloat32(addr, true).toFixed(4);
                    if (parseFloat(val) !== 0) color = 'text-blue-400 font-bold';
                    break;
                case 'int32':
                    val = view.getInt32(addr, true);
                    if (val !== 0) color = 'text-green-400 font-bold';
                    break;
                case 'int16':
                    val = view.getInt16(addr, true);
                    if (val !== 0) color = 'text-green-400 font-bold';
                    break;
                case 'byte':
                    val = view.getUint8(addr);
                    if (val !== 0) color = 'text-yellow-400 font-bold';
                    break;
                case 'hex':
                    val = view.getUint8(addr).toString(16).toUpperCase().padStart(2, '0');
                    if (val !== '00') color = 'text-purple-400 font-bold';
                    break;
                case 'ascii':
                    const charCode = view.getUint8(addr);
                    // Printable ASCII 32-126
                    val = (charCode >= 32 && charCode <= 126) ? String.fromCharCode(charCode) : '.';
                    if (val !== '.') color = 'text-orange-400 font-bold';
                    else color = 'text-gray-700';
                    break;
            }
            return <span className={`font-mono text-xs ${color}`}>{val}</span>;
        } catch (e) {
            return <span className="text-red-900">ERR</span>;
        }
    };

    // Generate rows
    const visibleRows = [];
    // For scrolling, let's just make a really tall div and stick the viewport?
    // Or just a simple Pager for now to ensure performance?
    // "Layout | Logic | Memory" - full screen.
    // Let's do a virtualized-like list but fixed to logical startAddr for manual navigation?
    // Or just render all 10000 bytes? 
    // 10000 / 16 = 625 rows. Not too bad for React.
    // Let's render all rows (clamped to sensible limit if needed, but 600 rows is fine if simple)

    // Actually, let's render *only* visible based on scrollTop if we can, or just render all for simplicity if performant.
    // 600 rows of 16 cols = 9600 elements. Might be heavy on 10Hz re-render.
    // Let's render a "Window" window around `startAddr`.

    const displayRows = 50; // Show 50 rows at a time (enough for screen)

    return (
        <div className="flex-1 bg-gray-950 flex flex-col overflow-hidden text-gray-300">
            {/* Toolbar */}
            <div className="h-12 border-b border-gray-800 flex items-center px-4 justify-between shrink-0 bg-gray-900">
                <div className="flex items-center gap-4">
                    <div className="flex items-center gap-1 text-gray-500 font-bold text-xs">
                        <Settings size={14} /> <span>Data View:</span>
                    </div>
                    <div className="flex bg-gray-950 rounded p-1">
                        <button onClick={() => setViewMode('hex')} className={`px-3 py-1 text-xs rounded ${viewMode === 'hex' ? 'bg-purple-600 text-white' : 'text-gray-500 hover:text-white'}`}>HEX</button>
                        <button onClick={() => setViewMode('byte')} className={`px-3 py-1 text-xs rounded ${viewMode === 'byte' ? 'bg-yellow-600 text-white' : 'text-gray-500 hover:text-white'}`}>Byte</button>
                        <button onClick={() => setViewMode('int16')} className={`px-3 py-1 text-xs rounded ${viewMode === 'int16' ? 'bg-green-600 text-white' : 'text-gray-500 hover:text-white'}`}>Int16</button>
                        <button onClick={() => setViewMode('int32')} className={`px-3 py-1 text-xs rounded ${viewMode === 'int32' ? 'bg-green-700 text-white' : 'text-gray-500 hover:text-white'}`}>Int32</button>
                        <button onClick={() => setViewMode('float')} className={`px-3 py-1 text-xs rounded ${viewMode === 'float' ? 'bg-blue-600 text-white' : 'text-gray-500 hover:text-white'}`}>Float</button>
                        <button onClick={() => setViewMode('ascii')} className={`px-3 py-1 text-xs rounded ${viewMode === 'ascii' ? 'bg-orange-600 text-white' : 'text-gray-500 hover:text-white'}`}>ASCII</button>
                    </div>
                </div>

                <div className="flex items-center gap-2">
                    <span className="text-xs font-mono text-gray-500">Go To Address:</span>
                    <input
                        type="number"
                        className="bg-gray-800 border-none rounded px-2 py-1 text-xs font-mono w-24 text-white"
                        value={startAddr}
                        onChange={e => setStartAddr(Math.max(0, parseInt(e.target.value) || 0))}
                    />
                </div>
            </div>

            {/* Grid Content */}
            <div className="flex-1 overflow-auto p-4 custom-scrollbar">
                <table className="w-full border-collapse">
                    <thead>
                        <tr>
                            <th className="text-left text-xs font-mono text-gray-600 border-b border-gray-800 pb-2 w-24">Address</th>
                            {/* Headers +0, +1 ... */}
                            {Array.from({ length: cols }).map((_, i) => (
                                <th key={i} className="text-center text-xs font-mono text-gray-600 border-b border-gray-800 pb-2">
                                    +{(i * stride).toString(16).toUpperCase().padStart(2, '0')}
                                </th>
                            ))}
                            <th className="text-left text-xs font-mono text-gray-600 border-b border-gray-800 pb-2 pl-4">ASCII / Interpretation</th>
                        </tr>
                    </thead>
                    <tbody>
                        {Array.from({ length: 100 }).map((_, rIndex) => { // Render 100 rows starting from startAddr
                            const rowAddr = startAddr + (rIndex * rowSize);
                            if (rowAddr >= MEMORY_SIZE) return null;

                            const isReserved = rowAddr >= 8000;
                            return (
                                <tr key={rowAddr} className={`${isReserved ? 'bg-blue-900/10 hover:bg-blue-900/20' : 'hover:bg-gray-900/50'}`}>
                                    <td className="py-1 text-xs font-mono text-gray-500 border-r border-gray-800/50">
                                        M{rowAddr.toString().padStart(4, '0')}
                                    </td>
                                    {Array.from({ length: cols }).map((_, cIndex) => {
                                        const cellAddr = rowAddr + (cIndex * stride);
                                        return (
                                            <td key={cIndex} className="text-center border-b border-gray-800/10">
                                                {renderCell(cellAddr)}
                                            </td>
                                        );
                                    })}
                                    {/* Optional ASCII side-view for the whole row */}
                                    <td className="pl-4 text-xs font-mono text-gray-600 truncate border-b border-gray-800/10">
                                        {Array.from({ length: rowSize }).map((_, b) => {
                                            const bAddr = rowAddr + b;
                                            if (bAddr >= MEMORY_SIZE) return '';
                                            const c = memoryView.current.getUint8(bAddr);
                                            return (c >= 32 && c <= 126) ? String.fromCharCode(c) : '.';
                                        }).join('')}
                                    </td>
                                </tr>
                            );
                        })}
                        {/* Empty row to indicate reserved space start if not visible? No, pure highlighting is enough */}
                    </tbody>
                </table>
                <div className="h-12 w-full flex justify-center items-center text-gray-600 text-xs">
                    <button onClick={() => setStartAddr(Math.min(startAddr + 100 * rowSize, MEMORY_SIZE))} className="hover:text-white">Load More...</button>
                </div>
            </div>
        </div>
    );
};
