tostore 3.5.1 copy "tostore: ^3.5.1" to clipboard
tostore: ^3.5.1 copied to clipboard

Fast distributed AI vector database and persistent local storage engine. High-performance key-value store supporting SQL, NoSQL, offline cache and encrypted data.

example/lib/main.dart

import 'dart:async';
import 'dart:convert';
import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:tostore/tostore.dart';

import 'testing/benchmark_dialog.dart';
import 'testing/benchmark_models.dart';
import 'testing/benchmark_runner.dart';
import 'testing/database_tester.dart';
import 'testing/example_schemas.dart';
import 'testing/log_service.dart';
import 'tostore_example.dart' show ForeignKeyMode, ToStoreExample;

String _dbResultErrorMessage(DbResult result) {
  final errors = result.statuses
      .where((s) => s.type != ResultType.success)
      .map((s) => s.message);
  return errors.isEmpty ? 'Operation failed' : errors.join('; ');
}

/// Simple UI to run examples
void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // It's crucial to set the log handler *before* any potential errors can occur.
  // This ensures that initialization logs are captured and displayed in the UI.
  ToStore.setLogConfig(
    logLevel: LogLevel.debug,
    onLog: (LogRecord log) {
      final message = log.message;
      final type = log.level;

      // Filter out expected test-induced calculation fallback logs
      if (message.contains('Division by zero in expression')) {
        return;
      }

      logService.add(message, type, true);
    },
  );

  final example = ToStoreExample();

  // The example app will now run even if initialization fails,
  // allowing the user to see the error logs in the ListView.
  runApp(MyApp(example: example));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key, required this.example});
  final ToStoreExample example;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'ToStore Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF006CC3),
          primary: const Color(0xFF006CC3),
          surface: Colors.white,
          surfaceTint: Colors.transparent,
        ),
        useMaterial3: true,
        scaffoldBackgroundColor: Colors.white,
        popupMenuTheme: PopupMenuThemeData(
          color: Colors.white,
          surfaceTintColor: Colors.transparent,
          elevation: 6,
          shadowColor: Colors.black.withAlpha(25),
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(12),
            side: const BorderSide(color: Color(0xFFE2E8F0), width: 1),
          ),
        ),
        dialogTheme: DialogThemeData(
          backgroundColor: Colors.white,
          surfaceTintColor: Colors.transparent,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(16),
          ),
        ),
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: ToStoreExamplePage(example: example),
    );
  }
}

enum AppView { dataView, tests }

enum PaginationMode { offset, cursor }

class ToStoreExamplePage extends StatefulWidget {
  const ToStoreExamplePage({super.key, required this.example});
  final ToStoreExample example;
  @override
  State<ToStoreExamplePage> createState() => _ToStoreExamplePageState();
}

class _ToStoreExamplePageState extends State<ToStoreExamplePage> {
  static const bool _isWasmBuild =
      bool.fromEnvironment('FLUTTER_WEB_USE_SKWASM');

  /// Shared content column width for app bar, body, and log panel content.
  static const double _kContentMaxWidth = 1200.0;

  final TextEditingController _searchController = TextEditingController();
  late final PageController _pageViewController;

  LogLevel? _selectedLogLevel;
  String _lastOperationInfo = 'Please initialize the database first.';
  bool _isDbInitialized = false;
  bool _isInitializing = true;
  bool _isTesting = false; // Add state to track if a test is running
  bool _isAtBottom = true; // Assume we start at the bottom

  BenchmarkSummary? _lastBenchmarkSummary;
  BenchmarkConfig _benchmarkConfig = const BenchmarkConfig();

  AppView _selectedView = AppView.dataView;

  // State for spaces
  final List<String> _spaceNames = ['default', 'space1', 'space2'];
  String _selectedSpace = 'default';

  // State for Data View
  final List<String> _tableNames = [
    ExampleSchemas.users.name,
    ExampleSchemas.posts.name,
    ExampleSchemas.comments.name,
    ExampleSchemas.embeddings.name,
    ExampleSchemas.settings.name,
    _kKvSpaceLabel,
    _kKvGlobalLabel,
  ];
  String _selectedTable = ExampleSchemas.users.name;
  bool _hasVectorSupport = false;

  bool get _isKvMode =>
      _selectedTable == _kKvSpaceLabel || _selectedTable == _kKvGlobalLabel;
  bool get _isKvGlobal => _selectedTable == _kKvGlobalLabel;
  List<Map<String, dynamic>> _tableData = [];
  List<String> _tableColumns = [];
  int _currentPage = 1;
  final int _pageSize = 20;
  int _totalRecords = 0;
  int _totalPages = 0;
  bool _isDataLoading = false;
  bool _isCountCalculating = false;
  int _fetchSequence = 0;
  bool _isCountLimited =
      false; // Indicates if count might be limited by defaultQueryLimit
  String? _primaryKey;
  final Set<dynamic> _selectedRows = {};

  // Pagination state
  PaginationMode _paginationMode = PaginationMode.cursor;
  String? _nextCursor;
  String? _prevCursor;

  final TextEditingController _pageInputController = TextEditingController();
  final DraggableScrollableController _logPanelController =
      DraggableScrollableController();

  // The scroll controller provided by the DraggableScrollableSheet builder.
  // We need to hold a reference to it to manage listeners correctly.
  ScrollController? _sheetScrollController;
  bool _logCanScrollUp = false;
  bool _logCanScrollDown = false;

  // New state for sorting
  String? _sortColumn;
  bool _sortAscending = true;

  // New state for active filters
  List<Map<String, dynamic>> _activeFilters = [];

  /// Collapsed log handle height — watch strip matches this so the main list
  /// stays usable while a single-row live watch is open.
  static const double _kBottomChromeHeight = 60;

  /// Live single-record watch (query().watch on PK). Survives switchSpace.
  String? _watchTable;
  String? _watchPkField;
  dynamic _watchPkValue;
  Map<String, dynamic>? _watchRow;
  bool _watchMissing = false;
  int _watchPulse = 0;
  StreamSubscription<List<Map<String, dynamic>>>? _watchSub;

  bool get _hasRecordWatch => _watchTable != null && _watchPkValue != null;

  @override
  void initState() {
    super.initState();
    _pageViewController = PageController(initialPage: _selectedView.index);
    _initializeDatabase();
    logService.logs.addListener(_onLogsChanged);
    _searchController.addListener(() {
      setState(() {
        // Just rebuild the widget when text changes
      });
    });
  }

  @override
  void dispose() {
    unawaited(_stopRecordWatch());
    logService.logs.removeListener(_onLogsChanged);
    _logPanelController.dispose();
    _sheetScrollController?.removeListener(_logScrollListener);
    _searchController.dispose();
    _pageViewController.dispose();
    _pageInputController.dispose();
    super.dispose();
  }

  Future<void> _fetchTableData({bool resetPage = false, String? cursor}) async {
    if (!_isDbInitialized) return;

    if (_isKvMode) {
      await _fetchKvData(resetPage: resetPage, cursor: cursor);
      return;
    }

    final int currentSeq = ++_fetchSequence;

    setState(() {
      _isDataLoading = true;
      if (resetPage) {
        _currentPage = 1;
        _selectedRows.clear();
        _sortColumn = null; // Reset sort on page reset
        _nextCursor = null;
        _prevCursor = null;
      }
    });

    try {
      // 1. Get schema to find columns and PK
      final schema = await widget.example.db.getTableSchema(_selectedTable);
      if (schema != null) {
        _tableColumns = schema.fields.map((f) => f.name).toList();
        _primaryKey = schema.primaryKeyConfig.name;
        if (!_tableColumns.contains(_primaryKey)) {
          _tableColumns.insert(0, _primaryKey!);
        }
        _hasVectorSupport =
            schema.indexes.any((idx) => idx.type == IndexType.vector);
      } else {
        _tableColumns = [];
        _primaryKey = 'key';
        _hasVectorSupport = false;
      }

      // 2. Base query for data fetching
      var dataQuery = widget.example.db.query(_selectedTable);
      for (final filter in _activeFilters) {
        final field = filter['field'] as String;
        final op = filter['operator'] as String;
        final value = filter['value'];
        if (op == 'startsWith' || op == 'prefix') {
          dataQuery = dataQuery.whereStartsWith(field, value?.toString() ?? '');
        } else {
          dataQuery = dataQuery.where(field, op, value);
        }
      }

      // 3. Base query for count calculation (matching filters)
      var countQuery = widget.example.db.query(_selectedTable);
      for (final filter in _activeFilters) {
        final field = filter['field'] as String;
        final op = filter['operator'] as String;
        final value = filter['value'];
        if (op == 'startsWith' || op == 'prefix') {
          countQuery =
              countQuery.whereStartsWith(field, value?.toString() ?? '');
        } else {
          countQuery = countQuery.where(field, op, value);
        }
      }

      // 4. Apply sorting for data fetching
      if (_sortColumn != null) {
        if (_sortAscending) {
          dataQuery = dataQuery.orderByAsc(_sortColumn!);
        } else {
          dataQuery = dataQuery.orderByDesc(_sortColumn!);
        }
      }

      final int maxOffset = widget.example.db.config.maxQueryOffset;
      late final QueryResult<Map<String, dynamic>> result;

      if (_paginationMode == PaginationMode.offset) {
        final int offset = (_currentPage - 1) * _pageSize;
        if (!mounted) return;
        if (offset > maxOffset) {
          _showOffsetLimitWarning(offset, maxOffset);
          setState(() => _isDataLoading = false);
          return;
        }

        result = await dataQuery.limit(_pageSize).offset(offset);
      } else {
        var q = dataQuery.limit(_pageSize);
        if (cursor != null) {
          q = q.cursor(cursor);
        }
        result = await q;
      }

      if (!mounted || currentSeq != _fetchSequence) return;

      setState(() {
        _tableData = result.data;
        _nextCursor = result.nextCursorToken;
        _prevCursor = result.prevCursorToken;
        if (_tableColumns.isEmpty && _tableData.isNotEmpty) {
          _tableColumns = _tableData.first.keys.toList();
        }
        _isDataLoading = false;
        _pageInputController.text = _currentPage.toString();
      });

      final filterHint = _activeFilters.isEmpty
          ? 'no filter'
          : '${_activeFilters.length} filter(s)';
      final modeHint = _paginationMode == PaginationMode.cursor
          ? 'cursor'
          : 'offset page $_currentPage';
      final elapsedMs = result.executionTimeMs;
      logService.add(
          'Query table "$_selectedTable" ($modeHint, $filterHint): '
          'fetched ${_tableData.length} records '
          'in ${elapsedMs ?? '?'}ms',
          LogLevel.info);

      // 5. Asynchronously update record count in background without blocking list rendering
      _asyncCalculateTableCount(countQuery, currentSeq);
    } catch (e, s) {
      logService.add('Error fetching table data: $e', LogLevel.error);
      logService.add('Stacktrace: $s', LogLevel.error);
      if (mounted) {
        setState(() => _isDataLoading = false);
      }
    }
  }

  Future<void> _asyncCalculateTableCount(
      QueryBuilder countQuery, int sequence) async {
    try {
      if (mounted && sequence == _fetchSequence) {
        setState(() => _isCountCalculating = true);
      }

      final count = await countQuery.count();
      if (!mounted || sequence != _fetchSequence) return;

      final defaultQueryLimit = widget.example.db.config.defaultQueryLimit;
      setState(() {
        _totalRecords = count;
        _isCountLimited =
            _activeFilters.isNotEmpty && _totalRecords == defaultQueryLimit;
        _totalPages = (_totalRecords / _pageSize).ceil();
        if (_totalPages == 0) _totalPages = 1;
        if (_currentPage > _totalPages &&
            _paginationMode == PaginationMode.offset) {
          _currentPage = _totalPages;
          _pageInputController.text = _currentPage.toString();
        }
        _isCountCalculating = false;
      });
    } catch (_) {
      if (mounted && sequence == _fetchSequence) {
        setState(() => _isCountCalculating = false);
      }
    }
  }

  /// Loads KV records via [KvStore.query] (limit/offset/cursor; not getKeys + N gets).
  Future<void> _fetchKvData({bool resetPage = false, String? cursor}) async {
    final previousNextCursor = _nextCursor;
    final previousPrevCursor = _prevCursor;
    final int currentSeq = ++_fetchSequence;

    setState(() {
      _isDataLoading = true;
      if (resetPage) {
        _currentPage = 1;
        _selectedRows.clear();
        _sortColumn = null;
        _nextCursor = null;
        _prevCursor = null;
      }
    });

    try {
      final isGlobal = _isKvGlobal;
      final kv = widget.example.db.kv;
      _tableColumns = const ['key', 'value', 'updated_at'];
      _primaryKey = 'key';
      _hasVectorSupport = false;
      _isCountLimited = false;

      String? prefix;
      for (final filter in _activeFilters) {
        if (filter['field'] == 'key' &&
            (filter['operator'] == 'startsWith' ||
                filter['operator'] == 'prefix')) {
          final v = filter['value'];
          if (v != null && v.toString().isNotEmpty) {
            prefix = v.toString();
            break;
          }
        }
      }

      var countQuery = kv.query(isGlobal: isGlobal);
      if (prefix != null) {
        countQuery = countQuery.prefix(prefix);
      }

      var dataQuery = kv.query(isGlobal: isGlobal);
      if (prefix != null) {
        dataQuery = dataQuery.prefix(prefix);
      }
      if (_sortColumn == 'updated_at') {
        dataQuery = _sortAscending
            ? dataQuery.orderByUpdatedAtAsc()
            : dataQuery.orderByUpdatedAtDesc();
      } else if (_sortColumn == 'key' && !_sortAscending) {
        dataQuery = dataQuery.orderByKeyDesc();
      } else {
        dataQuery = dataQuery.orderByKeyAsc();
      }
      dataQuery = dataQuery.limit(_pageSize);

      final useCursor = _paginationMode == PaginationMode.cursor &&
          cursor != null &&
          cursor.isNotEmpty &&
          !resetPage;
      if (useCursor) {
        if (cursor == previousNextCursor) {
          _currentPage++;
        } else if (cursor == previousPrevCursor && _currentPage > 1) {
          _currentPage--;
        }
        dataQuery = dataQuery.cursor(cursor);
      } else {
        if (_currentPage > _totalPages && _totalPages > 0) {
          _currentPage = _totalPages;
        }
        if (_currentPage < 1) _currentPage = 1;
        dataQuery = dataQuery.offset((_currentPage - 1) * _pageSize);
      }

      final result = await dataQuery;
      if (result.hasErrors) {
        logService.add('KV query failed: ${result.message}', LogLevel.error);
      }
      final rows = result.data.map((record) {
        return <String, dynamic>{
          'key': record['key'],
          'value': _formatKvDisplayValue(record['value']),
          'updated_at': record['updated_at'],
        };
      }).toList();

      if (!mounted || currentSeq != _fetchSequence) return;
      setState(() {
        _tableData = rows;
        if (_paginationMode == PaginationMode.cursor) {
          _nextCursor = result.nextCursorToken;
          _prevCursor = result.prevCursorToken;
        } else {
          _prevCursor = _currentPage > 1 ? 'prev' : null;
          _nextCursor = _currentPage < _totalPages ? 'next' : null;
        }
        _isDataLoading = false;
        _pageInputController.text = _currentPage.toString();
      });

      final scope = isGlobal ? 'global' : 'space';
      final prefixHint = prefix == null ? 'no prefix' : 'prefix=$prefix';
      final modeHint = useCursor ? 'cursor' : 'offset page $_currentPage';
      final elapsedMs = result.executionTimeMs;
      logService.add(
          'Query KV ($scope, $prefixHint, $modeHint): '
          'fetched ${rows.length} records '
          'in ${elapsedMs ?? '?'}ms',
          LogLevel.info);

      // Trigger asynchronous count
      _asyncCalculateKvCount(countQuery, currentSeq);
    } catch (e, s) {
      logService.add('Error fetching KV data: $e', LogLevel.error);
      logService.add('Stacktrace: $s', LogLevel.error);
      if (mounted) {
        setState(() => _isDataLoading = false);
      }
    }
  }

  Future<void> _asyncCalculateKvCount(
      KvQueryBuilder countQuery, int sequence) async {
    try {
      if (mounted && sequence == _fetchSequence) {
        setState(() => _isCountCalculating = true);
      }

      final count = await countQuery.count();
      if (!mounted || sequence != _fetchSequence) return;

      setState(() {
        _totalRecords = count;
        _totalPages = (_totalRecords / _pageSize).ceil();
        if (_totalPages == 0) _totalPages = 1;
        if (_currentPage > _totalPages &&
            _paginationMode == PaginationMode.offset) {
          _currentPage = _totalPages;
          _pageInputController.text = _currentPage.toString();
        }
        _isCountCalculating = false;
      });
    } catch (_) {
      if (mounted && sequence == _fetchSequence) {
        setState(() => _isCountCalculating = false);
      }
    }
  }

