import 'dart:async';
import 'dart:collection';
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';
import 'dart:isolate';
import 'package:file_picker/file_picker.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'widgets/scrollview.dart' as custom;

ThemeProvider _themeProvider = ThemeProvider();

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await _themeProvider.loadTheme();
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider<ThemeProvider>.value(value: _themeProvider),
      ],
      child: BinaryViewerApp(),
    ),
  );
}


enum ThemesEnum {
  Light_Default(colorScheme: ColorSchemes.lightDefaultColor),
  Dark_Default(colorScheme: ColorSchemes.darkDefaultColor),
  Light_Blue(colorScheme: ColorSchemes.lightBlue),
  Dark_Blue(colorScheme: ColorSchemes.darkBlue),
  Light_Green(colorScheme: ColorSchemes.lightGreen),
  Dark_Green(colorScheme: ColorSchemes.darkGreen),
  Light_Orange(colorScheme: ColorSchemes.lightOrange),
  Dark_Orange(colorScheme: ColorSchemes.darkOrange),
  Light_Violet(colorScheme: ColorSchemes.lightViolet),
  Dark_Violet(colorScheme: ColorSchemes.darkViolet),
  Light_Rose(colorScheme: ColorSchemes.lightRose),
  Dark_Rose(colorScheme: ColorSchemes.darkRose);

  final ColorScheme colorScheme;
  const ThemesEnum({required this.colorScheme});


}
class ThemeProvider extends ChangeNotifier {

  ThemesEnum _currentTheme = ThemesEnum.Light_Rose;

  ThemesEnum get currentTheme => _currentTheme;

  Future<void> loadTheme() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String? themeStr = prefs.getString('theme');
    if (themeStr != null) {
      _currentTheme = ThemesEnum.values.firstWhere((theme) => theme.name == themeStr, orElse: () => ThemesEnum.Light_Rose);
    } else {
      _currentTheme = ThemesEnum.Light_Rose;
    }
    notifyListeners();
  }

  void setTheme(ThemesEnum theme) async {
    _currentTheme = theme;

    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString('theme', _currentTheme.name);

    notifyListeners();
  }

}

class BinaryViewerApp extends StatelessWidget {
  const BinaryViewerApp({super.key});

  @override
  Widget build(BuildContext context) {
    return Consumer<ThemeProvider>(
      builder: (context, themeProvider, child) {
        print("Current theme: ${themeProvider.currentTheme.name}");
        return ShadcnApp(
          title: 'Binary Viewer',
          theme: ThemeData(
            colorScheme: themeProvider.currentTheme.colorScheme,
            radius: 0.5,
          ),
          home: BinaryViewerScreen(),
        );
      },
    );
  }
}

class BinaryViewerScreen extends StatefulWidget {
  @override
  State<BinaryViewerScreen> createState() => _BinaryViewerScreenState();
}

enum ViewMode {
  hex,
  ascii,
  binary,
  integer,
  float,
  double,
}
enum ViewEndian {
  little,
  big,
}

class _BinaryViewerScreenState extends State<BinaryViewerScreen> {
  RandomAccessFile? _file;
  int _fileLength = 0;

  Isolate? _readerIsolate;
  SendPort? _readerSendPort;
  ReceivePort? _mainReceivePort;
  int _isolateId = 0;
  final Map<int, Completer<Uint8List>> _pendingReads = {};
  final Queue<int> _readQueue = Queue<int>();
  Timer? _throttleTimer;
  Timer? _debounceTimer;
  static const int maxReadsPerSecond = 40;

  ViewEndian _leftEndian = ViewEndian.little;
  ViewMode _leftMode = ViewMode.hex;
  ViewEndian _rightEndian = ViewEndian.little;
  ViewMode _rightMode = ViewMode.ascii;

  final ScrollController _scrollController = ScrollController();
  final ScrollController _horizontalScrollController = ScrollController();
  int _firstVisibleRow = 0;
  int _lastVisibleRow = 0;
  static const int bufferRows = 10;

  final Map<int, Uint8List> _rowCache = {};

  @override
  void dispose() {
    _debounceTimer?.cancel();
    _readerIsolate?.kill(priority: Isolate.immediate);
    _mainReceivePort?.close();
    _throttleTimer?.cancel();
    _scrollController.dispose();
    _horizontalScrollController.dispose();
    super.dispose();
  }

  void _updateVisibleRows() {
    if (_scrollController.hasClients) {
      double offset = _scrollController.offset;
      double rowHeight = 35; // Updated row height based on user info
      int first = (offset / rowHeight).floor();
      int last = ((offset + _scrollController.position.viewportDimension) / rowHeight).ceil();
      int newFirst = max(0, first - bufferRows);
      int newLast = min((_fileLength / 16).ceil() - 1, last + bufferRows);
      if (newFirst != _firstVisibleRow || newLast != _lastVisibleRow) {
        _debounceTimer?.cancel();
        _debounceTimer = Timer(const Duration(milliseconds: 50), () {
          print('setState: _firstVisibleRow=$newFirst, _lastVisibleRow=$newLast');
          setState(() {
            _firstVisibleRow = newFirst;
            _lastVisibleRow = newLast;
          });
          // Evict cache rows far outside the buffer
          final minKeep = max(0, newFirst - bufferRows * 2);
          final maxKeep = min((_fileLength / 16).ceil() - 1, newLast + bufferRows * 2);
          _rowCache.removeWhere((offset, _) {
            int row = offset ~/ 16;
            return row < minKeep || row > maxKeep;
          });
        });
      }
    }
  }

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(_updateVisibleRows);
  }

  Future<void> _openFile(String path) async {
    RandomAccessFile file = await File(path).open();
    int length = await File(path).length();
    await _file?.close();
    _readerIsolate?.kill(priority: Isolate.immediate);
    _mainReceivePort?.close();
    _mainReceivePort = ReceivePort();
    _isolateId++;
    final isolateId = _isolateId;
    _readerIsolate = await Isolate.spawn(_fileReaderIsolate, {
      'sendPort': _mainReceivePort!.sendPort,
      'path': path,
      'isolateId': isolateId,
    });
    _mainReceivePort!.listen((msg) {
      if (msg is SendPort) {
        _readerSendPort = msg;
      } else if (msg is Map && msg['isolateId'] == _isolateId) {
        int offset = msg['offset'];
        Uint8List bytes = msg['bytes'];
        final completer = _pendingReads.remove(offset);
        if (completer != null && !completer.isCompleted) {
          completer.complete(bytes);
        }
      }
    });
    _throttleTimer?.cancel();
    _throttleTimer = Timer.periodic(Duration(milliseconds: 1000 ~/ maxReadsPerSecond), (_) {
      if (_readQueue.isNotEmpty && _readerSendPort != null) {
        int offset = _readQueue.removeFirst();
        final completer = _pendingReads[offset];
        if (completer != null && !completer.isCompleted) {
          int bytesToRead = min(16, _fileLength - offset);
          if (bytesToRead > 0) {
            _readerSendPort!.send({
              'offset': offset,
              'length': bytesToRead,
              'isolateId': _isolateId,
            });
          } else {
            completer.complete(Uint8List(0));
            _pendingReads.remove(offset);
          }
        }
      }
    });
    setState(() {
      _file = file;
      _fileLength = length;
    });
    // Ensure initial visible rows are calculated and loaded
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _updateVisibleRows();
    });
  }

  static void _fileReaderIsolate(Map args) async {
    final mainSendPort = args['sendPort'] as SendPort;
    final path = args['path'] as String;
    final isolateId = args['isolateId'] as int;
    final file = await File(path).open();
    final port = ReceivePort();
    mainSendPort.send(port.sendPort);
    await for (final msg in port) {
      if (msg is Map && msg['isolateId'] == isolateId) {
        int offset = msg['offset'];
        int length = msg['length'];
        file.setPositionSync(offset);
        Uint8List bytes = file.readSync(length);
        mainSendPort.send({
          'offset': offset,
          'bytes': bytes,
          'isolateId': isolateId,
        });
      }
    }
  }

  Future<Uint8List> _readBytes(int offset) async {
    if (_file == null) return Uint8List(0);
    if (_pendingReads.containsKey(offset)) {
      return _pendingReads[offset]!.future;
    }
    final completer = Completer<Uint8List>();
    _pendingReads[offset] = completer;
    _readQueue.add(offset);
    return completer.future;
  }

  int selectedAddress = -1;
  void _onAddressClicked(int address, int byteIndex) {
    int absoluteAddress = address + byteIndex;
    print('Address clicked: 0x${absoluteAddress.toRadixString(16).padLeft(8, '0').toUpperCase()}');
    // TODO: Add your address click handling logic here
    setState(() {
      selectedAddress = absoluteAddress;
    });
  }

  double _calculateViewModeWidth(ViewMode mode) {
    double width;
    switch (mode) {
      case ViewMode.hex:
        width = 16 * 32;
        break;
      case ViewMode.ascii:
        width = 16 * 24;
        break;
      case ViewMode.binary:
        width = 16 * 75;
        break;
      case ViewMode.integer:
        width = 4 * 96;
        break;
      case ViewMode.float:
        width = 4 * 190;
        break;
      case ViewMode.double:
        width = 2 * 190;
        break;
    }

    // Account for padding
    width += 20;

    return max(width, 330);
  }

  @override
  Widget build(BuildContext context) {

    double leftWidth = _calculateViewModeWidth(_leftMode);
    double rightWidth = _calculateViewModeWidth(_rightMode);


    return Scaffold(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [

          Row(
            children: [
              Menubar(
                children: [
                  MenuButton(
                    subMenu: [
                      MenuButton(
                        child: const Text("Open"),
                        onPressed: (context) async {
                          FilePickerResult? result = await FilePicker.platform.pickFiles(
                            initialDirectory: _file != null ? File(_file!.path).parent.path : null,
                          );
                          if (result != null && result.files.isNotEmpty) {
                            String path = result.files.first.path!;
                            await _openFile(path);
                          }
                        },
                      )
                    ],
                    child: const Text("File"),
                  ),
                  MenuButton(
                    subMenu: [
                      MenuButton(
                        subMenu: [
                          for (var theme in ThemesEnum.values)
                            MenuButton(
                              leading: Container(
                                width: 16,
                                height: 16,
                                decoration: BoxDecoration(
                                  color: theme.colorScheme.primary,
                                  borderRadius: BorderRadius.circular(4),
                                  border: Border.all(
                                    color: theme.colorScheme.primaryForeground,
                                    width: 1,
                                  ),
                                ),
                              ),
                              child: Text(theme.name.replaceAll('_', ' ')),
                              onPressed: (context) {
                                _themeProvider.setTheme(theme);
                              },
                            )
                        ],
                        child: const Text("Theme"),
                      ),
                    ],
                    child: const Text("Options"),
                  )
                ],
              ).withMargin(
                horizontal: 10
              ),

              Builder(
                builder: (context) {

                  if (_file == null) {
                    return Breadcrumb(
                      children: [
                        const Text("No file opened"),
                      ],
                    );
                  }

                  List<String> parts = _file?.path.split(Platform.pathSeparator) ?? [];

                  String fileName = parts.last;
                  String parentDir = parts.length > 1 ? parts[parts.length - 2] : "";

                  return Breadcrumb(
                    children: [
                      const MoreDots(),
                      Text(parentDir),
                      Text(fileName),
                    ],
                  );
                }
              )
            ],
          ),

          const SizedBox(height: 6),

          Expanded(
            child: OutlinedContainer(
              child: LayoutBuilder(
                builder: (context, constraints) {
                  return custom.RawScrollbar(
                    controller: _scrollController,
                    thumbVisibility: true,
                    trackVisibility: true,
                    notificationPredicate: (notification) => notification.depth == 1,
                    scrollbarMargin: EdgeInsets.only(left: 2, top: 2, right: 1),
                    renderOffset: Offset(0, 56),
                    radius: Radius.circular(10),
                    thumbColor: _themeProvider._currentTheme.colorScheme.primaryForeground,
                    thickness: 8,
                    trackBorderColor: _themeProvider._currentTheme.colorScheme.border,
                    trackColor: _themeProvider._currentTheme.colorScheme.background,
                    child: custom.RawScrollbar(
                      controller: _horizontalScrollController,
                      thumbColor: _themeProvider._currentTheme.colorScheme.primaryForeground,
                      thickness: 8,
                      trackBorderColor: _themeProvider._currentTheme.colorScheme.border,
                      trackColor: _themeProvider._currentTheme.colorScheme.background,
                      trackVisibility: true,
                      thumbVisibility: true,
                      interactive: true,
                      forceInteractive: true,
                      radius: Radius.circular(10),
                      scrollbarMargin: EdgeInsets.only(left: 2, top: 3, bottom: 2, right: 11),

                      child: SingleChildScrollView(
                        controller: _horizontalScrollController,
                        scrollDirection: Axis.horizontal,
                        physics: const ClampingScrollPhysics(),
                        child: SizedBox(
                          width: max(100 + leftWidth + rightWidth + 60, constraints.maxWidth),
                          height: constraints.maxHeight,
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              IntrinsicHeight(
                                child: Row(
                                  children: [
                                    SizedBox(
                                      width: 100,
                                      child: Center(
                                        child: Text(
                                          "Address",
                                        ).withMargin(
                                            all: 10
                                        ),
                                      ),
                                    ),
                                    VerticalDivider(),
                                    SizedBox(
                                      width: leftWidth,
                                      child: Row(
                                        children: [
                                          const SizedBox(width: 10),
                                          SizedBox(
                                            width: 200,
                                            child: Select<String>(
                                              itemBuilder: (context, item) {
                                                return Text(
                                                  item,
                                                );
                                              },
                                              value: _leftMode.name,
                                              onChanged: (value) {
                                                setState(() {
                                                  _leftMode = ViewMode.values.firstWhere((mode) => mode.name == value);
                                                });
                                              },
                                              popup: SelectPopup(
                                                  items: SelectItemList(
                                                      children: [
                                                        for (var mode in ViewMode.values)
                                                          SelectItemButton(
                                                            value: mode.name,
                                                            child: Text(mode.name),
                                                          )
                                                      ]
                                                  )
                                              ),
                                            ).withMargin(
                                                vertical: 10
                                            ),
                                          ),
                                          const SizedBox(width: 10),
                                          SizedBox(
                                            width: 100,
                                            child: Select<String>(
                                              itemBuilder: (context, item) {
                                                return Text(
                                                  item,
                                                );
                                              },
                                              value: _leftEndian.name,
                                              onChanged: (value) {
                                                setState(() {
                                                  _leftEndian = ViewEndian.values.firstWhere((mode) => mode.name == value);
                                                });
                                              },
                                              popup: SelectPopup(
                                                  items: SelectItemList(
                                                      children: [
                                                        for (var mode in ViewEndian.values)
                                                          SelectItemButton(
                                                            value: mode.name,
                                                            child: Text(mode.name),
                                                          )
                                                      ]
                                                  )
                                              ),
                                            ).withMargin(
                                                vertical: 10
                                            ),
                                          ),
                                          const SizedBox(width: 10),
                                        ],
                                      ),
                                    ),
                                    VerticalDivider(),
                                    SizedBox(
                                      width: rightWidth,
                                      child: Row(
                                        children: [
                                          const SizedBox(width: 10),
                                          SizedBox(
                                            width: 200,
                                            child: Select<String>(
                                              itemBuilder: (context, item) {
                                                return Text(
                                                  item,
                                                );
                                              },
                                              value: _rightMode.name,
                                              onChanged: (value) {
                                                setState(() {
                                                  _rightMode = ViewMode.values.firstWhere((mode) => mode.name == value);
                                                });
                                              },
                                              popup: SelectPopup(
                                                  items: SelectItemList(
                                                      children: [
                                                        for (var mode in ViewMode.values)
                                                          SelectItemButton(
                                                            value: mode.name,
                                                            child: Text(mode.name),
                                                          )
                                                      ]
                                                  )
                                              ),
                                            ).withMargin(
                                                vertical: 10
                                            ),
                                          ),
                                          const SizedBox(width: 10),
                                          SizedBox(
                                            width: 100,
                                            child: Select<String>(
                                              itemBuilder: (context, item) {
                                                return Text(
                                                  item,
                                                );
                                              },
                                              value: _rightEndian.name,
                                              onChanged: (value) {
                                                setState(() {
                                                  _rightEndian = ViewEndian.values.firstWhere((mode) => mode.name == value);
                                                });
                                              },
                                              popup: SelectPopup(
                                                  items: SelectItemList(
                                                      children: [
                                                        for (var mode in ViewEndian.values)
                                                          SelectItemButton(
                                                            value: mode.name,
                                                            child: Text(mode.name),
                                                          )
                                                      ]
                                                  )
                                              ),
                                            ).withMargin(
                                                vertical: 10
                                            ),
                                          ),
                                        ],
                                      ),
                                    ),
                                  ],
                                ),
                              ),
                              Divider(),
                              if (_file != null)
                                Expanded(
                                  child: ScrollConfiguration(
                                    behavior: ScrollConfiguration.of(context).copyWith(
                                      scrollbars: false,
                                      overscroll: false,
                                    ),
                                    child: SizedBox(
                                      width: double.infinity,
                                      child: NotificationListener<ScrollNotification>(
                                        onNotification: (scrollInfo) {
                                          _updateVisibleRows();
                                          return false;
                                        },
                                        child: SizedBox(
                                          width: max(100 + leftWidth + rightWidth + 60, MediaQuery.of(context).size.width - 20),
                                          child: ListView.builder(
                                            controller: _scrollController,
                                            itemCount: (_fileLength / 16).ceil() + 1,
                                            itemExtent: 35.0, // Match the actual row height
                                            cacheExtent: 2000.0, // Increase cache for smoother scrolling
                                            addAutomaticKeepAlives: false, // Reduce memory usage
                                            addRepaintBoundaries: true, // Improve repaint performance

                                            itemBuilder: (context, i) {
                                              String address = (i * 16).toRadixString(16).padLeft(8, '0').toUpperCase();
                                              address = "0x$address";

                                              if (i == (_fileLength / 16).ceil()) {
                                                return SizedBox(
                                                  height: 35,
                                                  child: Column(
                                                    children: [
                                                      Divider(),
                                                      Expanded(
                                                        child: Center(
                                                          child: Center(child: Text('End of File', style: TextStyle(fontSize: 14)).h4),
                                                        ),
                                                      ),
                                                      const SizedBox(height: 12),
                                                    ],
                                                  ),
                                                );
                                              }

                                              if (i < _firstVisibleRow || i > _lastVisibleRow) {
                                                return IntrinsicHeight(
                                                  child: Row(
                                                    children: [
                                                      SizedBox(
                                                        width: 100,
                                                        child: Center(
                                                          child: Text(
                                                            address,
                                                            style: TextStyle(fontSize: 12),
                                                          ).muted,
                                                        ),
                                                      ).withMargin(vertical: 10),
                                                      VerticalDivider(),
                                                      AspectRatio(
                                                          aspectRatio: 1,
                                                          child: CircularProgressIndicator().withMargin(all: 10)
                                                      )
                                                    ],
                                                  ),
                                                );
                                              }

                                              if (_rowCache.containsKey(i * 16)) {
                                                // Row data is cached, build directly
                                                Uint8List bytes = _rowCache[i * 16]!;
                                                String address = (i * 16).toRadixString(16).padLeft(8, '0').toUpperCase();
                                                address = "0x$address";
                                                return IntrinsicHeight(
                                                  child: Row(
                                                    children: [
                                                      SizedBox(
                                                        width: 100,
                                                        child: Center(
                                                          child: Text(
                                                            address,
                                                            style: TextStyle(fontSize: 12),
                                                          ).muted,
                                                        ),
                                                      ).withMargin(vertical: 10),
                                                      VerticalDivider(),
                                                      SizedBox(
                                                        width: leftWidth - 20,
                                                        child: Row(
                                                          children: [
                                                            ...getView(context, _leftMode, _leftEndian, bytes, i * 16, _onAddressClicked, selectedAddress),
                                                          ],
                                                        ),
                                                      ).withMargin(horizontal: 10),
                                                      VerticalDivider(),
                                                      SizedBox(
                                                        width: rightWidth - 20,
                                                        child: Row(
                                                          children: [
                                                            ...getView(context, _rightMode, _rightEndian, bytes, i * 16, _onAddressClicked, selectedAddress),
                                                          ],
                                                        ),
                                                      ).withMargin(horizontal: 10),
                                                    ],
                                                  ),
                                                );
                                              }

                                              // Not cached, use FutureBuilder
                                              return FutureBuilder<Uint8List>(
                                                future: _readBytes(i * 16),
                                                builder: (context, snapshot) {
                                                  if (snapshot.connectionState == ConnectionState.waiting) {
                                                    return IntrinsicHeight(
                                                      child: Row(
                                                        children: [
                                                          SizedBox(
                                                            width: 100,
                                                            child: Center(
                                                              child: Text(
                                                                address,
                                                                style: TextStyle(fontSize: 12),
                                                              ).muted,
                                                            ),
                                                          ).withMargin(vertical: 10),
                                                          VerticalDivider(),
                                                          AspectRatio(
                                                              aspectRatio: 1,
                                                              child: CircularProgressIndicator().withMargin(all: 10)
                                                          )
                                                        ],
                                                      ),
                                                    );
                                                  }
                                                  if (snapshot.hasError) {
                                                    print('Error loading bytes for offset ${i * 16}: ${snapshot.error}');
                                                    return Padding(
                                                      padding: const EdgeInsets.symmetric(vertical: 10),
                                                      child: Center(child: Text('Error loading data', style: TextStyle(color: Colors.red))),
                                                    );
                                                  }
                                                  Uint8List bytes = snapshot.data ?? Uint8List(0);
                                                  // Cache the loaded data
                                                  _rowCache[i * 16] = bytes;

                                                  return IntrinsicHeight(
                                                    child: Row(
                                                      children: [
                                                        SizedBox(
                                                          width: 100,
                                                          child: Center(
                                                            child: Text(
                                                              address,
                                                              style: TextStyle(fontSize: 12),
                                                            ).muted,
                                                          ),
                                                        ).withMargin(vertical: 10),
                                                        VerticalDivider(),
                                                        SizedBox(
                                                          width: leftWidth - 20,
                                                          child: Row(
                                                            children: [
                                                              ...getView(context, _leftMode, _leftEndian, bytes, i * 16, _onAddressClicked, selectedAddress),
                                                            ],
                                                          ),
                                                        ).withMargin(horizontal: 10),
                                                        VerticalDivider(),
                                                        SizedBox(
                                                          width: rightWidth - 20,
                                                          child: Row(
                                                            children: [
                                                              ...getView(context, _rightMode, _rightEndian, bytes, i * 16, _onAddressClicked, selectedAddress),
                                                            ],
                                                          ),
                                                        ).withMargin(horizontal: 10),
                                                      ],
                                                    ),
                                                  );
                                                },
                                              );
                                            },
                                          ),
                                        ),
                                      ),
                                    ),
                                  ),
                                ),
                            ],
                          ),
                        ),
                      ),
                    ),
                  );
                },
              ),
            ).withMargin(
              horizontal: 10
            ),
          ),

        ],
      ).withMargin(
        vertical: 10
      ),
    );
  }

}