  void _showBriefSnackBar(String message) {
    if (!mounted) return;
    ScaffoldMessenger.of(context).hideCurrentSnackBar();
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(message),
        duration: const Duration(seconds: 2),
      ),
    );
  }

  void _onLogsChanged() {
    // Check if we are at the bottom *before* new logs are added.
    bool wasAtBottom = true; // Assume true if we can't check
    if (_sheetScrollController != null && _sheetScrollController!.hasClients) {
      final pos = _sheetScrollController!.position;
      wasAtBottom =
          pos.pixels >= pos.maxScrollExtent - 5.0; // Use a small tolerance
    }

    if (wasAtBottom) {
      _logScrollToBottom();
    }

    // After logs are added, the scroll extent might change, so re-evaluate button states.
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) _logScrollListener();
    });
  }

  void _logScrollListener() {
    if (_sheetScrollController == null || !_sheetScrollController!.hasClients) {
      return;
    }
    final position = _sheetScrollController!.position;

    _isAtBottom = position.pixels >= position.maxScrollExtent - 5.0;
    final atTop = position.pixels <= position.minScrollExtent;

    final canScrollUp = !atTop;
    final canScrollDown = !_isAtBottom;

    if (_logCanScrollUp != canScrollUp || _logCanScrollDown != canScrollDown) {
      if (mounted) {
        setState(() {
          _logCanScrollUp = canScrollUp;
          _logCanScrollDown = canScrollDown;
        });
      }
    }
  }

  void _logScrollToTop() {
    if (_sheetScrollController != null && _sheetScrollController!.hasClients) {
      _sheetScrollController!.animateTo(
        0,
        duration: const Duration(milliseconds: 300),
        curve: Curves.easeOut,
      );
    }
  }

  void _logScrollToBottom() {
    // Use a post-frame callback to ensure the list has been rebuilt.
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (_sheetScrollController != null &&
          _sheetScrollController!.hasClients) {
        _sheetScrollController!.animateTo(
          _sheetScrollController!.position.maxScrollExtent,
          duration: const Duration(milliseconds: 300),
          curve: Curves.easeOut,
        );
      }
    });
  }

  void _updateOperationInfo(String info) {
    if (mounted) {
      setState(() {
        _lastOperationInfo = info;
      });
    }
  }

  Future<void> _initializeDatabase() async {
    setState(() {
      _isInitializing = true;
      _lastOperationInfo = 'Initializing Database...';
    });

    // Exclude getApplicationDocumentsDirectory time from stats
    // because that's an OS/Flutter limitation, not the db engine
    final dbPath = await widget.example.getDbPath();

    final stopwatch = Stopwatch()..start();
    await widget.example.initialize(dbPath: dbPath);
    stopwatch.stop();
    if (mounted) {
      setState(() {
        _isDbInitialized = true;
        _isInitializing = false;
        _lastOperationInfo =
            'DB Initialized: ${stopwatch.elapsedMilliseconds}ms';
        _selectedSpace = widget.example.db.currentSpaceName ?? 'default';
      });
      // Fetch data if the data view is active
      if (_selectedView == AppView.dataView) {
        await _fetchTableData(resetPage: true);
      }
    }
  }

  Widget _buildActionButton({
    required String text,
    IconData? icon,
    VoidCallback? onPressed,
  }) {
    return ElevatedButton(
      onPressed: onPressed,
      style: ElevatedButton.styleFrom(
        foregroundColor: Colors.white,
        backgroundColor: const Color.fromARGB(255, 10, 150, 210),
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(10),
        ),
        elevation: 1.5,
        shadowColor: const Color.fromARGB(100, 10, 150, 210),
        padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          if (icon != null) ...[
            Icon(icon, size: 18, color: Colors.white),
            const SizedBox(width: 6),
          ],
          Text(
            text,
            textAlign: TextAlign.center,
            style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 14),
            maxLines: 1,
            overflow: TextOverflow.visible,
          ),
        ],
      ),
    );
  }

  Widget _buildFilterButton(
      String text, LogLevel? type, int count, BuildContext context) {
    if (count == 0 && type != null) {
      // Don't show the button if there are no logs of this type (except for 'All')
      return const SizedBox.shrink();
    }
    final isSelected = _selectedLogLevel == type;
    final Color backgroundColor;
    final Color foregroundColor;
    final double elevation;
    final Color? shadowColor;
    Color? countColor;

    if (isSelected) {
      backgroundColor = const Color.fromARGB(255, 10, 150, 210);
      foregroundColor = Colors.white;
      elevation = 2;
      shadowColor = const Color.fromARGB(102, 6, 126, 177);
    } else {
      backgroundColor = const Color.fromARGB(255, 227, 232, 235);
      foregroundColor = Theme.of(context).colorScheme.onSecondaryContainer;
      elevation = 0;
      shadowColor = null;

      // Set count color for non-selected buttons
      if (type == LogLevel.critical) {
        countColor = Colors.red.shade900;
      } else if (type == LogLevel.error) {
        countColor = Colors.red;
      } else if (type == LogLevel.warn) {
        countColor = Colors.orange;
      }
    }

    return ElevatedButton(
      onPressed: () {
        setState(() {
          _selectedLogLevel = type;
        });
      },
      style: ElevatedButton.styleFrom(
        backgroundColor: backgroundColor,
        foregroundColor: foregroundColor,
        elevation: elevation,
        shadowColor: shadowColor,
        padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
        minimumSize: Size.zero,
        tapTargetSize: MaterialTapTargetSize.shrinkWrap,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(12),
        ),
      ),
      child: RichText(
        text: TextSpan(
          style: TextStyle(
            color: foregroundColor,
            fontWeight: FontWeight.normal,
          ),
          children: [
            TextSpan(text: '$text ('),
            TextSpan(
              text: '$count',
              style: TextStyle(
                fontWeight: FontWeight.bold,
                color:
                    countColor, // This will be null for selected, which is fine
              ),
            ),
            const TextSpan(text: ')'),
          ],
        ),
      ),
    );
  }

  Color _getLogColor(LogLevel type) {
    switch (type) {
      case LogLevel.critical:
        return Colors.red.shade900;
      case LogLevel.error:
        return Colors.red;
      case LogLevel.warn:
        return Colors.orange;
      case LogLevel.debug:
        return Colors.blueAccent;
      case LogLevel.info:
        return Colors.black;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        backgroundColor: Colors.white,
        surfaceTintColor: Colors.transparent,
        elevation: 0,
        automaticallyImplyLeading: false,
        titleSpacing: 0,
        title: const SizedBox.shrink(),
        flexibleSpace: SafeArea(
          bottom: false,
          child: Center(
            child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: _kContentMaxWidth),
              child: SizedBox(
                width: double.infinity,
                height: kToolbarHeight,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 16),
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      Image.asset(
                        'assets/logo-tostore.png',
                        height: 36.0,
                        fit: BoxFit.contain,
                        errorBuilder: (context, error, stackTrace) {
                          return const Text(
                            'ToStore',
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              color: Color(0xFF006CC3),
                            ),
                          );
                        },
                      ),
                      const SizedBox(width: 12),
                      Container(
                        padding: const EdgeInsets.symmetric(
                            horizontal: 10, vertical: 4),
                        decoration: BoxDecoration(
                          color: Colors.white,
                          borderRadius: BorderRadius.circular(20),
                          border: Border.all(
                            color: const Color(0xFFE2E8F0),
                            width: 0.8,
                          ),
                        ),
                        child: Row(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            Container(
                              width: 6.5,
                              height: 6.5,
                              decoration: const BoxDecoration(
                                color: Color(0xFF10B981),
                                shape: BoxShape.circle,
                              ),
                            ),
                            const SizedBox(width: 5),
                            const Text(
                              'DEMO',
                              style: TextStyle(
                                fontSize: 11,
                                fontWeight: FontWeight.w700,
                                color: Color(0xFF006CC3),
                                letterSpacing: 1.2,
                              ),
                            ),
                          ],
                        ),
                      ),
                      const Spacer(),
                      _buildMoreActionsButton(),
                    ],
                  ),
                ),
              ),
            ),
          ),
        ),
        bottom: PreferredSize(
          preferredSize: const Size.fromHeight(1.0),
          child: Container(
            color: const Color(0xFFE2E8F0),
            height: 1.0,
          ),
        ),
      ),
      body: SafeArea(
        top: false,
        child: Stack(
          children: [
            // Main Content
            Center(
              child: ConstrainedBox(
                constraints: const BoxConstraints(maxWidth: _kContentMaxWidth),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: [
                    _buildViewToggle(),
                    Expanded(
                      child: _isInitializing
                          ? _buildInitializingView()
                          : PageView(
                              controller: _pageViewController,
                              onPageChanged: (index) {
                                final newView = AppView.values[index];
                                if (_selectedView != newView) {
                                  setState(() {
                                    _selectedView = newView;
                                  });
                                  // If switching to Data View, always refresh the data
                                  // to ensure it's not stale after tests.
                                  if (newView == AppView.dataView) {
                                    _fetchTableData(resetPage: true);
                                  }
                                }
                              },
                              children: [
                                _buildDataView(),
                                _buildTestsView(),
                              ],
                            ),
                    ),
                    // Reserve space for collapsed log (+ watch strip when live).
                    SizedBox(
                      height: _hasRecordWatch
                          ? _kBottomChromeHeight * 2
                          : _kBottomChromeHeight,
                    ),
                  ],
                ),
              ),
            ),
            // Draggable Log Panel
            _buildResizableLogPanel(),
            // Sit on top of the log sheet so the live strip is never covered.
            if (_hasRecordWatch) _buildRecordWatchOverlay(),
          ],
        ),
      ),
    );
  }

  /// Positions the PK watch strip just above the current log panel height.
  Widget _buildRecordWatchOverlay() {
    return ListenableBuilder(
      listenable: _logPanelController,
      builder: (context, _) {
        return LayoutBuilder(
          builder: (context, constraints) {
            final logFraction =
                _logPanelController.isAttached ? _logPanelController.size : 0.1;
            final bottom = constraints.maxHeight * logFraction;
            return Align(
              alignment: Alignment.bottomCenter,
              child: Padding(
                padding: EdgeInsets.only(bottom: bottom),
                child: ConstrainedBox(
                  constraints:
                      const BoxConstraints(maxWidth: _kContentMaxWidth),
                  child: Material(
                    elevation: 6,
                    shadowColor: Colors.black26,
                    child: _buildRecordWatchStrip(),
                  ),
                ),
              ),
            );
          },
        );
      },
    );
  }

  Widget _buildResizableLogPanel() {
    return DraggableScrollableSheet(
      controller: _logPanelController,
      initialChildSize: 0.1,
      minChildSize: 0.1,
      maxChildSize: 0.8,
      builder: (BuildContext context, ScrollController scrollController) {
        // The builder provides a new scrollController instance on each rebuild.
        // We must manage our listener accordingly.
        if (_sheetScrollController != scrollController) {
          _sheetScrollController?.removeListener(_logScrollListener);
          _sheetScrollController = scrollController;
          _sheetScrollController?.addListener(_logScrollListener);
        }

        // Outer layer keeps shadow (unclipped); ClipRRect restores top
        // rounded corners so opaque log content cannot square them off.
        const panelRadius = BorderRadius.only(
          topLeft: Radius.circular(16.0),
          topRight: Radius.circular(16.0),
        );
        return Center(
          child: ConstrainedBox(
            constraints: const BoxConstraints(maxWidth: _kContentMaxWidth),
            child: Container(
              width: double.infinity,
              decoration: BoxDecoration(
                borderRadius: panelRadius,
                boxShadow: [
                  BoxShadow(
                    blurRadius: 16.0,
                    color: Colors.black.withAlpha(20),
                    offset: const Offset(0, -4),
                  ),
                ],
              ),
              child: ClipRRect(
                borderRadius: panelRadius,
                child: Container(
                  decoration: const BoxDecoration(
                    color: Colors.white,
                    border: Border(
                      top: BorderSide(color: Color(0xFFE2E8F0), width: 1),
                    ),
                  ),
                  child: _buildLogPanel(scrollController),
                ),
              ),
            ),
          ),
        );
      },
    );
  }

  Widget _buildInitializingView() {
    return const Center(
      child: Padding(
        padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 24),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            CircularProgressIndicator(),
            SizedBox(width: 20),
            Text('Initializing...'),
          ],
        ),
      ),
    );
  }

  Widget _buildViewToggle() {
    final isDataView = _selectedView == AppView.dataView;
    return Padding(
      padding: const EdgeInsets.only(top: 16.0, bottom: 12.0),
      child: Center(
        child: Container(
          width: 252.0,
          height: 42.0,
          padding: const EdgeInsets.all(3.0),
          decoration: BoxDecoration(
            color: const Color(0xFFF8FAFC),
            borderRadius: BorderRadius.circular(21.0),
            border: Border.all(color: const Color(0xFFE2E8F0), width: 1.0),
          ),
          child: Stack(
            children: [
              // Sliding Symmetrical White Pill Card
              AnimatedAlign(
                alignment:
                    isDataView ? Alignment.centerLeft : Alignment.centerRight,
                duration: const Duration(milliseconds: 220),
                curve: Curves.easeInOutCubic,
                child: Container(
                  width: 121.0,
                  height: 34.0,
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(17.0),
                    border:
                        Border.all(color: const Color(0xFFCBD5E1), width: 0.8),
                    boxShadow: [
                      BoxShadow(
                        color: Colors.black.withAlpha(12),
                        blurRadius: 4,
                        offset: const Offset(0, 1.5),
                      ),
                    ],
                  ),
                ),
              ),

              // Interactive Text Buttons
              Row(
                children: [
                  Expanded(
                    child: GestureDetector(
                      behavior: HitTestBehavior.opaque,
                      onTap: () {
                        if (!isDataView) {
                          _pageViewController.animateToPage(
                            0,
                            duration: const Duration(milliseconds: 250),
                            curve: Curves.easeInOut,
                          );
                        }
                      },
                      child: Center(
                        child: Text(
                          'Data View',
                          style: TextStyle(
                            fontSize: 13.5,
                            fontWeight:
                                isDataView ? FontWeight.w700 : FontWeight.w600,
                            color: isDataView
                                ? const Color.fromARGB(255, 10, 150, 210)
                                : const Color(0xFF64748B),
                          ),
                        ),
                      ),
                    ),
                  ),
                  Expanded(
                    child: GestureDetector(
                      behavior: HitTestBehavior.opaque,
                      onTap: () {
                        if (isDataView) {
                          _pageViewController.animateToPage(
                            1,
                            duration: const Duration(milliseconds: 250),
                            curve: Curves.easeInOut,
                          );
                        }
                      },
                      child: Center(
                        child: Text(
                          'Tests',
                          style: TextStyle(
                            fontSize: 13.5,
                            fontWeight:
                                !isDataView ? FontWeight.w700 : FontWeight.w600,
                            color: !isDataView
                                ? const Color.fromARGB(255, 10, 150, 210)
                                : const Color(0xFF64748B),
                          ),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildDataView() {
    return Column(
      children: [
        // Header with record count and actions
        _buildDataHeader(),
        _buildActiveFiltersDisplay(),
        const Divider(height: 1),
        // Data Table
        if (_isDataLoading)
          const Expanded(child: Center(child: CircularProgressIndicator()))
        else if (_tableData.isEmpty)
          const Expanded(
            child: Center(
              child: Text('No records found.'),
            ),
          )
        else
          _buildDataTable(),
        // Pagination Controls
        _buildPaginationControls(),
        // Add padding at the bottom to avoid being obscured by the log panel
        const SizedBox(height: 20),
      ],
    );
  }

  /// Bar above the log panel: live PK watch via [QueryBuilder.watch].
  Widget _buildRecordWatchStrip() {
    final title = _watchMissing
        ? 'MISSING  $_watchTable.$_watchPkField=$_watchPkValue'
        : 'LIVE  $_watchTable.$_watchPkField=$_watchPkValue';
    final body = _watchMissing
        ? 'No row in current space (deleted or never existed here). '
            'Edits in another space with the same id will appear after switch.'
        : (_watchRow == null
            ? 'Waiting for first watch emission…'
            : _watchRow!.entries
                .map((e) => '${e.key}:${e.value ?? 'NULL'}')
                .join(' · '));

    return ColoredBox(
      color: _watchMissing ? const Color(0xFFFFF7ED) : const Color(0xFFF5F3FF),
      child: SizedBox(
        height: _kBottomChromeHeight,
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
          child: Row(
            children: [
              AnimatedContainer(
                duration: const Duration(milliseconds: 220),
                width: 8,
                height: 8,
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: _watchMissing
                      ? const Color(0xFFEA580C)
                      : (_watchPulse.isEven
                          ? const Color(0xFF7C3AED)
                          : const Color(0xFF22C55E)),
                ),
              ),
              const SizedBox(width: 8),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text(
                      title,
                      maxLines: 1,
                      overflow: TextOverflow.ellipsis,
                      style: TextStyle(
                        fontSize: 11,
                        fontWeight: FontWeight.w700,
                        letterSpacing: 0.2,
                        color: _watchMissing
                            ? const Color(0xFF9A3412)
                            : const Color(0xFF5B21B6),
                      ),
                    ),
                    const SizedBox(height: 2),
                    Text(
                      body,
                      maxLines: 1,
                      overflow: TextOverflow.ellipsis,
                      style: const TextStyle(
                        fontSize: 12,
                        color: Color(0xFF334155),
                      ),
                    ),
                  ],
                ),
              ),
              IconButton(
                tooltip: 'Stop watch',
                visualDensity: VisualDensity.compact,
                padding: EdgeInsets.zero,
                constraints: const BoxConstraints(minWidth: 32, minHeight: 32),
                onPressed: () => unawaited(_stopRecordWatch()),
                icon: const Icon(Icons.close, size: 18),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future<void> _offerWatchSelectedRecord() async {
    if (_isKvMode || _primaryKey == null || _selectedRows.length != 1) {
      return;
    }
    final pk = _selectedRows.first;
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (ctx) => AlertDialog(
        title: const Text('Watch this primary key?'),
        content: Text(
          'Start a live query().watch() on\n'
          '$_selectedTable.$_primaryKey = $pk\n\n'
          'A strip above the log panel will show the row and update on '
          'modify/delete. After switchSpace, the same id in the new space '
          'keeps driving this watch.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(ctx, false),
            child: const Text('Cancel'),
          ),
          FilledButton(
            onPressed: () => Navigator.pop(ctx, true),
            child: const Text('Start watch'),
          ),
        ],
      ),
    );
    if (confirmed == true && mounted) {
      await _startRecordWatch(
        table: _selectedTable,
        pkField: _primaryKey!,
        pkValue: pk,
      );
    }
  }

  Future<void> _startRecordWatch({
    required String table,
    required String pkField,
    required dynamic pkValue,
  }) async {
    await _stopRecordWatch(notify: false);
    if (!mounted) return;

    setState(() {
      _watchTable = table;
      _watchPkField = pkField;
      _watchPkValue = pkValue;
      _watchRow = null;
      _watchMissing = false;
      _watchPulse = 0;
    });

    final stream =
        widget.example.db.query(table).where(pkField, '=', pkValue).watch();

    _watchSub = stream.listen(
      (rows) {
        if (!mounted) return;
        setState(() {
          _watchPulse++;
          if (rows.isEmpty) {
            _watchMissing = true;
            _watchRow = null;
          } else {
            _watchMissing = false;
            _watchRow = Map<String, dynamic>.from(rows.first);
          }
        });
        logService.add(
          rows.isEmpty
              ? 'Watch $_watchTable.$_watchPkField=$_watchPkValue → empty '
                  '(missing in current space)'
              : 'Watch $_watchTable.$_watchPkField=$_watchPkValue → '
                  '${rows.first}',
          LogLevel.info,
        );
      },
      onError: (Object e, StackTrace st) {
        logService.add('Watch error: $e', LogLevel.error);
      },
    );

    logService.add(
      'Started live watch on $table.$pkField=$pkValue',
      LogLevel.info,
    );
  }

  Future<void> _stopRecordWatch({bool notify = true}) async {
    await _watchSub?.cancel();
    _watchSub = null;
    if (!mounted) return;
    if (_watchTable == null && _watchPkValue == null) return;
    setState(() {
      _watchTable = null;
      _watchPkField = null;
      _watchPkValue = null;
      _watchRow = null;
      _watchMissing = false;
    });
    if (notify) {
      logService.add('Stopped live record watch', LogLevel.info);
    }
  }

  Widget _buildDataHeader() {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
      child: Column(
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              // Table Selector Dropdown Pill
              Container(
                height: 36.0,
                padding: const EdgeInsets.symmetric(horizontal: 10.0),
                decoration: BoxDecoration(
                  color: const Color(0xFFF8FAFC),
                  borderRadius: BorderRadius.circular(8.0),
                  border:
                      Border.all(color: const Color(0xFFE2E8F0), width: 1.0),
                ),
                child: DropdownButtonHideUnderline(
                  child: DropdownButton<String>(
                    value: _selectedTable,
                    icon: const Icon(
                      Icons.keyboard_arrow_down_rounded,
                      size: 20,
                      color: Color(0xFF64748B),
                    ),
                    style: const TextStyle(
                      fontSize: 14,
                      fontWeight: FontWeight.w600,
                      color: Color(0xFF0F172A),
                    ),
                    dropdownColor: Colors.white,
                    focusColor: Colors.transparent,
                    borderRadius: BorderRadius.circular(10),
                    items: _tableNames.map((String tableName) {
                      return DropdownMenuItem<String>(
                        value: tableName,
                        child: Text(tableName),
                      );
                    }).toList(),
                    onChanged: (String? newTable) {
                      if (newTable != null && newTable != _selectedTable) {
                        setState(() {
                          _selectedTable = newTable;
                          _activeFilters.clear();
                        });
                        _fetchTableData(resetPage: true);
                      }
                    },
                  ),
                ),
              ),
              Text(
                  _isCountCalculating
                      ? (_totalRecords > 0
                          ? '$_totalRecords Records (updating...)'
                          : 'Loading count...')
                      : (_isCountLimited
                          ? '≥$_totalRecords Records ($_selectedSpace)'
                          : '$_totalRecords Records ($_selectedSpace)'),
                  style: Theme.of(context).textTheme.bodyMedium),
            ],
          ),
          const SizedBox(height: 8),

          // Action Buttons
          Wrap(
            alignment: WrapAlignment.center,
            spacing: 8.0,
            runSpacing: 8.0,
            children: [
              if (_isKvMode) ...[
                ElevatedButton.icon(
                  onPressed: _isDataLoading ? null : _showKvBatchAddDialog,
                  icon: const Icon(Icons.add, size: 16),
                  label: const Text('Batch Add'),
                  style: ElevatedButton.styleFrom(
                    padding:
                        const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
                    backgroundColor: const Color.fromARGB(255, 10, 150, 210),
                    foregroundColor: Colors.white,
                    textStyle: const TextStyle(fontSize: 14),
                    tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                    visualDensity: VisualDensity.compact,
                  ),
                ),
                ElevatedButton.icon(
                  onPressed: _selectedRows.isEmpty || _isDataLoading
                      ? null
                      : _confirmDeleteSelected,
                  icon: const Icon(Icons.delete, size: 16),
                  label: Text('Del(${_selectedRows.length})'),
                  style: ElevatedButton.styleFrom(
                    padding:
                        const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
                    backgroundColor:
                        _selectedRows.isEmpty ? Colors.grey : Colors.red,
                    foregroundColor: Colors.white,
                    textStyle: const TextStyle(fontSize: 14),
                    tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                    visualDensity: VisualDensity.compact,
                  ),
                ),
              ] else ...[
                ElevatedButton.icon(
                  onPressed: _isDataLoading ? null : _showAddDataDialog,
                  icon: const Icon(Icons.add, size: 16),
                  label: const Text('Add'),
                  style: ElevatedButton.styleFrom(
                    padding:
                        const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
                    backgroundColor: const Color.fromARGB(255, 10, 150, 210),
                    foregroundColor: Colors.white,
                    textStyle: const TextStyle(fontSize: 14),
                    tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                    visualDensity: VisualDensity.compact,
                  ),
                ),
                ElevatedButton.icon(
                  onPressed: _selectedRows.isEmpty || _isDataLoading
                      ? null
                      : _showBatchUpdateDialog,
                  icon: const Icon(Icons.edit, size: 16),
                  label: const Text('Modify'),
                  style: ElevatedButton.styleFrom(
                    padding:
                        const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
                    backgroundColor:
                        _selectedRows.isEmpty ? Colors.grey : Colors.green,
                    foregroundColor: Colors.white,
                    textStyle: const TextStyle(fontSize: 14),
                    tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                    visualDensity: VisualDensity.compact,
                  ),
                ),
                ElevatedButton.icon(
                  onPressed: _selectedRows.isEmpty || _isDataLoading
                      ? null
                      : _confirmDeleteSelected,
                  icon: const Icon(Icons.delete, size: 16),
                  label: Text('Del(${_selectedRows.length})'),
                  style: ElevatedButton.styleFrom(
                    padding:
                        const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
                    backgroundColor:
                        _selectedRows.isEmpty ? Colors.grey : Colors.red,
                    foregroundColor: Colors.white,
                    textStyle: const TextStyle(fontSize: 14),
                    tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                    visualDensity: VisualDensity.compact,
                  ),
                ),
              ],
              PopupMenuButton<String>(
                icon: Icon(
                  Icons.more_horiz_outlined,
                  color: _activeFilters.isEmpty ? null : Colors.orange.shade700,
                ),
                tooltip: 'Advanced Actions',
                onSelected: (value) {
                  if (value == 'kv_set') {
                    _showKvSetDialog();
                  } else if (value == 'kv_get') {
                    _showKvGetDialog();
                  } else if (value == 'filter') {
                    _showFilterDialog();
                  } else if (value == 'watch_pk') {
                    unawaited(_offerWatchSelectedRecord());
                  } else if (value == 'custom_delete') {
                    _showCustomDeleteDialog();
                  } else if (value == 'clear_current_table') {
                    _confirmClearCurrentTable();
                  } else if (value == 'vector_search') {
                    _showVectorSearchBenchmarkDialog();
                  }
                },
                itemBuilder: (context) => [
                  if (_isKvMode) ...[
                    const PopupMenuItem(
                      value: 'kv_set',
                      child: Row(
                        children: [
                          Icon(Icons.edit_note, size: 18, color: Colors.green),
                          SizedBox(width: 8),
                          Text('Set Key'),
                        ],
                      ),
                    ),
                    const PopupMenuItem(
                      value: 'kv_get',
                      child: Row(
                        children: [
                          Icon(Icons.search, size: 18, color: Colors.indigo),
                          SizedBox(width: 8),
                          Text('Get Key'),
                        ],
                      ),
                    ),
                    const PopupMenuDivider(),
                  ],
                  PopupMenuItem(
                    value: 'filter',
                    child: Row(
                      children: [
                        const Icon(Icons.filter_alt_outlined, size: 18),
                        const SizedBox(width: 8),
                        Text(
                            _isKvMode ? 'Filter by Key Prefix' : 'Filter Data'),
                      ],
                    ),
                  ),
                  if (!_isKvMode) ...[
                    PopupMenuItem(
                      value: 'watch_pk',
                      enabled: _selectedRows.length == 1 &&
                          _primaryKey != null &&
                          !_isDataLoading,
                      child: Row(
                        children: [
                          Icon(
                            Icons.visibility_outlined,
                            size: 18,
                            color: _selectedRows.length == 1
                                ? const Color(0xFF7C3AED)
                                : Colors.grey,
                          ),
                          const SizedBox(width: 8),
                          Text(
                            _selectedRows.length == 1
                                ? 'Watch PK ${_selectedRows.first}'
                                : 'Watch PK (select 1 row)',
                          ),
                        ],
                      ),
                    ),
                    const PopupMenuDivider(),
                    const PopupMenuItem(
                      value: 'custom_delete',
                      child: Row(
                        children: [
                          Icon(Icons.playlist_remove, size: 18),
                          SizedBox(width: 8),
                          Text('Custom Delete'),
                        ],
                      ),
                    ),
                    if (_hasVectorSupport) const PopupMenuDivider(),
                    if (_hasVectorSupport)
                      const PopupMenuItem(
                        value: 'vector_search',
                        child: Row(
                          children: [
                            Icon(Icons.query_stats,
                                size: 18, color: Color(0xff0aa6e8)),
                            SizedBox(width: 8),
                            Text('Vector Search'),
                          ],
                        ),
                      ),
                  ],
                  const PopupMenuDivider(),
                  PopupMenuItem(
                    value: 'clear_current_table',
                    child: Row(
                      children: [
                        const Icon(Icons.cleaning_services_rounded, size: 18),
                        const SizedBox(width: 8),
                        Text(_isKvMode ? 'Clear KV' : 'Clear Table'),
                      ],
                    ),
                  ),
                ],
              ),
            ],
          )
        ],
      ),
    );
  }

  Widget _buildActiveFiltersDisplay() {
    if (_activeFilters.isEmpty) {
      return const SizedBox.shrink();
    }

    return Padding(
      padding: const EdgeInsets.fromLTRB(16, 0, 8, 8),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Expanded(
            child: Wrap(
              spacing: 6.0,
              runSpacing: 6.0,
              children: _activeFilters.map((filter) {
                return Chip(
                  materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                  padding: const EdgeInsets.all(4),
                  label: Text(
                      "'${filter['field']}' ${filter['operator']} '${filter['value']}'"),
                  deleteIcon: const Icon(Icons.close, size: 14),
                  onDeleted: () {
                    setState(() {
                      _activeFilters.remove(filter);
                    });
                    _fetchTableData(resetPage: true);
                  },
                );
              }).toList(),
            ),
          ),
          IconButton(
            tooltip: 'Clear All Filters',
            icon: const Icon(Icons.close_outlined, color: Colors.redAccent),
            onPressed: () {
              setState(() {
                _activeFilters.clear();
              });
              _fetchTableData(resetPage: true);
            },
          ),
        ],
      ),
    );
  }

  Widget _buildDataTable() {
    if (_tableColumns.isEmpty) {
      return const Expanded(child: Center(child: Text('No records found.')));
    }

    return Expanded(
      child: SingleChildScrollView(
        scrollDirection: Axis.vertical,
        child: SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: DataTable(
            sortColumnIndex: _sortColumn == null
                ? null
                : _tableColumns.indexOf(_sortColumn!),
            sortAscending: _sortAscending,
            showCheckboxColumn: _primaryKey != null,
            columns: [
              for (final colName in _tableColumns)
                DataColumn(
                  label: Text(colName),
                  onSort: (columnIndex, ascending) {
                    setState(() {
                      if (_sortColumn == _tableColumns[columnIndex]) {
                        if (_sortAscending) {
                          _sortAscending = false;
                        } else {
                          _sortColumn = null;
                        }
                      } else {
                        _sortColumn = _tableColumns[columnIndex];
                        _sortAscending = true;
                      }
                    });
                    _fetchTableData();
                  },
                ),
            ],
            rows: _tableData.map((row) {
              final pkValue = _primaryKey != null ? row[_primaryKey] : null;
              return DataRow(
                selected: pkValue != null && _selectedRows.contains(pkValue),
                onSelectChanged: pkValue == null
                    ? null
                    : (isSelected) {
                        setState(() {
                          if (isSelected ?? false) {
                            _selectedRows.add(pkValue);
                          } else {
                            _selectedRows.remove(pkValue);
                          }
                        });
                      },
                cells: [
                  for (final colName in _tableColumns)
                    DataCell(
                      Text(
                        '${row[colName] ?? 'NULL'}',
                        overflow: TextOverflow.ellipsis,
                      ),
                      onLongPress: () {
                        if (_primaryKey != null && row[_primaryKey] != null) {
                          _showEditRowDialog(row);
                        }
                      },
                    ),
                ],
              );
            }).toList(),
            onSelectAll: (isSelected) {
              if (_primaryKey == null) return;
              setState(() {
                if (isSelected ?? false) {
                  for (final row in _tableData) {
                    _selectedRows.add(row[_primaryKey]);
                  }
                } else {
                  for (final row in _tableData) {
                    _selectedRows.remove(row[_primaryKey]);
                  }
                }
              });
            },
          ),
        ),
      ),
    );
  }

  Widget _buildPaginationControls() {
    if (_paginationMode == PaginationMode.cursor) {
      return Padding(
        padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 8.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            IconButton(
              icon: const Icon(Icons.first_page, size: 20),
              tooltip: 'Jump to First Page',
              onPressed: _prevCursor != null
                  ? () => _fetchTableData(resetPage: true)
                  : null,
              visualDensity: VisualDensity.compact,
              padding: EdgeInsets.zero,
            ),
            const SizedBox(width: 8),
            ElevatedButton.icon(
              icon: const Icon(Icons.chevron_left, size: 16),
              label: const Text('Prev'),
              style: ElevatedButton.styleFrom(
                padding:
                    const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
                visualDensity: VisualDensity.compact,
                tapTargetSize: MaterialTapTargetSize.shrinkWrap,
              ),
              onPressed: _prevCursor != null
                  ? () => _fetchTableData(cursor: _prevCursor)
                  : null,
            ),
            const SizedBox(width: 16),
            ElevatedButton.icon(
              icon: const Icon(Icons.chevron_right, size: 16),
              label: const Text('Next'),
              style: ElevatedButton.styleFrom(
                padding:
                    const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
                visualDensity: VisualDensity.compact,
                tapTargetSize: MaterialTapTargetSize.shrinkWrap,
              ),
              onPressed: _nextCursor != null
                  ? () => _fetchTableData(cursor: _nextCursor)
                  : null,
            ),
          ],
        ),
      );
    }

    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 8.0),
      child: Wrap(
        alignment: WrapAlignment.center,
        crossAxisAlignment: WrapCrossAlignment.center,
        spacing: 2.0, // Reduced space between items
        runSpacing: 8.0,
        children: [
          IconButton(
            icon: const Icon(Icons.first_page),
            tooltip: 'First Page',
            onPressed: _currentPage > 1 ? () => _goToPage(1) : null,
            visualDensity: VisualDensity.compact,
            padding: EdgeInsets.zero,
          ),
          IconButton(
            icon: const Icon(Icons.chevron_left),
            tooltip: 'Previous Page',
            onPressed:
                _currentPage > 1 ? () => _goToPage(_currentPage - 1) : null,
            visualDensity: VisualDensity.compact,
            padding: EdgeInsets.zero,
          ),
          Row(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              const Text('Page'),
              const SizedBox(width: 4), // Reduced space
              SizedBox(
                width: 50,
                child: TextField(
                  controller: _pageInputController,
                  textAlign: TextAlign.center,
                  keyboardType: TextInputType.number,
                  inputFormatters: [FilteringTextInputFormatter.digitsOnly],
                  decoration: const InputDecoration(
                    isDense: true,
                    border: OutlineInputBorder(),
                    contentPadding: EdgeInsets.symmetric(horizontal: 8),
                  ),
                  onSubmitted: (value) {
                    final page = int.tryParse(value);
                    if (page != null) {
                      _goToPage(page);
                    }
                  },
                ),
              ),
              const SizedBox(width: 4), // Reduced space
              Text('of $_totalPages'),
            ],
          ),
          IconButton(
            icon: const Icon(Icons.chevron_right),
            tooltip: 'Next Page',
            onPressed: _currentPage < _totalPages
                ? () => _goToPage(_currentPage + 1)
                : null,
            visualDensity: VisualDensity.compact,
            padding: EdgeInsets.zero,
          ),
          IconButton(
            icon: const Icon(Icons.last_page),
            tooltip: 'Last Page',
            onPressed: _currentPage < _totalPages
                ? () => _goToPage(_totalPages)
                : null,
            visualDensity: VisualDensity.compact,
            padding: EdgeInsets.zero,
          ),
        ],
      ),
    );
  }

  void _goToPage(int page) {
    if (page < 1 || page > _totalPages) return;
    setState(() {
      _currentPage = page;
    });
    _fetchTableData();
  }

  void _showOffsetLimitWarning(int offset, int maxOffset) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Row(
          children: [
            Icon(Icons.warning_amber_rounded, color: Colors.orange),
            SizedBox(width: 8),
            Text('Offset Limit Reached'),
          ],
        ),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Current offset: $offset'),
            Text('Environment limit: $maxOffset'),
            const SizedBox(height: 12),
            const Text(
              'Deep pagination using Offset is discouraged due to performance costs. '
              'Please use Cursor mode for better performance at this depth.',
              style: TextStyle(fontWeight: FontWeight.bold),
            ),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Cancel'),
          ),
          ElevatedButton(
            onPressed: () {
              Navigator.pop(context);
              setState(() {
                _paginationMode = PaginationMode.cursor;
              });
              _fetchTableData(resetPage: true);
            },
            child: const Text('Switch to Cursor Mode'),
          ),
        ],
      ),
    );
  }

  Widget _buildTestsView() {
    return SingleChildScrollView(
      child: Padding(
        padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 200.0),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Container(
              height: 40,
              alignment: Alignment.center,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  if (_isTesting) ...[
                    const SizedBox(
                      height: 16,
                      width: 16,
                      child: CircularProgressIndicator(strokeWidth: 2.0),
                    ),
                    const SizedBox(width: 12),
                  ],
                  Expanded(
                    child: Text(
                      _lastOperationInfo,
                      style: Theme.of(context).textTheme.titleMedium,
                      overflow: TextOverflow.ellipsis,
                      textAlign:
                          _isTesting ? TextAlign.start : TextAlign.center,
                    ),
                  ),
                ],
              ),
            ),
            const SizedBox(height: 20),
            LayoutBuilder(builder: (context, constraints) {
              final double calculatedWidth = (constraints.maxWidth - 12) / 2;
              final double buttonWidth = constraints.maxWidth < 360
                  ? constraints.maxWidth
                  : math.min(calculatedWidth, 220.0);

              return Wrap(
                spacing: 12,
                runSpacing: 12,
                alignment: WrapAlignment.center,
                children: [
                  SizedBox(
                    width: buttonWidth,
                    child: Tooltip(
                      message: 'Run standardized performance benchmark suite',
                      child: _buildActionButton(
                        text: 'Benchmark Test',
                        icon: Icons.speed_rounded,
                        onPressed: !_isDbInitialized || _isTesting
                            ? null
                            : () {
                                _checkAndExpandLogPanel();
                                _showBenchmarkDialog();
                              },
                      ),
                    ),
                  ),
                  SizedBox(
                    width: buttonWidth,
                    child: Tooltip(
                      message: _isWasmBuild
                          ? 'Concurrency Test is unavailable on WebAssembly builds'
                          : 'Run configurable concurrency test',
                      child: _buildActionButton(
                        text: 'Concurrency Test',
                        icon: Icons.alt_route_rounded,
                        onPressed:
                            !_isDbInitialized || _isTesting || _isWasmBuild
                                ? null
                                : () {
                                    _checkAndExpandLogPanel();
                                    _showConcurrencyTestDialog();
                                  },
                      ),
                    ),
                  ),
                  SizedBox(
                    width: buttonWidth,
                    child: _buildActionButton(
                      text: 'Run All Tests',
                      icon: Icons.play_arrow_rounded,
                      onPressed: !_isDbInitialized || _isTesting
                          ? null
                          : () async {
                              _checkAndExpandLogPanel();
                              setState(() {
                                _isTesting = true;
                              });
                              try {
                                final tester = DatabaseTester(
                                  widget.example.db,
                                  logService,
                                  _updateOperationInfo,
                                );
                                await tester.runAllTests();
                              } finally {
                                if (mounted) {
                                  setState(() {
                                    _isTesting = false;
                                  });
                                }
                                _fetchTableData(resetPage: true);
                              }
                            },
                    ),
                  ),
                ],
              );
            }),
          ],
        ),
      ),
    );
  }

  Widget _buildLogPanel(ScrollController scrollController) {
    // We listen to the logs here to dynamically determine the header size.
    return ValueListenableBuilder<List<LogEntry>>(
      valueListenable: logService.logs,
      builder: (context, logs, child) {
        final bool hasLogs = logs.isNotEmpty;
        const double handleAndTitleHeight = 60.0;

        // Use a LayoutBuilder to dynamically calculate the header height
        // based on whether the search/filter section is visible.
        return LayoutBuilder(
          builder: (context, constraints) {
            // Create a text painter to measure text height for an accurate calculation.
            final textPainter = TextPainter(
              text: const TextSpan(text: 'Filter'),
              textDirection: TextDirection.ltr,
            )..layout();

            // Estimate heights for various components.
            const double textFieldHeight =
                50.0; // Approx height of the TextField
            const double paddingAndSpacing = 30.0; // Combined vertical padding
            final double buttonHeight =
                textPainter.height * 2.5; // Estimated height for filter buttons
            final double buttonsSectionHeight =
                (constraints.maxWidth < 350) ? buttonHeight * 2 : buttonHeight;

            final searchAndFilterHeight =
                textFieldHeight + paddingAndSpacing + buttonsSectionHeight;

            final totalHeaderHeight =
                handleAndTitleHeight + (hasLogs ? searchAndFilterHeight : 0);

            return CustomScrollView(
              controller: scrollController,
              slivers: [
                SliverPersistentHeader(
                  pinned: true,
                  delegate: _LogPanelHeaderDelegate(
                    height: totalHeaderHeight,
                    child: GestureDetector(
                      onDoubleTap: () {
                        if (_logPanelController.isAttached) {
                          final bool isExpanded =
                              _logPanelController.size > 0.15;
                          _logPanelController.animateTo(
                            isExpanded ? 0.1 : 0.8,
                            duration: const Duration(milliseconds: 300),
                            curve: Curves.easeOut,
                          );
                        }
                      },
                      child: Container(
                        color: Theme.of(context).colorScheme.surface,
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.stretch,
                          children: [
                            // Drag Handle and Title Row
                            SizedBox(
                              height: handleAndTitleHeight,
                              child: Column(
                                children: [
                                  Center(
                                    child: Container(
                                      width: 40,
                                      height: 4,
                                      margin: const EdgeInsets.only(
                                          top: 6, bottom: 2),
                                      decoration: BoxDecoration(
                                        color: Colors.grey.shade300,
                                        borderRadius: BorderRadius.circular(10),
                                      ),
                                    ),
                                  ),
                                  Expanded(
                                    child: Padding(
                                      padding: const EdgeInsets.fromLTRB(
                                          16.0, 0, 12, 6),
                                      child: AnimatedBuilder(
                                        animation: _logPanelController,
                                        builder: (context, child) {
                                          final bool isExpanded =
                                              _logPanelController.size > 0.15;
                                          return Row(
                                            crossAxisAlignment:
                                                CrossAxisAlignment.center,
                                            children: [
                                              const Text(
                                                'Logs',
                                                style: TextStyle(
                                                  fontWeight: FontWeight.bold,
                                                  fontSize: 16,
                                                ),
                                              ),
                                              const Spacer(),
                                              if (isExpanded) ...[
                                                _buildLogPanelIconButton(
                                                  icon: Icons.arrow_upward,
                                                  tooltip: 'Scroll to Top',
                                                  onPressed: _logCanScrollUp
                                                      ? _logScrollToTop
                                                      : null,
                                                ),
                                                _buildLogPanelIconButton(
                                                  icon: Icons.arrow_downward,
                                                  tooltip: 'Scroll to Bottom',
                                                  onPressed: _logCanScrollDown
                                                      ? _logScrollToBottom
                                                      : null,
                                                ),
                                                _buildLogPanelIconButton(
                                                  icon: Icons.copy_outlined,
                                                  iconSize: 20,
                                                  tooltip: 'Copy Visible Logs',
                                                  onPressed: _copyVisibleLogs,
                                                ),
                                                _buildLogPanelIconButton(
                                                  icon: Icons
                                                      .cleaning_services_rounded,
                                                  iconSize: 20,
                                                  tooltip: 'Clear Logs',
                                                  onPressed: logService.clear,
                                                ),
                                              ],
                                              _buildLogPanelIconButton(
                                                icon: isExpanded
                                                    ? Icons.keyboard_arrow_down
                                                    : Icons.keyboard_arrow_up,
                                                tooltip: isExpanded
                                                    ? 'Collapse Logs'
                                                    : 'Expand Logs',
                                                onPressed: () {
                                                  _logPanelController.animateTo(
                                                    isExpanded ? 0.1 : 0.8,
                                                    duration: const Duration(
                                                        milliseconds: 300),
                                                    curve: Curves.easeOut,
                                                  );
                                                },
                                              ),
                                            ],
                                          );
                                        },
                                      ),
                                    ),
                                  ),
                                  const Divider(height: 1),
                                ],
                              ),
                            ),
                            // Search and Filter section (conditionally shown)
                            if (hasLogs)
                              Expanded(
                                child: Padding(
                                  padding: const EdgeInsets.symmetric(
                                      horizontal: 16.0),
                                  child: Column(
                                    crossAxisAlignment:
                                        CrossAxisAlignment.start,
                                    mainAxisAlignment:
                                        MainAxisAlignment.spaceEvenly,
                                    children: [
                                      TextField(
                                        controller: _searchController,
                                        decoration: InputDecoration(
                                          hintText: 'Search in logs...',
                                          prefixIcon: const Icon(Icons.search),
                                          suffixIcon: _searchController
                                                  .text.isNotEmpty
                                              ? IconButton(
                                                  icon: const Icon(Icons.clear),
                                                  onPressed: () {
                                                    _searchController.clear();
                                                  },
                                                )
                                              : null,
                                          border: OutlineInputBorder(
                                            borderRadius:
                                                BorderRadius.circular(8),
                                          ),
                                          enabledBorder: OutlineInputBorder(
                                            borderRadius:
                                                BorderRadius.circular(8),
                                            borderSide: BorderSide(
                                                color: Colors.grey.shade300,
                                                width: 0.8),
                                          ),
                                          contentPadding:
                                              const EdgeInsets.symmetric(
                                                  horizontal: 12, vertical: 8),
                                        ),
                                      ),
                                      ValueListenableBuilder<List<LogEntry>>(
                                        valueListenable: logService.logs,
                                        builder: (context, logs, child) {
                                          // Counts...
                                          final allCount = logs.length;
                                          final infoCount = logs
                                              .where((log) =>
                                                  log.type == LogLevel.info)
                                              .length;
                                          final debugCount = logs
                                              .where((log) =>
                                                  log.type == LogLevel.debug)
                                              .length;
                                          final warnCount = logs
                                              .where((log) =>
                                                  log.type == LogLevel.warn)
                                              .length;
                                          final errorCount = logs
                                              .where((log) =>
                                                  log.type == LogLevel.error)
                                              .length;
                                          final criticalCount = logs
                                              .where((log) =>
                                                  log.type == LogLevel.critical)
                                              .length;

                                          return Wrap(
                                            spacing: 8.0,
                                            runSpacing: 8.0,
                                            alignment: WrapAlignment.start,
                                            children: [
                                              _buildFilterButton('All', null,
                                                  allCount, context),
                                              _buildFilterButton(
                                                  'Info',
                                                  LogLevel.info,
                                                  infoCount,
                                                  context),
                                              _buildFilterButton(
                                                  'Debug',
                                                  LogLevel.debug,
                                                  debugCount,
                                                  context),
                                              _buildFilterButton(
                                                  'Warn',
                                                  LogLevel.warn,
                                                  warnCount,
                                                  context),
                                              _buildFilterButton(
                                                  'Error',
                                                  LogLevel.error,
                                                  errorCount,
                                                  context),
                                              _buildFilterButton(
                                                  'Critical',
                                                  LogLevel.critical,
                                                  criticalCount,
                                                  context),
                                            ],
                                          );
                                        },
                                      ),
                                    ],
                                  ),
                                ),
                              ),
                          ],
                        ),
                      ),
                    ),
                  ),
                ),
                ValueListenableBuilder<List<LogEntry>>(
                  valueListenable: logService.logs,
                  builder: (context, logs, child) {
                    // ... (filtering logic remains the same)
                    final filteredByType = _selectedLogLevel == null
                        ? logs
                        : logs
                            .where((log) => log.type == _selectedLogLevel)
                            .toList();
                    final searchText = _searchController.text.toLowerCase();
                    final filteredLogs = searchText.isEmpty
                        ? filteredByType
                        : filteredByType
                            .where((log) =>
                                log.message.toLowerCase().contains(searchText))
                            .toList();

                    if (filteredLogs.isEmpty) {
                      return const SliverToBoxAdapter(
                        child: Padding(
                          padding: EdgeInsets.symmetric(vertical: 48),
                          child: Center(child: Text('No logs to display.')),
                        ),
                      );
                    }
                    return SliverPadding(
                      padding: const EdgeInsets.symmetric(
                          horizontal: 16.0, vertical: 16.0),
                      sliver: SliverList(
                        delegate: SliverChildBuilderDelegate(
                          (context, index) {
                            final logEntry = filteredLogs[index];
                            return Padding(
                              padding:
                                  const EdgeInsets.symmetric(vertical: 4.0),
                              child: GestureDetector(
                                behavior: HitTestBehavior.opaque,
                                onLongPress: () => _copySingleLog(logEntry),
                                child: Text(
                                  logEntry.message,
                                  style: TextStyle(
                                    fontSize: 12,
                                    color: _getLogColor(logEntry.type),
                                  ),
                                ),
                              ),
                            );
                          },
                          childCount: filteredLogs.length,
                        ),
                      ),
                    );
                  },
                ),
              ],
            );
          },
        );
      },
    );
  }

  PopupMenuButton<String> _buildMoreActionsButton() {
    return PopupMenuButton<String>(
      onSelected: (value) async {
        if (value.startsWith('switch_space_')) {
          final newSpace = value.substring('switch_space_'.length);
          if (newSpace != _selectedSpace) {
            await widget.example.db
                .switchSpace(spaceName: newSpace, keepActive: true);
            setState(() {
              _selectedSpace = newSpace;
              _activeFilters.clear();
            });
            await _fetchTableData(resetPage: true);
          }
          return;
        }

        switch (value) {
          case 'set_mode_offset':
            setState(() {
              _paginationMode = PaginationMode.offset;
            });
            _fetchTableData(resetPage: true);
            break;
          case 'set_mode_cursor':
            setState(() {
              _paginationMode = PaginationMode.cursor;
            });
            _fetchTableData(resetPage: true);
            break;
          case 'clear_all_tables':
            setState(() {
              _isTesting = true;
              _lastOperationInfo = 'Clearing all tables...';
            });
            try {
              await widget.example.db.clear(ExampleSchemas.comments.name);
              await widget.example.db.clear(ExampleSchemas.posts.name);
              await widget.example.db.clear(ExampleSchemas.users.name);
              await widget.example.db.clear(ExampleSchemas.settings.name);
              await widget.example.db.clear(ExampleSchemas.embeddings.name);
              _updateOperationInfo('All tables cleared.');
              _fetchTableData(resetPage: true);
            } finally {
              if (mounted) {
                setState(() {
                  _isTesting = false;
                });
              }
            }
            break;
          case 'restore_initialization':
            _confirmRestoreInitialization();
            break;
        }
      },
      itemBuilder: (BuildContext context) {
        return [
          PopupMenuItem<String>(
            value: _paginationMode == PaginationMode.offset
                ? 'set_mode_cursor'
                : 'set_mode_offset',
            child: Row(
              children: [
                Icon(
                  _paginationMode == PaginationMode.offset
                      ? Icons.ads_click
                      : Icons.format_list_numbered,
                  size: 20,
                  color: Colors.blue,
                ),
                const SizedBox(width: 12),
                Text(_paginationMode == PaginationMode.offset
                    ? 'Switch to Cursor Mode'
                    : 'Switch to Offset Mode'),
              ],
            ),
          ),
          const PopupMenuDivider(),
          const PopupMenuItem<String>(
            enabled: false,
            child: Row(
              children: [
                Icon(Icons.storage, size: 20, color: Colors.grey),
                SizedBox(width: 12),
                Text('Switch Space',
                    style: TextStyle(fontWeight: FontWeight.bold)),
              ],
            ),
          ),
          ..._spaceNames.map((spaceName) {
            return CheckedPopupMenuItem<String>(
              value: 'switch_space_$spaceName',
              checked: _selectedSpace == spaceName,
              child: Text(spaceName),
            );
          }),
          const PopupMenuDivider(),
          const PopupMenuItem<String>(
            value: 'clear_all_tables',
            child: Row(
              children: [
                Icon(
                  Icons.delete_sweep,
                  size: 20,
                ),
                SizedBox(width: 12),
                Text('Clear All Tables'),
              ],
            ),
          ),
          const PopupMenuDivider(),
          const PopupMenuItem<String>(
            value: 'restore_initialization',
            child: Row(
              children: [
                Icon(
                  Icons.refresh_rounded,
                  size: 20,
                ),
                SizedBox(width: 12),
                Text('Restore Initialization'),
              ],
            ),
          ),
        ];
      },
    );
  }

  Future<void> _showBenchmarkDialog() async {
    final config = await showDialog<BenchmarkConfig>(
      context: context,
      barrierDismissible: true,
      builder: (context) => BenchmarkDialog(
        lastSummary: _lastBenchmarkSummary,
        initialConfig: _benchmarkConfig,
      ),
    );
    if (!mounted || config == null) return;

    _benchmarkConfig = config;
    _updateOperationInfo('Starting Benchmark Suite...');
    setState(() {
      _isTesting = true;
    });
    BenchmarkSummary? resultSummary;
    try {
      final runner = BenchmarkRunner(
        widget.example.db,
        logService,
        _updateOperationInfo,
      );
      resultSummary = await runner.runBenchmark(config);
      if (mounted) {
        setState(() {
          _lastBenchmarkSummary = resultSummary;
        });
      }
    } catch (e) {
      logService.add('Benchmark failed: $e', LogLevel.error);
      _updateOperationInfo('❌ Benchmark Failed');
    } finally {
      if (mounted) {
        setState(() {
          _isTesting = false;
        });
        _fetchTableData(resetPage: true);
        if (resultSummary != null) {
          // Auto open results dialog upon completion
          _showBenchmarkDialog();
        }
      }
    }
  }

  Future<void> _showConcurrencyTestDialog() async {
    if (_isWasmBuild) {
      logService.add(
        '❌ Concurrency Test is disabled on WebAssembly builds.',
        LogLevel.warn,
      );
      _updateOperationInfo('❌ Concurrency Test Disabled on WebAssembly');
      return;
    }

    final config = await showDialog<Map<String, Map<String, int>>>(
      context: context,
      barrierDismissible: false,
      builder: (context) => const ConcurrencyTestDialog(),
    );
    if (!mounted) return;

    if (config != null) {
      _updateOperationInfo('Running Custom Concurrency Test...');
      setState(() {
        _isTesting = true;
      });
      try {
        final tester = DatabaseTester(
          widget.example.db,
          logService,
          _updateOperationInfo,
        );
        final success = await tester.runConfigurableConcurrencyTest(config);
        if (success) {
          _updateOperationInfo('✅ Custom Concurrency Test Passed');
        } else {
          _updateOperationInfo('❌ Custom Concurrency Test Failed');
        }
      } finally {
        if (mounted) {
          setState(() {
            _isTesting = false;
          });
          _fetchTableData(resetPage: true);
        }
      }
    }
  }

  Future<void> _showVectorSearchBenchmarkDialog() async {
    final result = await showDialog<Map<String, int>>(
      context: context,
      builder: (context) => const VectorSearchDialog(),
    );
    if (!mounted) return;

    if (result != null) {
      final iterations = result['iterations'] ?? 1;
      final topK = result['topK'] ?? 10;
      final searchDepth = result['searchDepth'] ?? 50;

      setState(() {
        _isTesting = true;
        _lastOperationInfo =
            'Running $iterations vector search iterations (Top-$topK, depth=$searchDepth)...';
      });

      try {
        await widget.example.vectorSearchBenchmark(
          _selectedTable,
          iterations,
          topK,
          searchDepth: searchDepth,
        );
      } catch (e) {
        logService.add('Benchmark failed: $e', LogLevel.error);
        _updateOperationInfo('❌ Vector search benchmark failed.');
      } finally {
        if (mounted) {
          setState(() {
            _isTesting = false;
          });
        }
      }
    }
  }

  Future<void> _showAddDataDialog() async {
    final result = await showDialog<Map<String, dynamic>>(
      context: context,
      builder: (context) => AddDataDialog(
        defaultCount: 10000,
        tableName: _selectedTable,
        db: widget.example.db,
      ),
    );
    if (!mounted) return;

    if (result != null) {
      final count = result['count'] as int;
      final method = result['method'] as InsertMethod;
      final foreignKeyValues =
          result['foreignKeyValues'] as Map<String, dynamic>?;
      final foreignKeyModes =
          result['foreignKeyModes'] as Map<String, ForeignKeyMode>?;
      final foreignKeyIdLists =
          result['foreignKeyIdLists'] as Map<String, List<dynamic>>?;

      if (count <= 0) return;

      setState(() {
        _isTesting = true; // Use the tests view's testing flag
        _isDataLoading = true;
        _lastOperationInfo =
            'Adding $count records (${method == InsertMethod.batch ? 'batch' : 'one-by-one'})...';
      });

      int elapsed = -1;

      try {
        if (method == InsertMethod.batch) {
          // Use the existing benchmark logic for batch adding
          elapsed = await widget.example.addExamples(
            _selectedTable,
            count,
            foreignKeyValues: foreignKeyValues,
            foreignKeyModes: foreignKeyModes,
            foreignKeyIdLists: foreignKeyIdLists,
          );
        } else {
          // Use the existing benchmark logic for one-by-one adding
          elapsed = await widget.example.addExamplesOneByOne(
            _selectedTable,
            count,
            foreignKeyValues: foreignKeyValues,
            foreignKeyModes: foreignKeyModes,
            foreignKeyIdLists: foreignKeyIdLists,
          );
        }
      } catch (e, s) {
        logService.add('Failed to add data: $e', LogLevel.error);
        logService.add('Stacktrace: $s', LogLevel.error);
        // 'elapsed' remains -1, indicating failure.
      }

      if (!mounted) return;

      // Show a user-friendly SnackBar based on the operation result.
      if (elapsed >= 0) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Added $count records in ${elapsed}ms'),
            duration: const Duration(seconds: 3),
            backgroundColor: Colors.green,
          ),
        );
      } else {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text('Failed to add data. Please check logs for details.'),
            duration: Duration(seconds: 4),
            backgroundColor: Colors.red,
          ),
        );
      }

      setState(() {
        _isTesting = false;
      });
      await _fetchTableData(
          resetPage: true); // Refresh the view and go to page 1
    }
  }

  Future<void> _confirmDeleteSelected() async {
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Confirm Deletion'),
        content: Text(
            'Are you sure you want to delete ${_selectedRows.length} selected record(s)?'),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: const Text('Cancel'),
          ),
          TextButton(
            onPressed: () => Navigator.of(context).pop(true),
            style: TextButton.styleFrom(foregroundColor: Colors.red),
            child: const Text('Delete'),
          ),
        ],
      ),
    );

    if (confirmed ?? false) {
      if (_primaryKey == null) {
        logService.add('Cannot delete without a primary key.', LogLevel.error);
        return;
      }

      setState(() {
        _isDataLoading = true;
        _lastOperationInfo = 'Deleting ${_selectedRows.length} records...';
      });

      try {
        if (_isKvMode) {
          final keys = _selectedRows.map((e) => e.toString()).toList();
          final result = await widget.example.db.kv
              .removeKeys(keys, isGlobal: _isKvGlobal);
          logService.add(
              'Removed ${result.successCount} of ${keys.length} KV key(s).',
              !result.hasErrors ? LogLevel.info : LogLevel.warn);
          if (result.failedCount > 0) {
            logService.add(
                'Failed to remove ${result.failedCount} KV key(s). Error: ${_dbResultErrorMessage(result)}',
                LogLevel.error);
          }
        } else {
          final result = await widget.example.db
              .delete(_selectedTable)
              .whereIn(_primaryKey!, _selectedRows.toList());

          logService.add(
              'Deleted ${result.successCount} of ${_selectedRows.length} records.',
              !result.hasErrors ? LogLevel.info : LogLevel.warn);

          if (result.failedCount > 0) {
            logService.add(
                'Failed to delete ${result.failedCount} records. Error: ${_dbResultErrorMessage(result)}',
                LogLevel.error);
          }
        }
      } catch (e, s) {
        logService.add('Failed to delete data: $e', LogLevel.error);
        logService.add('Stacktrace: $s', LogLevel.error);
      }

      _selectedRows.clear();
      await _fetchTableData(); // Refresh the view
    }
  }

  Future<void> _showEditRowDialog(Map<String, dynamic> rowData) async {
    if (_isKvMode) {
      await _showKvSetDialog(
        initialKey: rowData['key']?.toString(),
        initialValue: rowData['value']?.toString(),
      );
      return;
    }

    final schema = await widget.example.db.getTableSchema(_selectedTable);
    if (schema == null) {
      logService.add('Cannot edit row: Schema not found for $_selectedTable.',
          LogLevel.warn);
      return;
    }

    if (!mounted) return;
    final Map<String, dynamic>? updatedData = await showDialog(
      context: context,
      builder: (context) => EditRowDialog(
        schema: schema,
        initialData: rowData,
      ),
    );
    if (!mounted) return;

    if (updatedData != null) {
      setState(() {
        _isDataLoading = true;
        _lastOperationInfo = 'Updating row...';
      });

      final pkValue = rowData[schema.primaryKeyConfig.name];

      try {
        final result = await widget.example.db
            .update(_selectedTable, updatedData)
            .where(schema.primaryKeyConfig.name, '=', pkValue);

        if (!result.hasErrors) {
          logService.add('Row successfully updated.', LogLevel.info);
          if (mounted) {
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(
                content: Text('Row updated!'),
                duration: Duration(seconds: 2),
              ),
            );
          }
        } else {
          final errorMsg = _dbResultErrorMessage(result);
          logService.add('Failed to update row: $errorMsg', LogLevel.error);
          if (mounted) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text('Error: $errorMsg'),
                backgroundColor: Colors.red,
              ),
            );
          }
        }
      } catch (e, s) {
        logService.add('Failed to update data: $e', LogLevel.error);
        logService.add('Stacktrace: $s', LogLevel.error);
      }

      await _fetchTableData();
    }
  }

  Future<void> _showBatchUpdateDialog() async {
    final schema = await widget.example.db.getTableSchema(_selectedTable);
    if (schema == null) {
      logService.add(
          'Cannot modify rows: Schema not found for $_selectedTable.',
          LogLevel.warn);
      return;
    }

    if (!mounted) return;
    final Map<String, dynamic>? updateInfo = await showDialog(
      context: context,
      builder: (context) => BatchUpdateDialog(schema: schema),
    );
    if (!mounted) return;

    if (updateInfo != null) {
      final fieldToUpdate = updateInfo['field'] as String;
      final newValue = updateInfo['value'];

      setState(() {
        _isDataLoading = true;
        _lastOperationInfo = 'Updating ${_selectedRows.length} records...';
      });

      try {
        final result = await widget.example.db
            .update(_selectedTable, {fieldToUpdate: newValue})
            .whereIn(_primaryKey!, _selectedRows.toList())
            .allowPartialErrors();

        final successMsg =
            'Successfully updated ${result.successCount} of ${_selectedRows.length} records.';
        logService.add(successMsg, LogLevel.info);
        if (mounted) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content: Text(successMsg),
              duration: const Duration(seconds: 3),
            ),
          );
        }

        if (result.failedCount > 0) {
          final errorMsg =
              'Failed to update ${result.failedCount} records. Error: ${_dbResultErrorMessage(result)}';
          logService.add(errorMsg, LogLevel.error);
          if (mounted) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text(errorMsg),
                backgroundColor: Colors.red,
                duration: const Duration(seconds: 5),
              ),
            );
          }
        }
      } catch (e, s) {
        logService.add('Failed to bulk update data: $e', LogLevel.error);
        logService.add('Stacktrace: $s', LogLevel.error);
      }

      _selectedRows.clear();
      await _fetchTableData();
    }
  }

  Future<void> _showCustomDeleteDialog() async {
    final schema = await widget.example.db.getTableSchema(_selectedTable);
    if (schema == null) {
      logService.add(
          'Cannot perform custom delete: Schema not found for $_selectedTable.',
          LogLevel.warn);
      return;
    }
    if (!mounted) return;
    final result = await showDialog<Map<String, dynamic>>(
      context: context,
      builder: (context) => CustomDeleteDialog(schema: schema),
    );
    if (!mounted) return;

    if (result != null) {
      final field = result['field'] as String;
      final op = result['operator'] as String;
      final value = result['value'];

      if (value == null) {
        logService.add('Invalid value for custom delete.', LogLevel.warn);
        return;
      }
      if (!mounted) return;
      final confirmed = await showDialog<bool>(
        context: context,
        builder: (context) => AlertDialog(
          title: const Text('Confirm Custom Deletion'),
          content: Text(
              'Are you sure you want to delete all records from "$_selectedTable" where $field $op $value? This action cannot be undone.'),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(false),
              child: const Text('Cancel'),
            ),
            TextButton(
              onPressed: () => Navigator.of(context).pop(true),
              style: TextButton.styleFrom(foregroundColor: Colors.red),
              child: const Text('Delete'),
            ),
          ],
        ),
      );
      if (!mounted) return;

      if (confirmed ?? false) {
        setState(() {
          _isDataLoading = true;
          _lastOperationInfo = 'Deleting records where $field $op $value...';
        });

        try {
          final result = await widget.example.db
              .delete(_selectedTable)
              .where(field, op, value)
              .allowLargeScaleOperation();

          logService.add(
              'Custom delete affected ${result.successCount} record(s).',
              !result.hasErrors ? LogLevel.info : LogLevel.warn);

          if (mounted) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text(
                    '${result.successCount} record(s) deleted successfully.'),
              ),
            );
          }
        } catch (e, s) {
          logService.add('Failed to perform custom delete: $e', LogLevel.error);
          logService.add('Stacktrace: $s', LogLevel.error);
        }

        await _fetchTableData(resetPage: true);
      }
    }
  }

  Future<void> _confirmRestoreInitialization() async {
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Confirm Restore Initialization'),
        content: const Text(
          'This will delete the entire database and all test data, then re-initialize it. This action cannot be undone.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: const Text('Cancel'),
          ),
          TextButton(
            onPressed: () => Navigator.of(context).pop(true),
            style: TextButton.styleFrom(foregroundColor: Colors.red),
            child: const Text('Restore'),
          ),
        ],
      ),
    );

    if (confirmed ?? false) {
      if (!mounted) return;
      setState(() {
        _isInitializing = true;
        _lastOperationInfo = 'Restoring Initialization...';
      });

      try {
        await widget.example.db.deleteDatabase();
        logService.add('Database deleted for restoration.', LogLevel.info);
        await _initializeDatabase();
      } catch (e, s) {
        logService.add('Failed to restore initialization: $e', LogLevel.error);
        logService.add('Stacktrace: $s', LogLevel.error);
        if (mounted) {
          setState(() {
            _isInitializing = false;
          });
        }
      }
    }
  }

  Future<void> _showFilterDialog() async {
    if (_isKvMode) {
      final prefixController = TextEditingController(
        text: _activeFilters.isNotEmpty
            ? (_activeFilters.first['value']?.toString() ?? '')
            : '',
      );
      final prefix = await showDialog<String>(
        context: context,
        builder: (context) => AlertDialog(
          title: const Text('Filter KV by Key Prefix'),
          content: TextField(
            controller: prefixController,
            decoration: const InputDecoration(
              labelText: 'Key prefix',
              hintText: _kKvDefaultKeyPrefix,
              border: OutlineInputBorder(),
            ),
            autofocus: true,
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(''),
              child: const Text('Clear Filter'),
            ),
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: const Text('Cancel'),
            ),
            ElevatedButton(
              onPressed: () =>
                  Navigator.of(context).pop(prefixController.text.trim()),
              child: const Text('Apply'),
            ),
          ],
        ),
      );
      prefixController.dispose();
      if (!mounted || prefix == null) return;
      setState(() {
        if (prefix.isEmpty) {
          _activeFilters = [];
        } else {
          _activeFilters = [
            {'field': 'key', 'operator': 'prefix', 'value': prefix},
          ];
        }
      });
      await _fetchTableData(resetPage: true);
      return;
    }

    final schema = await widget.example.db.getTableSchema(_selectedTable);
    if (schema == null) {
      logService.add('Cannot filter: Schema not found for $_selectedTable.',
          LogLevel.warn);
      return;
    }

    if (!mounted) return;
    final newFilters = await showDialog<List<Map<String, dynamic>>>(
      context: context,
      builder: (context) => FilterDialog(
        schema: schema,
        existingFilters: _activeFilters,
      ),
    );
    if (!mounted) return;

    if (newFilters != null) {
      setState(() {
        _activeFilters = newFilters;
      });
      _fetchTableData(resetPage: true);
    }
  }

  Future<void> _confirmClearCurrentTable() async {
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(_isKvMode ? 'Confirm Clear KV' : 'Confirm Clear Table'),
        content: Text(
          _isKvMode
              ? 'Are you sure you want to clear all key-value pairs in ${_isKvGlobal ? 'global' : 'current space'} KV store?'
              : 'Are you sure you want to clear the current table?',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: const Text('Cancel'),
          ),
          TextButton(
            onPressed: () => Navigator.of(context).pop(true),
            style: TextButton.styleFrom(foregroundColor: Colors.red),
            child: const Text('Clear'),
          ),
        ],
      ),
    );
    if (!mounted) return;

    if (confirmed ?? false) {
      setState(() {
        _isDataLoading = true;
        _lastOperationInfo =
            _isKvMode ? 'Clearing KV store...' : 'Clearing current table...';
      });

      try {
        if (_isKvMode) {
          await widget.example.db.kv.clear(isGlobal: _isKvGlobal);
          logService.add(
              'Cleared ${_isKvGlobal ? 'global' : 'space'} KV store.',
              LogLevel.info);
        } else {
          await widget.example.db.clear(_selectedTable);
          logService.add('Cleared table $_selectedTable.', LogLevel.info);
        }
      } catch (e, s) {
        logService.add('Failed to clear table: $e', LogLevel.error);
        logService.add('Stacktrace: $s', LogLevel.error);
      }
      await _fetchTableData(resetPage: true);
    }
  }

  /// Next sequential index for demo KV keys with [prefix].
  ///
  /// One `orderByKeyDesc` seek: 8-digit suffixes make string max == numeric max.
  /// Skips a few non-numeric keys (e.g. leftover `prefix~`) without a count scan.
  Future<int> _nextKvBatchStart(String prefix) async {
    final page = await widget.example.db.kv
        .query(isGlobal: _isKvGlobal)
        .prefix(prefix)
        .orderByKeyDesc()
        .limit(1);
    for (final row in page.data) {
      final key = row['key']?.toString() ?? '';
      if (!key.startsWith(prefix)) continue;
      final parsed = int.tryParse(key.substring(prefix.length));
      if (parsed != null && parsed > 0) return parsed + 1;
    }
    return 1;
  }

  Future<void> _showKvBatchAddDialog() async {
    final result = await showDialog<Map<String, dynamic>>(
      context: context,
      builder: (context) => KvBatchAddDialog(
        isGlobal: _isKvGlobal,
        defaultPrefix: _kKvDefaultKeyPrefix,
      ),
    );
    if (!mounted || result == null) return;

    final count = result['count'] as int;
    final prefix = result['prefix'] as String;
    if (count <= 0) return;

    setState(() {
      _isTesting = true;
      _isDataLoading = true;
      _lastOperationInfo = 'Adding $count KV pairs...';
    });

    final sw = Stopwatch()..start();
    try {
      final startIndex = await _nextKvBatchStart(prefix);
      final endIndex = startIndex + count - 1;
      const chunkSize = 500;
      var written = 0;
      for (var start = startIndex; start <= endIndex; start += chunkSize) {
        final end = math.min(start + chunkSize - 1, endIndex);
        final items = <String, dynamic>{};
        for (var i = start; i <= end; i++) {
          items[_kvBatchKey(prefix, i)] = 'batch_value_${_kvBatchIndexPart(i)}';
        }
        final r =
            await widget.example.db.kv.setMany(items, isGlobal: _isKvGlobal);
        if (r.hasErrors) {
          logService.add('KV batch partial error: ${_dbResultErrorMessage(r)}',
              LogLevel.warn);
        }
        written += end - start + 1;
      }
      sw.stop();
      logService.add(
          'KV batch add: $written pairs in ${sw.elapsedMilliseconds}ms '
          '(${_isKvGlobal ? 'global' : 'space'}, prefix=$prefix, '
          'keys ${_kvBatchKey(prefix, startIndex)}..'
          '${_kvBatchKey(prefix, endIndex)})',
          LogLevel.info);
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content:
                Text('Added $written KV pairs in ${sw.elapsedMilliseconds}ms'),
            backgroundColor: Colors.green,
          ),
        );
      }
    } catch (e, s) {
      logService.add('Failed KV batch add: $e', LogLevel.error);
      logService.add('Stacktrace: $s', LogLevel.error);
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text('Failed to add KV data. Check logs.'),
            backgroundColor: Colors.red,
          ),
        );
      }
    } finally {
      if (mounted) {
        setState(() {
          _isTesting = false;
        });
      }
      await _fetchTableData(resetPage: true);
    }
  }

  Future<void> _showKvSetDialog(
      {String? initialKey, String? initialValue}) async {
    final result = await showDialog<Map<String, dynamic>>(
      context: context,
      builder: (context) => KvSetDialog(
        isGlobal: _isKvGlobal,
        initialKey: initialKey,
        initialValue: initialValue,
      ),
    );
    if (!mounted || result == null) return;

    final key = (result['key'] as String).trim();
    final value = result['value'];
    if (key.isEmpty) return;

    setState(() {
      _isDataLoading = true;
      _lastOperationInfo = 'Setting KV key "$key"...';
    });

    final sw = Stopwatch()..start();
    try {
      final r =
          await widget.example.db.kv.set(key, value, isGlobal: _isKvGlobal);
      sw.stop();
      if (!r.hasErrors) {
        logService.add(
            'KV set "$key" = ${_formatKvDisplayValue(value)} '
            '(${_isKvGlobal ? 'global' : 'space'}) in ${sw.elapsedMilliseconds}ms',
            LogLevel.info);
        _showBriefSnackBar('Set "$key" in ${sw.elapsedMilliseconds}ms');
      } else {
        logService.add(
            'KV set failed: ${_dbResultErrorMessage(r)}', LogLevel.error);
      }
    } catch (e, s) {
      logService.add('Failed KV set: $e', LogLevel.error);
      logService.add('Stacktrace: $s', LogLevel.error);
    }

    await _fetchTableData();
  }

  Future<void> _showKvGetDialog() async {
    final keyController = TextEditingController();
    final key = await showDialog<String>(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Get KV (${_isKvGlobal ? 'global' : 'space'})'),
        content: TextField(
          controller: keyController,
          decoration: InputDecoration(
            labelText: 'Key',
            hintText: _kvBatchKey(_kKvDefaultKeyPrefix, 1),
            border: const OutlineInputBorder(),
          ),
          autofocus: true,
          onSubmitted: (v) => Navigator.of(context).pop(v.trim()),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: const Text('Cancel'),
          ),
          ElevatedButton(
            onPressed: () =>
                Navigator.of(context).pop(keyController.text.trim()),
            child: const Text('Get'),
          ),
        ],
      ),
    );
    keyController.dispose();
    if (!mounted || key == null || key.isEmpty) return;

    final sw = Stopwatch()..start();
    try {
      final value = await widget.example.db.kv.get(key, isGlobal: _isKvGlobal);
      sw.stop();
      final display = value == null
          ? '(not found / expired)'
          : _formatKvDisplayValue(value);
      logService.add(
          'KV get "$key" => $display (${_isKvGlobal ? 'global' : 'space'}) '
          'in ${sw.elapsedMilliseconds}ms',
          LogLevel.info);
      _showBriefSnackBar('Get "$key" in ${sw.elapsedMilliseconds}ms');
      if (!mounted) return;
      await showDialog<void>(
        context: context,
        builder: (context) => AlertDialog(
          title: Text('KV Get: $key (${sw.elapsedMilliseconds}ms)'),
          content: SelectableText(display),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: const Text('Close'),
            ),
          ],
        ),
      );
    } catch (e, s) {
      logService.add('Failed KV get: $e', LogLevel.error);
      logService.add('Stacktrace: $s', LogLevel.error);
    }
  }

  Future<void> _copyVisibleLogs() async {
    final logs = logService.logs.value;
    if (logs.isEmpty) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text('No logs to copy.'),
            duration: Duration(seconds: 2),
          ),
        );
      }
      return;
    }

    // Apply the same filtering logic as in the log panel
    var filteredLogs = logs;

    // Filter by type
    if (_selectedLogLevel != null) {
      filteredLogs =
          filteredLogs.where((log) => log.type == _selectedLogLevel).toList();
    }

    // Filter by search text
    final searchText = _searchController.text.toLowerCase();
    if (searchText.isNotEmpty) {
      filteredLogs = filteredLogs
          .where((log) => log.message.toLowerCase().contains(searchText))
          .toList();
    }

    if (filteredLogs.isEmpty) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text('No visible logs to copy.'),
            duration: Duration(seconds: 2),
          ),
        );
      }
      return;
    }

    // Format logs as text (one log per line)
    final logText = filteredLogs.map((log) => log.message).join('\n');

    // Copy to clipboard
    await Clipboard.setData(ClipboardData(text: logText));

    if (mounted) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Copied ${filteredLogs.length} log(s) to clipboard.'),
          duration: const Duration(seconds: 2),
        ),
      );
    }
  }

  Future<void> _copySingleLog(LogEntry logEntry) async {
    await Clipboard.setData(ClipboardData(text: logEntry.message));
    if (!mounted) return;
    ScaffoldMessenger.of(context).hideCurrentSnackBar();
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        content: Text('Copied selected log to clipboard.'),
        duration: Duration(seconds: 2),
      ),
    );
  }

  /// Log panel toolbar IconButtons: square hit target + CircleBorder so hover
  /// overlay stays circular (M3 default + compact density otherwise flattens it).
  Widget _buildLogPanelIconButton({
    required IconData icon,
    required String tooltip,
    required VoidCallback? onPressed,
    double? iconSize,
  }) {
    return IconButton(
      style: IconButton.styleFrom(
        shape: const CircleBorder(),
        tapTargetSize: MaterialTapTargetSize.shrinkWrap,
        minimumSize: const Size(40, 40),
        maximumSize: const Size(40, 40),
        padding: const EdgeInsets.all(8),
      ),
      icon: Icon(icon, size: iconSize),
      tooltip: tooltip,
      onPressed: onPressed,
    );
  }

  void _checkAndExpandLogPanel() {
    // Threshold is slightly larger than minChildSize to handle tolerances
    // and minor user dragging.
    if (_logPanelController.isAttached && _logPanelController.size < 0.15) {
      // Animate to a size that's large enough to be useful but leaves
      // top controls visible. The max is 0.8.
      const targetSize = 0.7;
      _logPanelController.animateTo(
        targetSize,
        duration: const Duration(milliseconds: 300),
        curve: Curves.easeOut,
      );
    }
  }
}

/// A custom SliverPersistentHeaderDelegate for creating a pinned header
/// for the log panel. This ensures the header (with title and action buttons)
/// stays visible while the log content scrolls.
class _LogPanelHeaderDelegate extends SliverPersistentHeaderDelegate {
  final Widget child;
  final double height;

  _LogPanelHeaderDelegate({required this.child, required this.height});

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return SizedBox.expand(child: child);
  }

  @override
  double get maxExtent => height;

  @override
  double get minExtent => height;

  @override
  bool shouldRebuild(covariant _LogPanelHeaderDelegate oldDelegate) {
    return oldDelegate.height != height || oldDelegate.child != child;
  }
}

/// Dialog to batch-add demo key-value pairs via KvStore.setMany.
class KvBatchAddDialog extends StatefulWidget {
  const KvBatchAddDialog({
    super.key,
    required this.isGlobal,
    this.defaultPrefix = _kKvDefaultKeyPrefix,
  });

  final bool isGlobal;
  final String defaultPrefix;

  @override
  State<KvBatchAddDialog> createState() => _KvBatchAddDialogState();
}

class _KvBatchAddDialogState extends State<KvBatchAddDialog> {
  final _formKey = GlobalKey<FormState>();
  late final TextEditingController _countController;
  late final TextEditingController _prefixController;