Widget _createViewButton(String text, int byteOffset, int baseAddress, Function(int, int) onAddressClick, int selectedAddress, {double? width, bool isBold = false, AlignmentGeometry? alignment}) {
  int currentAddress = baseAddress + byteOffset;
  bool isSelected = currentAddress == selectedAddress;

  Widget button;

  if (isSelected) {
    button = SizedBox(
      child: OutlinedContainer(
        padding: EdgeInsets.symmetric(horizontal: 7),
        borderRadius: BorderRadius.circular(8),
        height: 31,
        boxShadow: [
          BoxShadow(
            color: _themeProvider.currentTheme.colorScheme.primary.withOpacity(0.5),
            blurRadius: 4,
            spreadRadius: 2,
          ),
        ],
        child: Align(
          alignment: alignment ?? Alignment.centerLeft,
          child: Text(
            text,
            style: TextStyle(
              fontSize: 12,
              fontWeight: isBold ? FontWeight.bold : null,
            ),
          ).mono,
        ),
      ),
    );
  } else {
    button = GhostButton(
      onPressed: () => onAddressClick(baseAddress, byteOffset),
      density: ButtonDensity.icon,
      alignment: alignment ?? Alignment.centerLeft,
      child: Text(
        text,
        style: TextStyle(
          fontSize: 12,
          fontWeight: isBold ? FontWeight.bold : null,
        ),
      ).mono,
    );
  }


  
  return width != null ? SizedBox(width: width, child: button) : button;
}