  @override
  void initState() {
    super.initState();
    _countController = TextEditingController(text: '10000');
    _prefixController = TextEditingController(text: widget.defaultPrefix);
  }

  @override
  void dispose() {
    _countController.dispose();
    _prefixController.dispose();
    super.dispose();
  }

  void _onSubmit() {
    if (!_formKey.currentState!.validate()) return;
    Navigator.of(context).pop({
      'count': int.parse(_countController.text.trim()),
      'prefix': _prefixController.text.trim(),
    });
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('Batch Add KV (${widget.isGlobal ? 'global' : 'space'})'),
      content: Form(
        key: _formKey,
        child: SizedBox(
          width: 360,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              TextFormField(
                controller: _countController,
                decoration: const InputDecoration(
                  labelText: 'Count',
                  border: OutlineInputBorder(),
                ),
                keyboardType: TextInputType.number,
                inputFormatters: [FilteringTextInputFormatter.digitsOnly],
                validator: (v) {
                  final n = int.tryParse(v?.trim() ?? '');
                  if (n == null || n <= 0) return 'Enter a positive count';
                  if (n > 100000) return 'Max 100000 per batch';
                  return null;
                },
              ),
              const SizedBox(height: 12),
              TextFormField(
                controller: _prefixController,
                decoration: const InputDecoration(
                  labelText: 'Key prefix',
                  hintText: _kKvDefaultKeyPrefix,
                  border: OutlineInputBorder(),
                  helperText: 'Continues from max key, e.g. prefix00000001',
                ),
                validator: (v) {
                  if (v == null || v.trim().isEmpty) {
                    return 'Prefix is required';
                  }
                  return null;
                },
              ),
            ],
          ),
        ),
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.of(context).pop(),
          child: const Text('Cancel'),
        ),
        ElevatedButton(
          onPressed: _onSubmit,
          child: const Text('Add'),
        ),
      ],
    );
  }
}

/// Dialog to set a single key-value pair via KvStore.set.
class KvSetDialog extends StatefulWidget {
  const KvSetDialog({
    super.key,
    required this.isGlobal,
    this.initialKey,
    this.initialValue,
  });

  final bool isGlobal;
  final String? initialKey;
  final String? initialValue;

  @override
  State<KvSetDialog> createState() => _KvSetDialogState();
}

class _KvSetDialogState extends State<KvSetDialog> {
  final _formKey = GlobalKey<FormState>();
  late final TextEditingController _keyController;
  late final TextEditingController _valueController;

  @override
  void initState() {
    super.initState();
    _keyController = TextEditingController(text: widget.initialKey ?? '');
    _valueController = TextEditingController(text: widget.initialValue ?? '');
  }

  @override
  void dispose() {
    _keyController.dispose();
    _valueController.dispose();
    super.dispose();
  }

  void _onSubmit() {
    if (!_formKey.currentState!.validate()) return;
    Navigator.of(context).pop({
      'key': _keyController.text.trim(),
      'value': _parseKvInputValue(_valueController.text),
    });
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('Set KV (${widget.isGlobal ? 'global' : 'space'})'),
      content: Form(
        key: _formKey,
        child: SizedBox(
          width: 400,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              TextFormField(
                controller: _keyController,
                decoration: const InputDecoration(
                  labelText: 'Key',
                  border: OutlineInputBorder(),
                ),
                validator: (v) {
                  if (v == null || v.trim().isEmpty) return 'Key is required';
                  return null;
                },
              ),
              const SizedBox(height: 12),
              TextFormField(
                controller: _valueController,
                decoration: const InputDecoration(
                  labelText: 'Value',
                  border: OutlineInputBorder(),
                  helperText:
                      'Plain text, or JSON (e.g. 123, true, {"a":1}, [1,2])',
                ),
                maxLines: 4,
              ),
            ],
          ),
        ),
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.of(context).pop(),
          child: const Text('Cancel'),
        ),
        ElevatedButton(
          onPressed: _onSubmit,
          child: const Text('Set'),
        ),
      ],
    );
  }
}