List<Widget> getView(BuildContext context, ViewMode mode, ViewEndian endian, Uint8List bytes, int baseAddress, Function(int, int) onAddressClick, int selectedAddress) {
  List<Widget> leftWidgets = [];
  
  if (mode == ViewMode.hex) {
    for (int i = 0; i < bytes.length; i++) {
      String byteStr = bytes[i].toRadixString(16).padLeft(2, '0').toUpperCase();
      leftWidgets.add(_createViewButton( byteStr, i, baseAddress, onAddressClick, selectedAddress, width: 32, isBold: true));
    }
  } else if (mode == ViewMode.ascii) {
    for (int i = 0; i < bytes.length; i++) {
      String char = bytes[i] >= 32 && bytes[i] <= 126 ? String.fromCharCode(bytes[i]) : '.';
      leftWidgets.add(_createViewButton( char, i, baseAddress, onAddressClick, selectedAddress, width: 24));
    }
  } else if (mode == ViewMode.binary) {
    for (int i = 0; i < bytes.length; i++) {
      String byteStr = bytes[i].toRadixString(2).padLeft(8, '0');
      leftWidgets.add(_createViewButton( byteStr, i, baseAddress, onAddressClick, selectedAddress));
    }
  } else if (mode == ViewMode.integer) {
    ByteData byteData = ByteData.sublistView(bytes);
    int maxIntegers = bytes.length ~/ 4;
    for (int j = 0; j < 4 && j < maxIntegers; j++) {
      if (j * 4 + 4 <= bytes.length) {
        int value = byteData.getInt32(j * 4, endian == ViewEndian.little ? Endian.little : Endian.big);
        String valueStr = value.toString().padLeft(11, ' ');
        leftWidgets.add(_createViewButton( valueStr, j * 4, baseAddress, onAddressClick, selectedAddress, alignment: Alignment.centerLeft));
      }
    }
  } else if (mode == ViewMode.float) {
    ByteData byteData = ByteData.sublistView(bytes);
    int maxFloats = bytes.length ~/ 4;
    for (int j = 0; j < 4 && j < maxFloats; j++) {
      if (j * 4 + 4 <= bytes.length) {
        double value = byteData.getFloat32(j * 4, endian == ViewEndian.little ? Endian.little : Endian.big);
        String valueStr = value.toStringAsFixed(2);
        leftWidgets.add(_createViewButton( valueStr, j * 4, baseAddress, onAddressClick, selectedAddress, width: 190, alignment: Alignment.centerLeft));
      }
    }
  } else if (mode == ViewMode.double) {
    ByteData byteData = ByteData.sublistView(bytes);
    int maxDoubles = bytes.length ~/ 8;
    for (int j = 0; j < 2 && j < maxDoubles; j++) {
      if (j * 8 + 8 <= bytes.length) {
        double value = byteData.getFloat64(j * 8, endian == ViewEndian.little ? Endian.little : Endian.big);
        String valueStr = value.toStringAsFixed(2);
        leftWidgets.add(_createViewButton(valueStr, j * 8, baseAddress, onAddressClick, selectedAddress, width: 190, alignment: Alignment.centerLeft));
      }
    }
  }
  return leftWidgets;
}