/// A dialog for configuring and running a custom concurrency test.
class ConcurrencyTestDialog extends StatefulWidget {
  const ConcurrencyTestDialog({super.key});

  @override
  State<ConcurrencyTestDialog> createState() => _ConcurrencyTestDialogState();
}

class _ConcurrencyTestDialogState extends State<ConcurrencyTestDialog> {
  final _formKey = GlobalKey<FormState>();

  final _controllers = {
    ExampleSchemas.users.name: {
      'insert': TextEditingController(text: '1000'),
      'read': TextEditingController(text: '1000'),
      'update': TextEditingController(text: '500'),
      'delete': TextEditingController(text: '500'),
    },
    ExampleSchemas.settings.name: {
      'insert': TextEditingController(text: '1000'),
      'read': TextEditingController(text: '1000'),
      'update': TextEditingController(text: '500'),
      'delete': TextEditingController(text: '500'),
    },
  };

  @override
  void dispose() {
    for (final table in _controllers.values) {
      for (final controller in table.values) {
        controller.dispose();
      }
    }
    super.dispose();
  }

  void _onRun() {
    if (_formKey.currentState!.validate()) {
      final config = _controllers.map((table, operations) {
        return MapEntry(table, operations.map((op, controller) {
          return MapEntry(op, int.tryParse(controller.text) ?? 0);
        }));
      });
      Navigator.of(context).pop(config);
    }
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      // 1. Make dialog wider by reducing horizontal padding
      insetPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24),
      title: const Text('Configure Concurrency Test'),
      // Use a SizedBox to constrain the content width
      content: SizedBox(
        width: MediaQuery.of(context).size.width, // Use full screen width
        child: SingleChildScrollView(
          child: Form(
            key: _formKey,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: _controllers.entries.map((tableEntry) {
                return _buildTableSection(tableEntry.key, tableEntry.value);
              }).toList(),
            ),
          ),
        ),
      ),
      // 2. Center the buttons
      actionsAlignment: MainAxisAlignment.center,
      actionsPadding: const EdgeInsets.fromLTRB(24, 0, 24, 24),
      actions: [
        TextButton(
          onPressed: () => Navigator.of(context).pop(),
          child: const Text('Cancel'),
        ),
        const SizedBox(width: 16),
        // 3. Style the Run Test button to match the main screen
        ElevatedButton(
          style: ElevatedButton.styleFrom(
            foregroundColor: Colors.white,
            backgroundColor: const Color.fromARGB(255, 10, 150, 210),
            padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
          ),
          onPressed: _onRun,
          child: const Text('Run Test', style: TextStyle(fontSize: 16)),
        ),
      ],
    );
  }

  Widget _buildTableSection(
      String title, Map<String, TextEditingController> controllers) {
    return Padding(
      // 4. Adjust spacing for better visual layout
      padding: const EdgeInsets.only(bottom: 24.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            '${title[0].toUpperCase()}${title.substring(1)}',
            style: Theme.of(context).textTheme.titleLarge,
          ),
          const SizedBox(height: 16),
          if (controllers.containsKey('insert'))
            _buildOperationRow('Inserts', controllers['insert']!),
          if (controllers.containsKey('read'))
            _buildOperationRow('Reads', controllers['read']!),
          if (controllers.containsKey('update'))
            _buildOperationRow('Updates', controllers['update']!),
          if (controllers.containsKey('delete'))
            _buildOperationRow('Deletes', controllers['delete']!),
        ],
      ),
    );
  }

  Widget _buildOperationRow(String label, TextEditingController controller) {
    return Padding(
      // 4. Adjust spacing
      padding: const EdgeInsets.symmetric(vertical: 6.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Expanded(
            flex: 2,
            child: Text(label, style: const TextStyle(fontSize: 16)),
          ),
          // 4. Add space between label and field
          const SizedBox(width: 24),
          Expanded(
            flex: 3,
            child: TextFormField(
              controller: controller,
              keyboardType: TextInputType.number,
              inputFormatters: [FilteringTextInputFormatter.digitsOnly],
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                isDense: true,
                contentPadding:
                    EdgeInsets.symmetric(horizontal: 10, vertical: 8),
              ),
              validator: (value) {
                if (value == null || value.isEmpty) {
                  return 'Required';
                }
                if (int.tryParse(value) == null) {
                  return 'Invalid';
                }
                return null;
              },
            ),
          ),
        ],
      ),
    );
  }
}

enum InsertMethod { batch, oneByOne }

/// A dialog for adding a specific number of records.
class AddDataDialog extends StatefulWidget {
  final int defaultCount;
  final String tableName;
  final ToStore db;
  const AddDataDialog({
    super.key,
    required this.defaultCount,
    required this.tableName,
    required this.db,
  });

  @override
  State<AddDataDialog> createState() => _AddDataDialogState();
}

class _AddDataDialogState extends State<AddDataDialog> {
  late final TextEditingController _controller;
  InsertMethod _method = InsertMethod.batch;
  bool _isLoading = true;
  Map<String, List<Map<String, dynamic>>> _foreignKeyOptions =
      {}; // foreign key options for dropdown display (up to 100 records)
  final Map<String, dynamic> _selectedForeignKeyValues = {};
  Map<String, String> _foreignKeyFieldMap = {}; // fk_field -> referenced_table
  final Map<String, ForeignKeyMode> _foreignKeyModes = {}; // fk_field -> mode
  final Map<String, List<dynamic>> _foreignKeyIdLists =
      {}; // fk_field -> [id1, id2, ...] all IDs for random
  final Map<String, int> _foreignKeyTotalCounts =
      {}; // fk_field -> total number of records
  final Map<String, TextEditingController> _manualInputControllers =
      {}; // manual input controller
  final Map<String, bool> _useManualInput = {}; // whether to use manual input
  List<String> _missingForeignKeyTables =
      []; // records missing data in the main table

  @override
  void initState() {
    super.initState();
    _controller = TextEditingController(text: widget.defaultCount.toString());
    _loadForeignKeyData();
  }

  @override
  void dispose() {
    _controller.dispose();
    for (final controller in _manualInputControllers.values) {
      controller.dispose();
    }
    super.dispose();
  }

  Future<void> _loadForeignKeyData() async {
    try {
      final schema = await widget.db.getTableSchema(widget.tableName);
      if (schema == null || schema.foreignKeys.isEmpty) {
        setState(() {
          _isLoading = false;
        });
        return;
      }

      final Map<String, List<Map<String, dynamic>>> options = {};
      final Map<String, String> fieldMap = {};
      final List<String> missingTables = [];

      for (final fk in schema.foreignKeys) {
        if (!fk.enabled) continue;

        // First query the total number of records
        final totalCount = await widget.db.query(fk.referencedTable).count();

        if (totalCount == 0) {
          // The main table has no data, record it in the missing list
          missingTables.add(fk.referencedTable);
          continue;
        }

        // Query the first 100 records for dropdown display (performance optimization)
        final refTableResult = await widget.db
            .query(fk.referencedTable)
            .select([fk.referencedFields.first])
            .orderByAsc(fk.referencedFields.first)
            .limit(100);

        // Store option data (up to 100 records for dropdown)
        options[fk.fields.first] = refTableResult.data;
        fieldMap[fk.fields.first] = fk.referencedTable;
        _foreignKeyTotalCounts[fk.fields.first] = totalCount;

        // Extract all primary key values for random selection (need to query all data)
        // If the total number exceeds 1000, only query the first 1000 records for random (performance consideration)
        final maxForRandom = totalCount > 1000 ? 1000 : totalCount;
        final allIdsResult = await widget.db
            .query(fk.referencedTable)
            .select([fk.referencedFields.first])
            .orderByAsc(fk.referencedFields.first)
            .limit(maxForRandom);

        final idList = allIdsResult.data
            .map((row) => row[fk.referencedFields.first])
            .toList();
        _foreignKeyIdLists[fk.fields.first] = idList;

        // Initialize manual input controller
        _manualInputControllers[fk.fields.first] = TextEditingController();
        _useManualInput[fk.fields.first] = false;

        // Default select the first record, default mode is random
        if (refTableResult.data.isNotEmpty) {
          final pkValue = refTableResult.data.first[fk.referencedFields.first];
          _selectedForeignKeyValues[fk.fields.first] = pkValue;
          _foreignKeyModes[fk.fields.first] =
              ForeignKeyMode.random; // Default random mode
        }
      }

      setState(() {
        _foreignKeyOptions = options;
        _foreignKeyFieldMap = fieldMap;
        _missingForeignKeyTables = missingTables;
        _isLoading = false;
      });
    } catch (e) {
      logService.add('Error loading foreign key data: $e', LogLevel.error);
      setState(() {
        _isLoading = false;
      });
    }
  }

  void _onAdd() async {
    final count = int.tryParse(_controller.text);
    if (count != null && count > 0) {
      // Check if there are foreign keys but the main table has no data
      if (_missingForeignKeyTables.isNotEmpty) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text(
                'Cannot add: Tables "${_missingForeignKeyTables.join('", "')}" have no data, please add records first.'),
            backgroundColor: Colors.red,
            duration: const Duration(seconds: 3),
          ),
        );
        return;
      }

      // Process manual input values
      final finalForeignKeyValues =
          Map<String, dynamic>.from(_selectedForeignKeyValues);
      for (final entry in _useManualInput.entries) {
        if (entry.value) {
          // Use manual input values
          final controller = _manualInputControllers[entry.key];
          if (controller != null && controller.text.isNotEmpty) {
            final inputValue = controller.text.trim();
            // Try to convert to number (if the foreign key is a number type)
            final numValue = num.tryParse(inputValue);
            finalForeignKeyValues[entry.key] = numValue ?? inputValue;
          }
        }
      }

      Navigator.of(context).pop({
        'count': count,
        'method': _method,
        'foreignKeyValues': finalForeignKeyValues,
        'foreignKeyModes': _foreignKeyModes,
        'foreignKeyIdLists': _foreignKeyIdLists,
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: const Text('Add Test Data'),
      content: SingleChildScrollView(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            if (_isLoading)
              const Padding(
                padding: EdgeInsets.all(16.0),
                child: CircularProgressIndicator(),
              )
            else ...[
              // If there are missing main table data, display a warning
              if (_missingForeignKeyTables.isNotEmpty)
                Container(
                  padding: const EdgeInsets.all(12.0),
                  margin: const EdgeInsets.only(bottom: 16.0),
                  decoration: BoxDecoration(
                    color: Colors.orange.shade50,
                    border: Border.all(color: Colors.orange.shade300),
                    borderRadius: BorderRadius.circular(8),
                  ),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Row(
                        children: [
                          Icon(Icons.warning_amber_rounded,
                              color: Colors.orange.shade700, size: 20),
                          const SizedBox(width: 8),
                          Text(
                            'Missing main table data',
                            style: TextStyle(
                                fontWeight: FontWeight.bold,
                                color: Colors.orange.shade700),
                          ),
                        ],
                      ),
                      const SizedBox(height: 8),
                      Text(
                        'The following tables have no data, please add first:\n${_missingForeignKeyTables.map((t) => '• $t').join('\n')}',
                        style: TextStyle(color: Colors.orange.shade700),
                      ),
                    ],
                  ),
                ),
              TextField(
                controller: _controller,
                autofocus: true,
                keyboardType: TextInputType.number,
                inputFormatters: [FilteringTextInputFormatter.digitsOnly],
                decoration: const InputDecoration(
                  labelText: 'Number of records to add',
                  border: OutlineInputBorder(),
                ),
              ),
              const SizedBox(height: 20),
              // Display foreign key selector
              ..._foreignKeyOptions.entries.map((entry) {
                final fkField = entry.key;
                final options = entry.value;
                final refTable = _foreignKeyFieldMap[fkField] ?? '';
                final selectedValue = _selectedForeignKeyValues[fkField];
                final mode = _foreignKeyModes[fkField] ?? ForeignKeyMode.random;
                final totalCount = _foreignKeyTotalCounts[fkField] ?? 0;
                final displayCount = options.length;
                final useManual = _useManualInput[fkField] ?? false;

                return Padding(
                  padding: const EdgeInsets.only(bottom: 16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Row(
                        children: [
                          Expanded(
                            child: Text(
                              '$fkField (from $refTable)',
                              style: const TextStyle(
                                fontWeight: FontWeight.bold,
                                fontSize: 14,
                              ),
                            ),
                          ),
                          Text(
                            totalCount > displayCount
                                ? '($displayCount/$totalCount records)'
                                : '($totalCount records)',
                            style: TextStyle(
                              fontSize: 12,
                              color: Colors.grey.shade600,
                            ),
                          ),
                        ],
                      ),
                      const SizedBox(height: 8),
                      // Mode selection
                      RadioGroup<ForeignKeyMode>(
                        groupValue: mode,
                        onChanged: (value) {
                          setState(() {
                            _foreignKeyModes[fkField] = value!;
                          });
                        },
                        child: const Row(
                          children: [
                            Expanded(
                              child: RadioListTile<ForeignKeyMode>(
                                title: Text('Fixed value'),
                                value: ForeignKeyMode.fixed,
                                dense: true,
                                contentPadding: EdgeInsets.zero,
                              ),
                            ),
                            Expanded(
                              child: RadioListTile<ForeignKeyMode>(
                                title: Text('Random value'),
                                value: ForeignKeyMode.random,
                                dense: true,
                                contentPadding: EdgeInsets.zero,
                              ),
                            ),
                          ],
                        ),
                      ),
                      // Fixed value mode display dropdown or manual input
                      if (mode == ForeignKeyMode.fixed) ...[
                        // Select input method
                        RadioGroup<bool>(
                          groupValue: useManual,
                          onChanged: (value) {
                            setState(() {
                              _useManualInput[fkField] = value!;
                            });
                          },
                          child: const Row(
                            children: [
                              Expanded(
                                child: RadioListTile<bool>(
                                  title: Text('Dropdown selection'),
                                  value: false,
                                  dense: true,
                                  contentPadding: EdgeInsets.zero,
                                ),
                              ),
                              Expanded(
                                child: RadioListTile<bool>(
                                  title: Text('Manual input'),
                                  value: true,
                                  dense: true,
                                  contentPadding: EdgeInsets.zero,
                                ),
                              ),
                            ],
                          ),
                        ),
                        const SizedBox(height: 8),
                        if (!useManual)
                          DropdownButtonFormField<dynamic>(
                            initialValue: selectedValue,
                            decoration: InputDecoration(
                              labelText: 'Select foreign key value',
                              border: const OutlineInputBorder(),
                              isDense: true,
                              contentPadding: const EdgeInsets.symmetric(
                                  horizontal: 12, vertical: 8),
                              helperText: totalCount > displayCount
                                  ? 'Only display the first $displayCount records, total $totalCount records'
                                  : null,
                            ),
                            items: options.map((option) {
                              final pkValue = option.values.first;
                              return DropdownMenuItem<dynamic>(
                                value: pkValue,
                                child: Text('$pkValue'),
                              );
                            }).toList(),
                            onChanged: (value) {
                              setState(() {
                                _selectedForeignKeyValues[fkField] = value;
                              });
                            },
                          )
                        else
                          TextField(
                            controller: _manualInputControllers[fkField],
                            decoration: InputDecoration(
                              labelText: 'Manual input foreign key value',
                              border: const OutlineInputBorder(),
                              isDense: true,
                              contentPadding: const EdgeInsets.symmetric(
                                  horizontal: 12, vertical: 8),
                              helperText: 'Enter valid $refTable table ID',
                              hintText: 'For example: 1, 2, 100',
                            ),
                            keyboardType: TextInputType.number,
                            onChanged: (value) {
                              // Real-time update value
                              if (value.isNotEmpty) {
                                final numValue = num.tryParse(value);
                                if (numValue != null) {
                                  _selectedForeignKeyValues[fkField] = numValue;
                                } else {
                                  _selectedForeignKeyValues[fkField] = value;
                                }
                              }
                            },
                          ),
                      ] else
                        Container(
                          padding: const EdgeInsets.all(12.0),
                          decoration: BoxDecoration(
                            color: Colors.blue.shade50,
                            border: Border.all(color: Colors.blue.shade200),
                            borderRadius: BorderRadius.circular(4),
                          ),
                          child: Row(
                            children: [
                              Icon(Icons.shuffle,
                                  size: 16, color: Colors.blue.shade700),
                              const SizedBox(width: 8),
                              Expanded(
                                child: Text(
                                  totalCount >
                                          (_foreignKeyIdLists[fkField]
                                                  ?.length ??
                                              0)
                                      ? 'Will randomly select from ${_foreignKeyIdLists[fkField]?.length ?? 0} records (total $totalCount records)'
                                      : 'Will randomly select from $totalCount records',
                                  style: TextStyle(
                                    fontSize: 12,
                                    color: Colors.blue.shade700,
                                  ),
                                ),
                              ),
                            ],
                          ),
                        ),
                    ],
                  ),
                );
              }),
              const SizedBox(height: 20),
              const Text('Insertion Method'),
              RadioGroup<InsertMethod>(
                groupValue: _method,
                onChanged: (value) {
                  setState(() {
                    _method = value!;
                  });
                },
                child: const Column(
                  children: [
                    RadioListTile<InsertMethod>(
                      title: Text('Batch Insert'),
                      value: InsertMethod.batch,
                    ),
                    RadioListTile<InsertMethod>(
                      title: Text('Insert One by One'),
                      value: InsertMethod.oneByOne,
                    ),
                  ],
                ),
              ),
            ],
          ],
        ),
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.of(context).pop(),
          child: const Text('Cancel'),
        ),
        ElevatedButton(
          onPressed: _isLoading ? null : _onAdd,
          child: const Text('Add'),
        ),
      ],
    );
  }
}

/// A dialog for editing a single row of data.
class EditRowDialog extends StatefulWidget {
  final TableSchema schema;
  final Map<String, dynamic> initialData;

  const EditRowDialog(
      {super.key, required this.schema, required this.initialData});

  @override
  State<EditRowDialog> createState() => _EditRowDialogState();
}

class _EditRowDialogState extends State<EditRowDialog> {
  final _formKey = GlobalKey<FormState>();
  late Map<String, TextEditingController> _controllers;
  late Map<String, dynamic> _updatedData;

  @override
  void initState() {
    super.initState();
    _updatedData = Map.from(widget.initialData);

    // Initialize controllers for all fields defined in the schema
    _controllers = {
      for (var field in widget.schema.fields)
        field.name: TextEditingController(
            text: '${widget.initialData[field.name] ?? ''}'),
    };

    // Also add a controller for the primary key, which will be read-only
    final pkName = widget.schema.primaryKeyConfig.name;
    if (!_controllers.containsKey(pkName) &&
        widget.initialData.containsKey(pkName)) {
      _controllers[pkName] =
          TextEditingController(text: '${widget.initialData[pkName]}');
    }
  }

  @override
  void dispose() {
    for (var controller in _controllers.values) {
      controller.dispose();
    }
    super.dispose();
  }

  void _onSave() {
    if (_formKey.currentState!.validate()) {
      _formKey.currentState!.save();
      Navigator.of(context).pop(_updatedData);
    }
  }

  dynamic _convertValue(String? value, DataType type) {
    if (value == null || value.isEmpty || value.toLowerCase() == 'null') {
      return null;
    }
    switch (type) {
      case DataType.integer:
        return int.tryParse(value);
      case DataType.double:
        return double.tryParse(value);
      case DataType.boolean:
        return value.toLowerCase() == 'true' || value == '1';
      default:
        return value;
    }
  }

  @override
  Widget build(BuildContext context) {
    final pkName = widget.schema.primaryKeyConfig.name;

    return AlertDialog(
      title: Text('Edit Record: ${widget.initialData[pkName]}'),
      content: Form(
        key: _formKey,
        child: SingleChildScrollView(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              // Display the primary key as read-only if it exists
              if (_controllers.containsKey(pkName))
                Padding(
                  padding: const EdgeInsets.symmetric(vertical: 8.0),
                  child: TextFormField(
                    controller: _controllers[pkName],
                    readOnly: true,
                    decoration: InputDecoration(
                      labelText: '$pkName (Primary Key)',
                      border: const OutlineInputBorder(),
                      filled: true,
                      fillColor: Colors.grey.shade200,
                    ),
                  ),
                ),
              // Editable fields from schema
              ...widget.schema.fields.map((field) {
                // Don't show the primary key again if it's also listed in fields
                if (field.name == pkName) return const SizedBox.shrink();

                return Padding(
                  padding: const EdgeInsets.symmetric(vertical: 8.0),
                  child: TextFormField(
                    controller: _controllers[field.name],
                    decoration: InputDecoration(
                      labelText: field.name,
                      border: const OutlineInputBorder(),
                    ),
                    validator: (value) {
                      if (!field.nullable && (value == null || value.isEmpty)) {
                        return 'This field cannot be empty.';
                      }
                      return null;
                    },
                    onSaved: (newValue) {
                      _updatedData[field.name] =
                          _convertValue(newValue, field.type);
                    },
                  ),
                );
              }),
            ],
          ),
        ),
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.of(context).pop(),
          child: const Text('Cancel'),
        ),
        ElevatedButton(
          onPressed: _onSave,
          child: const Text('Save'),
        ),
      ],
    );
  }
}

class BatchUpdateDialog extends StatefulWidget {
  final TableSchema schema;
  const BatchUpdateDialog({super.key, required this.schema});

  @override
  State<BatchUpdateDialog> createState() => _BatchUpdateDialogState();
}

class _BatchUpdateDialogState extends State<BatchUpdateDialog> {
  final _formKey = GlobalKey<FormState>();
  String? _selectedField;
  final _valueController = TextEditingController();
  late final List<FieldSchema> _updatableFields;

  @override
  void initState() {
    super.initState();
    // Exclude primary key and unique fields from batch updates
    final pkName = widget.schema.primaryKeyConfig.name;
    _updatableFields = widget.schema.fields
        .where((f) => f.name != pkName && !f.unique)
        .toList();
    if (_updatableFields.isNotEmpty) {
      _selectedField = _updatableFields.first.name;
    }
  }

  @override
  void dispose() {
    _valueController.dispose();
    super.dispose();
  }

  void _onSave() {
    if (_formKey.currentState!.validate() && _selectedField != null) {
      final field =
          _updatableFields.firstWhere((f) => f.name == _selectedField);
      final value = _convertValue(_valueController.text, field.type);
      Navigator.of(context).pop({'field': _selectedField, 'value': value});
    }
  }

  dynamic _convertValue(String? value, DataType type) {
    if (value == null || value.isEmpty || value.toLowerCase() == 'null') {
      return null;
    }
    switch (type) {
      case DataType.integer:
        return int.tryParse(value);
      case DataType.double:
        return double.tryParse(value);
      case DataType.boolean:
        return value.toLowerCase() == 'true' || value == '1';
      default:
        return value;
    }
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: const Text('Batch Update Selected'),
      content: _updatableFields.isEmpty
          ? const Text(
              'No updatable (non-unique) fields available for this table.')
          : Form(
              key: _formKey,
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  DropdownButtonFormField<String>(
                    initialValue: _selectedField,
                    items: _updatableFields.map((field) {
                      return DropdownMenuItem(
                        value: field.name,
                        child: Text(field.name),
                      );
                    }).toList(),
                    onChanged: (value) {
                      if (value != null) {
                        setState(() {
                          _selectedField = value;
                        });
                      }
                    },
                    decoration: const InputDecoration(
                      labelText: 'Field to Update',
                      border: OutlineInputBorder(),
                    ),
                  ),
                  const SizedBox(height: 16),
                  TextFormField(
                    controller: _valueController,
                    decoration: const InputDecoration(
                      labelText: 'New Value',
                      hintText: 'Enter the new value for all selected rows',
                      border: OutlineInputBorder(),
                    ),
                    validator: (value) {
                      if (_selectedField == null) return null;
                      final field = _updatableFields
                          .firstWhere((f) => f.name == _selectedField);
                      if (!field.nullable && (value == null || value.isEmpty)) {
                        return 'This field cannot be empty.';
                      }
                      return null;
                    },
                  )
                ],
              ),
            ),
      actions: [
        TextButton(
          onPressed: () => Navigator.of(context).pop(),
          child: const Text('Cancel'),
        ),
        ElevatedButton(
          onPressed: _updatableFields.isEmpty ? null : _onSave,
          child: const Text('Update All'),
        ),
      ],
    );
  }
}

class CustomDeleteDialog extends StatefulWidget {
  final TableSchema schema;

  const CustomDeleteDialog({super.key, required this.schema});

  @override
  State<CustomDeleteDialog> createState() => _CustomDeleteDialogState();
}

class _CustomDeleteDialogState extends State<CustomDeleteDialog> {
  final _formKey = GlobalKey<FormState>();
  String? _selectedField;
  String _selectedOperator = '>';
  final _valueController = TextEditingController();

  @override
  void initState() {
    super.initState();
    _selectedField = widget.schema.primaryKeyConfig.name;
  }

  @override
  void dispose() {
    _valueController.dispose();
    super.dispose();
  }

  void _onConfirm() {
    if (_formKey.currentState!.validate()) {
      final fieldSchema = _getSelectedFieldSchema();
      if (fieldSchema == null) return;

      final convertedValue =
          _convertValue(_valueController.text, fieldSchema.type);

      Navigator.of(context).pop({
        'field': _selectedField,
        'operator': _selectedOperator,
        'value': convertedValue,
      });
    }
  }

  FieldSchema? _getSelectedFieldSchema() {
    if (_selectedField == widget.schema.primaryKeyConfig.name) {
      return FieldSchema(
        name: _selectedField!,
        type: widget.schema.primaryKeyConfig.getDefaultDataType(),
      );
    }
    return widget.schema.fields.firstWhere((f) => f.name == _selectedField);
  }

  dynamic _convertValue(String? value, DataType type) {
    if (value == null || value.isEmpty || value.toLowerCase() == 'null') {
      return null;
    }
    switch (type) {
      case DataType.integer:
        return int.tryParse(value);
      case DataType.double:
        return double.tryParse(value);
      case DataType.boolean:
        return value.toLowerCase() == 'true' || value == '1';
      default:
        return value;
    }
  }

  @override
  Widget build(BuildContext context) {
    final allFields = [
      widget.schema.primaryKeyConfig.name,
      ...widget.schema.fields.map((f) => f.name)
    ];

    final selectedFieldSchema = _getSelectedFieldSchema();
    final isNumeric = selectedFieldSchema?.type == DataType.integer ||
        selectedFieldSchema?.type == DataType.double;

    return AlertDialog(
      title: const Text('Custom Delete'),
      content: Form(
        key: _formKey,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Delete records based on the following condition:'),
            const SizedBox(height: 24),
            Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Expanded(
                  flex: 4,
                  child: DropdownButtonFormField<String>(
                    initialValue: _selectedField,
                    items: allFields
                        .map((field) =>
                            DropdownMenuItem(value: field, child: Text(field)))
                        .toList(),
                    onChanged: (value) {
                      if (value != null) {
                        setState(() {
                          _selectedField = value;
                          // Reset value when field changes
                          _valueController.clear();
                        });
                      }
                    },
                    decoration: const InputDecoration(
                      labelText: 'Field',
                      border: OutlineInputBorder(),
                    ),
                  ),
                ),
                const SizedBox(width: 8),
                Expanded(
                  flex: 3,
                  child: DropdownButtonFormField<String>(
                    initialValue: _selectedOperator,
                    items: ['>', '>=', '<', '<=', '=', '!=', 'LIKE']
                        .map((op) =>
                            DropdownMenuItem(value: op, child: Text(op)))
                        .toList(),
                    onChanged: (value) {
                      if (value != null) {
                        setState(() {
                          _selectedOperator = value;
                        });
                      }
                    },
                    decoration: const InputDecoration(
                      border: OutlineInputBorder(),
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 16),
            TextFormField(
              controller: _valueController,
              autofocus: true,
              keyboardType:
                  isNumeric ? TextInputType.number : TextInputType.text,
              inputFormatters:
                  isNumeric ? [FilteringTextInputFormatter.digitsOnly] : [],
              decoration: const InputDecoration(
                labelText: 'Value',
                border: OutlineInputBorder(),
              ),
              validator: (value) {
                if (value == null || value.isEmpty) {
                  return 'Required';
                }
                if (isNumeric && int.tryParse(value) == null) {
                  return 'Invalid number';
                }
                // Add more validation for other types if needed
                return null;
              },
            ),
          ],
        ),
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.of(context).pop(),
          child: const Text('Cancel'),
        ),
        ElevatedButton(
          onPressed: _onConfirm,
          style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
          child: const Text('Delete', style: TextStyle(color: Colors.white)),
        ),
      ],
    );
  }
}

class FilterDialog extends StatefulWidget {
  final TableSchema schema;
  final List<Map<String, dynamic>> existingFilters;

  const FilterDialog(
      {super.key, required this.schema, required this.existingFilters});

  @override
  State<FilterDialog> createState() => _FilterDialogState();
}

class _FilterDialogState extends State<FilterDialog> {
  late List<_FilterCondition> _filters;
  final _formKey = GlobalKey<FormState>();

  @override
  void initState() {
    super.initState();
    _filters = widget.existingFilters.map((f) {
      return _FilterCondition(
        field: f['field'],
        operator: f['operator'],
        valueController: TextEditingController(text: '${f['value']}'),
      );
    }).toList();

    if (_filters.isEmpty) {
      _filters.add(
        _FilterCondition(
          field: _getAvailableFields().first,
          operator: '=',
          valueController: TextEditingController(),
        ),
      );
    }
  }

  @override
  void dispose() {
    for (final filter in _filters) {
      filter.valueController.dispose();
    }
    super.dispose();
  }

  void _addFilter() {
    setState(() {
      _filters.add(_FilterCondition(
        field: _getAvailableFields().first,
        operator: '=',
        valueController: TextEditingController(),
      ));
    });
  }

  void _removeFilter(int index) {
    setState(() {
      _filters.removeAt(index);
    });
  }

  List<String> _getAvailableFields() {
    final pkName = widget.schema.primaryKeyConfig.name;
    final fieldNames = widget.schema.fields.map((f) => f.name).toSet();
    fieldNames.add(pkName);
    return fieldNames.toList()..sort();
  }

  void _onApply() {
    if (_formKey.currentState!.validate()) {
      final newFilters = _filters.map((f) {
        final fieldSchema = _getFieldSchema(f.field);
        final raw = f.valueController.text;
        // LIKE / startsWith patterns must stay strings (e.g. "123%", "user_2@...").
        // Never int.tryParse them — that turns "123%" into null for integer PKs.
        final dynamic value;
        if (f.operator == 'LIKE' ||
            f.operator == 'startsWith' ||
            f.operator == 'prefix') {
          value = raw;
        } else {
          value = _convertValue(raw, fieldSchema?.type ?? DataType.text);
        }
        return {
          'field': f.field,
          'operator': f.operator,
          'value': value,
        };
      }).toList();
      Navigator.of(context).pop(newFilters);
    }
  }

  FieldSchema? _getFieldSchema(String fieldName) {
    if (fieldName == widget.schema.primaryKeyConfig.name) {
      // PK storage type is text for all PrimaryKeyType variants in the engine.
      return FieldSchema(
        name: fieldName,
        type: widget.schema.primaryKeyConfig.getDefaultDataType(),
      );
    }
    try {
      return widget.schema.fields.firstWhere((f) => f.name == fieldName);
    } catch (_) {
      return null;
    }
  }

  dynamic _convertValue(String? value, DataType type) {
    if (value == null || value.isEmpty || value.toLowerCase() == 'null') {
      return null;
    }
    switch (type) {
      case DataType.integer:
        return int.tryParse(value);
      case DataType.double:
        return double.tryParse(value);
      case DataType.boolean:
        return value.toLowerCase() == 'true' || value == '1';
      default:
        return value;
    }
  }

  @override
  Widget build(BuildContext context) {
    final availableFields = _getAvailableFields();
    return AlertDialog(
      title: const Text('Set Filter Conditions'),
      content: Form(
        key: _formKey,
        child: SizedBox(
          width: double.maxFinite,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Expanded(
                child: _filters.isEmpty
                    ? const Center(
                        child: Text('No filters. Add one below.'),
                      )
                    : ListView.builder(
                        shrinkWrap: true,
                        itemCount: _filters.length,
                        itemBuilder: (context, index) {
                          final filter = _filters[index];
                          return _buildFilterRow(
                              filter, index, availableFields);
                        },
                      ),
              ),
              const SizedBox(height: 16),
              ElevatedButton.icon(
                onPressed: _addFilter,
                icon: const Icon(Icons.add),
                label: const Text('Add Condition'),
              ),
            ],
          ),
        ),
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.of(context).pop(),
          child: const Text('Cancel'),
        ),
        ElevatedButton(
          onPressed: _onApply,
          child: const Text('Apply Filters'),
        ),
      ],
    );
  }

  Widget _buildFilterRow(
      _FilterCondition filter, int index, List<String> availableFields) {
    return Padding(
      padding: const EdgeInsets.symmetric(
        vertical: 8.0,
      ),
      child: Column(
        children: [
          Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Expanded(
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Expanded(
                      flex: 5,
                      child: DropdownButtonFormField<String>(
                        initialValue: filter.field,
                        items: availableFields
                            .map((f) =>
                                DropdownMenuItem(value: f, child: Text(f)))
                            .toList(),
                        onChanged: (value) {
                          if (value != null) {
                            setState(() {
                              filter.field = value;
                            });
                          }
                        },
                        decoration: const InputDecoration(
                            border: OutlineInputBorder(), labelText: 'Field'),
                      ),
                    ),
                    const SizedBox(width: 8),
                    Expanded(
                      flex: 3,
                      child: DropdownButtonFormField<String>(
                        initialValue: filter.operator,
                        items: [
                          '=',
                          '!=',
                          '>',
                          '>=',
                          '<',
                          '<=',
                          'LIKE',
                          'startsWith',
                        ]
                            .map((op) =>
                                DropdownMenuItem(value: op, child: Text(op)))
                            .toList(),
                        onChanged: (value) {
                          if (value != null) {
                            setState(() {
                              filter.operator = value;
                            });
                          }
                        },
                        decoration:
                            const InputDecoration(border: OutlineInputBorder()),
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
          const SizedBox(height: 8),
          Row(
            children: [
              Expanded(
                flex: 5,
                child: TextFormField(
                  controller: filter.valueController,
                  decoration: InputDecoration(
                    border: const OutlineInputBorder(),
                    labelText: 'Value',
                    helperText: filter.operator == 'startsWith'
                        ? 'Literal prefix (no % needed; _ is literal)'
                        : filter.operator == 'LIKE'
                            ? r'SQL LIKE: escape _/% as \_ \%'
                            : null,
                    helperMaxLines: 2,
                  ),
                  validator: (value) {
                    if (value == null || value.isEmpty) {
                      return 'Required';
                    }
                    return null;
                  },
                ),
              ),
              IconButton(
                icon:
                    const Icon(Icons.remove_circle_outline, color: Colors.red),
                onPressed: () => _removeFilter(index),
              )
            ],
          ),
        ],
      ),
    );
  }
}

class _FilterCondition {
  String field;
  String operator;
  TextEditingController valueController;

  _FilterCondition({
    required this.field,
    required this.operator,
    required this.valueController,
  });
}

class VectorSearchDialog extends StatefulWidget {
  const VectorSearchDialog({super.key});

  @override
  State<VectorSearchDialog> createState() => _VectorSearchDialogState();
}

class _VectorSearchDialogState extends State<VectorSearchDialog> {
  // Presets aligned to recall-intent mapping (depth → ~90–100%).
  static const int _depthFast = 30; // ~93%
  static const int _depthBalanced = 50; // ~95% production baseline
  static const int _depthDeep = 80; // ~98%

  int _iterations = 1;
  int _topK = 10;
  int _searchDepth = _depthBalanced;
  final _customController = TextEditingController(text: '1');
  final _depthController = TextEditingController(text: '$_depthBalanced');

  @override
  void dispose() {
    _customController.dispose();
    _depthController.dispose();
    super.dispose();
  }

  void _setSearchDepth(int depth) {
    final clamped = depth.clamp(1, 100);
    setState(() {
      _searchDepth = clamped;
      _depthController.text = clamped.toString();
    });
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: const Row(
        children: [
          Icon(Icons.query_stats, color: Color(0xff0aa6e8)),
          SizedBox(width: 10),
          Expanded(
            child: Text(
              'Vector Search Benchmark',
              overflow: TextOverflow.ellipsis,
            ),
          ),
        ],
      ),
      content: SingleChildScrollView(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Search Config',
                style: TextStyle(fontWeight: FontWeight.bold)),
            const SizedBox(height: 16),
            const Text('Top-K (Number of neighbors):'),
            Slider(
              value: _topK.toDouble(),
              min: 1,
              max: 100,
              divisions: 99,
              label: _topK.toString(),
              activeColor: const Color(0xff0aa6e8),
              onChanged: (v) => setState(() => _topK = v.toInt()),
            ),
            Center(child: Text('$_topK results per search')),
            const SizedBox(height: 24),
            const Text('Search Depth (1–100):',
                style: TextStyle(fontWeight: FontWeight.bold)),
            const SizedBox(height: 8),
            Wrap(
              spacing: 8,
              children: [
                (_depthFast, 'Fast'),
                (_depthBalanced, 'Balanced'),
                (_depthDeep, 'Deep'),
              ].map((preset) {
                final depth = preset.$1;
                final label = preset.$2;
                final isSelected = _searchDepth == depth;
                return ChoiceChip(
                  label: Text('$label ($depth)'),
                  selected: isSelected,
                  selectedColor: const Color(0xff0aa6e8),
                  checkmarkColor: Colors.white,
                  labelStyle: TextStyle(
                    color: isSelected ? Colors.white : Colors.black,
                  ),
                  onSelected: (selected) {
                    if (selected) _setSearchDepth(depth);
                  },
                );
              }).toList(),
            ),
            const SizedBox(height: 12),
            TextField(
              controller: _depthController,
              keyboardType: TextInputType.number,
              decoration: const InputDecoration(
                labelText: 'Custom Search Depth',
                border: OutlineInputBorder(),
                prefixIcon: Icon(Icons.layers),
                helperText:
                    'Higher ≈ better recall intent + more latency (not recall%)',
              ),
              onChanged: (v) {
                final val = int.tryParse(v);
                if (val != null && val >= 1 && val <= 100) {
                  setState(() => _searchDepth = val);
                }
              },
            ),
            const SizedBox(height: 24),
            const Text('Iterations:',
                style: TextStyle(fontWeight: FontWeight.bold)),
            const SizedBox(height: 8),
            Wrap(
              spacing: 8,
              children: [1, 100, 1000, 10000].map((count) {
                final isSelected = _iterations == count;
                return ChoiceChip(
                  label: Text(count == 1 ? 'Single' : count.toString()),
                  selected: isSelected,
                  selectedColor: const Color(0xff0aa6e8),
                  checkmarkColor: Colors.white,
                  labelStyle: TextStyle(
                    color: isSelected ? Colors.white : Colors.black,
                  ),
                  onSelected: (selected) {
                    if (selected) {
                      setState(() {
                        _iterations = count;
                        _customController.text = count.toString();
                      });
                    }
                  },
                );
              }).toList(),
            ),
            const SizedBox(height: 16),
            TextField(
              controller: _customController,
              keyboardType: TextInputType.number,
              decoration: const InputDecoration(
                labelText: 'Custom Iterations',
                border: OutlineInputBorder(),
                prefixIcon: Icon(Icons.repeat),
              ),
              onChanged: (v) {
                final val = int.tryParse(v);
                if (val != null && val > 0) {
                  setState(() => _iterations = val);
                }
              },
            ),
            const SizedBox(height: 16),
            const Text(
              'Total searches to perform. Results will be averaged to measure latency.',
              style: TextStyle(fontSize: 12, color: Colors.grey),
            ),
          ],
        ),
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.of(context).pop(),
          child: const Text('Cancel'),
        ),
        ElevatedButton(
          onPressed: () {
            final parsedDepth = int.tryParse(_depthController.text.trim());
            final depth = (parsedDepth ?? _searchDepth).clamp(1, 100);
            Navigator.of(context).pop({
              'iterations': _iterations,
              'topK': _topK,
              'searchDepth': depth,
            });
          },
          style: ElevatedButton.styleFrom(
            backgroundColor: const Color(0xff0aa6e8),
            foregroundColor: Colors.white,
          ),
          child: const Text('Start Benchmark'),
        ),
      ],
    );
  }
}

/// Pseudo table labels for the system key-value store (not real table names).
/// Listing uses [KvStore.getKeys]/[KvStore.get] because system tables cannot
/// be queried via [ToStore.query].
const String _kKvSpaceLabel = 'KV (space)';
const String _kKvGlobalLabel = 'KV (global)';
const String _kKvDefaultKeyPrefix = 'demo_kv_';

/// Fixed-width numeric suffix so key DESC order matches numeric max.
const int _kKvBatchIndexWidth = 8;

String _kvBatchIndexPart(int index) =>
    index.toString().padLeft(_kKvBatchIndexWidth, '0');

String _kvBatchKey(String prefix, int index) =>
    '$prefix${_kvBatchIndexPart(index)}';

dynamic _parseKvInputValue(String raw) {
  final trimmed = raw.trim();
  if (trimmed.isEmpty) return '';
  try {
    return jsonDecode(trimmed);
  } catch (_) {
    return raw;
  }
}

String _formatKvDisplayValue(dynamic value) {
  if (value == null) return 'null';
  if (value is String) return value;
  try {
    return jsonEncode(value);
  } catch (_) {
    return value.toString();
  }
}
141
likes
160
points
851k
downloads

Documentation

Documentation
API reference

Publisher

verified publishertoway.world

Weekly Downloads

Fast distributed AI vector database and persistent local storage engine. High-performance key-value store supporting SQL, NoSQL, offline cache and encrypted data.

Repository (GitHub)
View/report issues
Contributing

Topics

#database #storage #vector-database #sql #key-value

License

Apache-2.0 (license)

Dependencies

archive, ffi, path, web

More

Packages that depend on tostore