import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { ResultsView } from '../ResultsView';

// Mock react-syntax-highlighter
vi.mock('react-syntax-highlighter', () => {
  const MockLight = ({ children }) => (
    <pre data-testid="syntax-highlighter">{children}</pre>
  );
  MockLight.registerLanguage = vi.fn();
  return { Light: MockLight };
});
vi.mock('react-syntax-highlighter/src/styles/hljs', () => ({
  foundation: {},
}));
vi.mock('react-syntax-highlighter/dist/esm/languages/hljs/sql', () => ({
  default: () => {},
}));

// Mock recharts to avoid canvas rendering issues in jsdom.
// YAxis calls tickFormatter with sample values (covering the formatYAxis helper).
vi.mock('recharts', async () => {
  const React = await vi.importActual('react');
  const mockComponent =
    name =>
    ({ children, ...props }) =>
      React.createElement('div', { 'data-testid': name, ...props }, children);

  // YAxis: call tickFormatter with a spread of magnitudes so formatYAxis branches are hit
  const MockYAxis = ({ children, tickFormatter, ...props }) => {
    if (tickFormatter) {
      // Exercise all four branches of formatYAxis
      tickFormatter(1_500_000_000); // >=1B
      tickFormatter(2_500_000); // >=1M
      tickFormatter(5_000); // >=1K
      tickFormatter(42); // plain
    }
    return React.createElement(
      'div',
      { 'data-testid': 'YAxis', ...props },
      children,
    );
  };

  return {
    LineChart: mockComponent('LineChart'),
    BarChart: mockComponent('BarChart'),
    Line: mockComponent('Line'),
    Bar: mockComponent('Bar'),
    XAxis: mockComponent('XAxis'),
    YAxis: MockYAxis,
    CartesianGrid: mockComponent('CartesianGrid'),
    Tooltip: mockComponent('Tooltip'),
    ResponsiveContainer: ({ children }) =>
      React.createElement(
        'div',
        { 'data-testid': 'ResponsiveContainer' },
        children,
      ),
  };
});

// Mock clipboard API
const mockWriteText = vi.fn();
Object.assign(navigator, {
  clipboard: {
    writeText: mockWriteText,
  },
});

describe('ResultsView', () => {
  const defaultProps = {
    sql: 'SELECT * FROM table',
    results: {
      results: [
        {
          columns: [
            { name: 'id', type: 'INT' },
            { name: 'name', type: 'STRING' },
          ],
          rows: [
            [1, 'Alice'],
            [2, 'Bob'],
          ],
        },
      ],
    },
    loading: false,
    error: null,
    elapsedTime: 1.5,
    onBackToPlan: vi.fn(),
    selectedMetrics: ['metric1', 'metric2'],
    selectedDimensions: ['dim1'],
    filters: [],
    dialect: 'SPARK',
    cubeName: null,
    availability: null,
  };

  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('Header', () => {
    it('renders back to plan button', () => {
      render(<ResultsView {...defaultProps} />);
      expect(screen.getByText('Back to Plan')).toBeInTheDocument();
    });

    it('calls onBackToPlan when back button is clicked', () => {
      const onBackToPlan = vi.fn();
      render(<ResultsView {...defaultProps} onBackToPlan={onBackToPlan} />);

      fireEvent.click(screen.getByText('Back to Plan'));
      expect(onBackToPlan).toHaveBeenCalled();
    });

    it('shows row count and elapsed time', () => {
      render(<ResultsView {...defaultProps} />);
      // Row count appears in both header and table section
      expect(screen.getAllByText('2 rows').length).toBeGreaterThanOrEqual(1);
      expect(screen.getByText('1.50s')).toBeInTheDocument();
    });

    it('shows loading state', () => {
      render(<ResultsView {...defaultProps} loading={true} />);
      expect(screen.getByText('Running query...')).toBeInTheDocument();
    });

    it('shows error state in header', () => {
      render(<ResultsView {...defaultProps} error="Query timeout" />);
      expect(screen.getByText('Query failed')).toBeInTheDocument();
    });

    it('handles null elapsedTime', () => {
      render(<ResultsView {...defaultProps} elapsedTime={null} />);
      expect(screen.getAllByText('2 rows').length).toBeGreaterThanOrEqual(1);
      // Should not show elapsed time when null
      expect(screen.queryByText(/^\d+\.\d+s$/)).not.toBeInTheDocument();
    });
  });

  describe('SQL Pane', () => {
    it('displays SQL query', () => {
      render(<ResultsView {...defaultProps} />);
      expect(screen.getByText('SELECT * FROM table')).toBeInTheDocument();
    });

    it('shows SQL Query title', () => {
      render(<ResultsView {...defaultProps} />);
      expect(screen.getByText('SQL Query')).toBeInTheDocument();
    });

    it('shows generating message when no SQL', () => {
      render(<ResultsView {...defaultProps} sql={null} />);
      expect(screen.getByText('Generating SQL...')).toBeInTheDocument();
    });

    it('renders copy button', () => {
      render(<ResultsView {...defaultProps} />);
      expect(screen.getByText('Copy')).toBeInTheDocument();
    });

    it('copies SQL to clipboard when copy button clicked', async () => {
      render(<ResultsView {...defaultProps} />);

      fireEvent.click(screen.getByText('Copy'));

      expect(mockWriteText).toHaveBeenCalledWith('SELECT * FROM table');
      expect(screen.getByText('✓ Copied')).toBeInTheDocument();
    });

    it('disables copy button when no SQL', () => {
      render(<ResultsView {...defaultProps} sql={null} />);
      expect(screen.getByText('Copy')).toBeDisabled();
    });

    it('shows materialization info when cubeName is provided', () => {
      render(
        <ResultsView
          {...defaultProps}
          cubeName="test_cube"
          availability={{
            catalog: 'catalog',
            schema_: 'schema',
            table: 'table',
            validThroughTs: 1705363200000, // Jan 16, 2024
          }}
        />,
      );

      expect(screen.getByText(/Using materialized cube/)).toBeInTheDocument();
      expect(screen.getByText(/Valid thru/)).toBeInTheDocument();
    });

    it('shows materialization info without availability date', () => {
      render(<ResultsView {...defaultProps} cubeName="test_cube" />);

      expect(screen.getByText(/Using materialized cube/)).toBeInTheDocument();
      expect(screen.queryByText(/Valid thru/)).not.toBeInTheDocument();
    });
  });

  describe('Loading State', () => {
    it('shows loading spinner and message', () => {
      render(<ResultsView {...defaultProps} loading={true} />);

      expect(screen.getByText('Executing query...')).toBeInTheDocument();
      expect(
        screen.getByText(/Querying 2 metric\(s\) with 1 dimension\(s\)/),
      ).toBeInTheDocument();
    });
  });

  describe('Error State', () => {
    it('shows error message', () => {
      render(<ResultsView {...defaultProps} error="Connection failed" />);

      expect(screen.getByText('Query Failed')).toBeInTheDocument();
      expect(screen.getByText('Connection failed')).toBeInTheDocument();
    });

    it('shows back to plan button in error state', () => {
      const onBackToPlan = vi.fn();
      render(
        <ResultsView
          {...defaultProps}
          error="Error"
          onBackToPlan={onBackToPlan}
        />,
      );

      // There are two back buttons - one in header, one in error state
      const backButtons = screen.getAllByText('Back to Plan');
      expect(backButtons.length).toBe(2);

      fireEvent.click(backButtons[1]);
      expect(onBackToPlan).toHaveBeenCalled();
    });
  });

  describe('Results Table', () => {
    it('renders table with columns and rows', () => {
      render(<ResultsView {...defaultProps} />);

      expect(screen.getByText('id')).toBeInTheDocument();
      expect(screen.getByText('name')).toBeInTheDocument();
      expect(screen.getByText('Alice')).toBeInTheDocument();
      expect(screen.getByText('Bob')).toBeInTheDocument();
    });

    it('shows column types', () => {
      render(<ResultsView {...defaultProps} />);

      expect(screen.getByText('INT')).toBeInTheDocument();
      expect(screen.getByText('STRING')).toBeInTheDocument();
    });

    it('shows row count in table header', () => {
      render(<ResultsView {...defaultProps} />);

      // Row count appears in both header and table section
      const rowCounts = screen.getAllByText('2 rows');
      expect(rowCounts.length).toBeGreaterThanOrEqual(1);
    });

    it('shows empty state when no results', () => {
      render(
        <ResultsView
          {...defaultProps}
          results={{ results: [{ columns: [], rows: [] }] }}
        />,
      );

      expect(screen.getByText('No results returned')).toBeInTheDocument();
    });

    it('handles null values in cells', () => {
      render(
        <ResultsView
          {...defaultProps}
          results={{
            results: [
              {
                columns: [{ name: 'value', type: 'STRING' }],
                rows: [[null], ['data']],
              },
            ],
          }}
        />,
      );

      expect(screen.getByText('NULL')).toBeInTheDocument();
      expect(screen.getByText('data')).toBeInTheDocument();
    });

    it('displays filters as chips', () => {
      render(
        <ResultsView
          {...defaultProps}
          filters={["date >= '2024-01-01'", "status = 'active'"]}
        />,
      );

      expect(screen.getByText("date >= '2024-01-01'")).toBeInTheDocument();
      expect(screen.getByText("status = 'active'")).toBeInTheDocument();
    });
  });

  describe('Sorting', () => {
    it('sorts by column when header is clicked', () => {
      render(<ResultsView {...defaultProps} />);

      // Click on 'name' column header to sort
      const nameHeader = screen.getByText('name').closest('th');
      fireEvent.click(nameHeader);

      // First row should now be Alice (ascending)
      const rows = screen.getAllByRole('row');
      expect(rows[1]).toHaveTextContent('Alice');
    });

    it('toggles sort direction on second click', () => {
      render(<ResultsView {...defaultProps} />);

      const nameHeader = screen.getByText('name').closest('th');

      // First click - ascending
      fireEvent.click(nameHeader);
      let rows = screen.getAllByRole('row');
      expect(rows[1]).toHaveTextContent('Alice');

      // Second click - descending
      fireEvent.click(nameHeader);
      rows = screen.getAllByRole('row');
      expect(rows[1]).toHaveTextContent('Bob');
    });

    it('shows active sort indicator', () => {
      render(<ResultsView {...defaultProps} />);

      const nameHeader = screen.getByText('name').closest('th');
      fireEvent.click(nameHeader);

      expect(nameHeader).toHaveClass('sorted');
    });

    it('sorts numeric columns correctly', () => {
      render(
        <ResultsView
          {...defaultProps}
          results={{
            results: [
              {
                columns: [{ name: 'count', type: 'INT' }],
                rows: [[10], [2], [100]],
              },
            ],
          }}
        />,
      );

      const countHeader = screen.getByText('count').closest('th');
      fireEvent.click(countHeader);

      const cells = screen.getAllByRole('cell');
      expect(cells[0]).toHaveTextContent('2');
      expect(cells[1]).toHaveTextContent('10');
      expect(cells[2]).toHaveTextContent('100');
    });

    it('handles null values in sorting - nulls go last', () => {
      render(
        <ResultsView
          {...defaultProps}
          results={{
            results: [
              {
                columns: [{ name: 'value', type: 'STRING' }],
                rows: [[null], ['b'], ['a']],
              },
            ],
          }}
        />,
      );

      const valueHeader = screen.getByText('value').closest('th');
      fireEvent.click(valueHeader);

      const cells = screen.getAllByRole('cell');
      expect(cells[0]).toHaveTextContent('a');
      expect(cells[1]).toHaveTextContent('b');
      expect(cells[2]).toHaveTextContent('NULL');
    });
  });

  describe('Edge Cases', () => {
    it('handles missing results gracefully', () => {
      render(<ResultsView {...defaultProps} results={null} />);

      // Row count appears in both header and table section
      expect(screen.getAllByText('0 rows').length).toBeGreaterThanOrEqual(1);
    });

    it('handles empty results object', () => {
      render(<ResultsView {...defaultProps} results={{}} />);

      // Row count appears in both header and table section
      expect(screen.getAllByText('0 rows').length).toBeGreaterThanOrEqual(1);
    });

    it('formats large row counts with locale', () => {
      const manyRows = Array.from({ length: 1000 }, (_, i) => [i]);
      render(
        <ResultsView
          {...defaultProps}
          results={{
            results: [
              {
                columns: [{ name: 'id', type: 'INT' }],
                rows: manyRows,
              },
            ],
          }}
        />,
      );

      // Should show "1,000 rows" with locale formatting (appears in both header and table)
      expect(screen.getAllByText('1,000 rows').length).toBeGreaterThanOrEqual(
        1,
      );
    });
  });

  describe('Chart Tab', () => {
    // Results with a string dimension + numeric metric → bar chart config
    const barChartResults = {
      results: [
        {
          columns: [
            { name: 'country', type: 'STRING' },
            { name: 'revenue', type: 'FLOAT' },
          ],
          rows: [
            ['US', 1000],
            ['UK', 500],
          ],
        },
      ],
    };

    // Results with a time dimension + numeric metric → line chart config
    const lineChartResults = {
      results: [
        {
          columns: [
            { name: 'date', type: 'DATE' },
            { name: 'revenue', type: 'FLOAT' },
          ],
          rows: [
            ['2024-01-01', 1000],
            ['2024-01-02', 1500],
          ],
        },
      ],
    };

    // Results with two numeric columns (no string/time dim) → line with first as x
    const allNumericResults = {
      results: [
        {
          columns: [
            { name: 'x_val', type: 'FLOAT' },
            { name: 'y_val', type: 'FLOAT' },
          ],
          rows: [
            [1.0, 10.5],
            [2.0, 20.5],
          ],
        },
      ],
    };

    // Scalar result: single numeric column, one row → KPI cards
    const scalarResults = {
      results: [
        {
          columns: [{ name: 'total_revenue', type: 'FLOAT' }],
          rows: [[1234567.89]],
        },
      ],
    };

    it('renders Chart tab button', () => {
      render(<ResultsView {...defaultProps} results={barChartResults} />);
      expect(screen.getByText('Chart')).toBeInTheDocument();
    });

    it('Chart tab is enabled when data is chartable (bar chart data)', () => {
      render(<ResultsView {...defaultProps} results={barChartResults} />);
      const chartTab = screen.getByText('Chart').closest('button');
      expect(chartTab).not.toHaveClass('disabled');
    });

    it('Chart tab is enabled for any data with rows, showing no-data message when unchartable', () => {
      render(
        <ResultsView
          {...defaultProps}
          results={{
            results: [
              {
                columns: [{ name: 'name', type: 'STRING' }],
                rows: [['Alice']],
              },
            ],
          }}
        />,
      );
      const chartTab = screen.getByText('Chart').closest('button');
      expect(chartTab).not.toHaveClass('disabled');

      fireEvent.click(chartTab);
      expect(
        screen.getByText('No chartable data detected'),
      ).toBeInTheDocument();
    });

    it('switches to chart view when Chart tab is clicked (bar chart)', () => {
      render(<ResultsView {...defaultProps} results={barChartResults} />);

      fireEvent.click(screen.getByText('Chart'));

      // The chart wrapper should appear
      expect(
        document.querySelector('.results-chart-wrapper'),
      ).toBeInTheDocument();
      expect(screen.getByTestId('BarChart')).toBeInTheDocument();
    });

    it('switches to chart view when Chart tab is clicked (line chart)', () => {
      render(<ResultsView {...defaultProps} results={lineChartResults} />);

      fireEvent.click(screen.getByText('Chart'));

      expect(
        document.querySelector('.results-chart-wrapper'),
      ).toBeInTheDocument();
      expect(screen.getByTestId('LineChart')).toBeInTheDocument();
    });

    it('switches back to table view when Table tab is clicked', () => {
      render(<ResultsView {...defaultProps} results={barChartResults} />);

      // Switch to chart
      fireEvent.click(screen.getByText('Chart'));
      expect(
        document.querySelector('.results-chart-wrapper'),
      ).toBeInTheDocument();

      // Switch back to table
      fireEvent.click(screen.getByText('Table'));
      expect(
        document.querySelector('.results-table-wrapper'),
      ).toBeInTheDocument();
    });

    it('renders line chart for all-numeric columns (lines 93-95: no time/string dim)', () => {
      render(<ResultsView {...defaultProps} results={allNumericResults} />);

      fireEvent.click(screen.getByText('Chart'));

      expect(screen.getByTestId('LineChart')).toBeInTheDocument();
    });

    it('renders KPI cards for scalar numeric result', () => {
      render(<ResultsView {...defaultProps} results={scalarResults} />);

      fireEvent.click(screen.getByText('Chart'));

      expect(document.querySelector('.kpi-cards')).toBeInTheDocument();
      expect(document.querySelector('.kpi-label')).toHaveTextContent(
        'total_revenue',
      );
    });

    it('KPI card formats null value as em-dash', () => {
      render(
        <ResultsView
          {...defaultProps}
          results={{
            results: [
              {
                columns: [{ name: 'revenue', type: 'FLOAT' }],
                rows: [[null]],
              },
            ],
          }}
        />,
      );

      fireEvent.click(screen.getByText('Chart'));

      expect(document.querySelector('.kpi-value')).toHaveTextContent('—');
    });

    it('KPI card formats numeric value with toLocaleString', () => {
      render(<ResultsView {...defaultProps} results={scalarResults} />);

      fireEvent.click(screen.getByText('Chart'));

      // 1234567.89 formatted
      const kpiValue = document.querySelector('.kpi-value');
      expect(kpiValue).toBeInTheDocument();
      // Value should be a localized number string (not null)
      expect(kpiValue.textContent).not.toBe('—');
    });

    it('KPI card shows column type when present', () => {
      render(<ResultsView {...defaultProps} results={scalarResults} />);

      fireEvent.click(screen.getByText('Chart'));

      expect(document.querySelector('.kpi-type')).toHaveTextContent('FLOAT');
    });

    it('renders small multiples when 3+ metric columns present', () => {
      const threeMetricResults = {
        results: [
          {
            columns: [
              { name: 'date', type: 'DATE' },
              { name: 'metric_a', type: 'FLOAT' },
              { name: 'metric_b', type: 'FLOAT' },
              { name: 'metric_c', type: 'FLOAT' },
            ],
            rows: [
              ['2024-01-01', 10, 20, 30],
              ['2024-01-02', 15, 25, 35],
            ],
          },
        ],
      };

      render(<ResultsView {...defaultProps} results={threeMetricResults} />);

      fireEvent.click(screen.getByText('Chart'));

      // SMALL_MULTIPLES_THRESHOLD is 2, so 3 metric cols triggers small multiples
      expect(document.querySelector('.small-multiples')).toBeInTheDocument();
      const labels = document.querySelectorAll('.small-multiple-label');
      expect(labels.length).toBe(3);
    });

    it('shows no-data message when Chart tab clicked with unchartable data', () => {
      // Single string column → not chartable, but tab is still clickable
      render(
        <ResultsView
          {...defaultProps}
          results={{
            results: [
              {
                columns: [{ name: 'label', type: 'STRING' }],
                rows: [['x']],
              },
            ],
          }}
        />,
      );

      const chartTab = screen.getByText('Chart').closest('button');
      fireEvent.click(chartTab);

      expect(
        screen.getByText('No chartable data detected'),
      ).toBeInTheDocument();
    });

    it('resets to table view if new results are not chartable while on chart tab', () => {
      const { rerender } = render(
        <ResultsView {...defaultProps} results={barChartResults} />,
      );

      // Switch to chart view
      fireEvent.click(screen.getByText('Chart'));
      expect(
        document.querySelector('.results-chart-wrapper'),
      ).toBeInTheDocument();

      // Re-render with non-chartable results (empty rows)
      rerender(
        <ResultsView
          {...defaultProps}
          results={{ results: [{ columns: [], rows: [] }] }}
        />,
      );

      // Should auto-reset to table view
      expect(
        document.querySelector('.results-table-wrapper'),
      ).toBeInTheDocument();
    });

    it('shows links during loading when links prop is provided', () => {
      render(
        <ResultsView
          {...defaultProps}
          loading={true}
          links={['https://example.com/query/123']}
        />,
      );

      const link = screen.getByText('View query ↗');
      expect(link).toBeInTheDocument();
      expect(link).toHaveAttribute('href', 'https://example.com/query/123');
    });

    // ── Pivoted chart paths (buildPivotedData + ChartView branches) ──────────

    it('renders pivoted line chart for time + 1 categorical + 1 metric (groupByCol path)', () => {
      // detectChartConfig line 84-90: timeCols + nonTimeCatCols.length === 1
      // buildPivotedData lines 131-178, useMemo lines 505-512, ChartView line 353
      const pivotedLineResults = {
        results: [
          {
            columns: [
              { name: 'date', type: 'DATE' },
              { name: 'country', type: 'STRING' },
              { name: 'revenue', type: 'FLOAT' },
            ],
            rows: [
              ['2024-01-01', 'US', 1000],
              ['2024-01-01', 'UK', 500],
              ['2024-01-02', 'US', 1200],
              ['2024-01-02', null, 300], // null group value → '(null)'
            ],
          },
        ],
      };

      render(<ResultsView {...defaultProps} results={pivotedLineResults} />);
      fireEvent.click(screen.getByText('Chart'));

      expect(screen.getByTestId('LineChart')).toBeInTheDocument();
    });

    it('renders pivoted multi-metric small multiples (time + 1 cat + 2 metrics)', () => {
      // ChartView lines 331-334: pivotedByMetric.length > 1
      const pivotedMultiMetricResults = {
        results: [
          {
            columns: [
              { name: 'date', type: 'DATE' },
              { name: 'country', type: 'STRING' },
              { name: 'revenue', type: 'FLOAT' },
              { name: 'orders', type: 'FLOAT' },
            ],
            rows: [
              ['2024-01-01', 'US', 1000, 10],
              ['2024-01-01', 'UK', 500, 5],
              ['2024-01-02', 'US', 1200, 12],
            ],
          },
        ],
      };

      render(
        <ResultsView {...defaultProps} results={pivotedMultiMetricResults} />,
      );
      fireEvent.click(screen.getByText('Chart'));

      // pivotedByMetric.length === 2 → small-multiples wrapper
      expect(document.querySelector('.small-multiples')).toBeInTheDocument();
      const labels = document.querySelectorAll('.small-multiple-label');
      expect(labels.length).toBe(2);
      expect(labels[0]).toHaveTextContent('revenue');
      expect(labels[1]).toHaveTextContent('orders');
    });

    it('renders grouped bar chart for 2 categorical columns (lines 101-107)', () => {
      // detectChartConfig: nonTimeCatCols.length === 2 → bar with groupByCol
      const groupedBarResults = {
        results: [
          {
            columns: [
              { name: 'region', type: 'STRING' },
              { name: 'category', type: 'STRING' },
              { name: 'revenue', type: 'FLOAT' },
            ],
            rows: [
              ['North', 'A', 1000],
              ['South', 'A', 800],
              ['North', 'B', 600],
              ['South', null, 400], // null group value
            ],
          },
        ],
      };

      render(<ResultsView {...defaultProps} results={groupedBarResults} />);
      fireEvent.click(screen.getByText('Chart'));

      expect(screen.getByTestId('BarChart')).toBeInTheDocument();
    });

    it('renders bar chart for 3+ categorical columns falling back to first as x-axis (lines 108-110)', () => {
      const threeCatResults = {
        results: [
          {
            columns: [
              { name: 'a', type: 'STRING' },
              { name: 'b', type: 'STRING' },
              { name: 'c', type: 'STRING' },
              { name: 'metric', type: 'FLOAT' },
            ],
            rows: [
              ['x1', 'y1', 'z1', 100],
              ['x2', 'y2', 'z2', 200],
            ],
          },
        ],
      };

      render(<ResultsView {...defaultProps} results={threeCatResults} />);
      fireEvent.click(screen.getByText('Chart'));

      expect(screen.getByTestId('BarChart')).toBeInTheDocument();
    });
  });

  describe('Pane Resize', () => {
    it('handles SQL pane drag resize via horizontal-resizer', () => {
      render(<ResultsView {...defaultProps} />);

      const resizer = document.querySelector('.horizontal-resizer');
      expect(resizer).toBeInTheDocument();

      // Mousedown starts the drag
      fireEvent.mouseDown(resizer, { clientY: 300 });

      // Mousemove updates height (in jsdom offsetHeight is 0, so newHeight clamps to min 80)
      fireEvent.mouseMove(document, { clientY: 350 });

      // Inline style should be applied to sql-pane
      const sqlPane = document.querySelector('.sql-pane');
      expect(sqlPane.style.maxHeight).toBeTruthy();

      // Mouseup removes event listeners
      fireEvent.mouseUp(document);

      // Further moves should not update (listeners removed)
      const heightAfterUp = sqlPane.style.maxHeight;
      fireEvent.mouseMove(document, { clientY: 500 });
      expect(sqlPane.style.maxHeight).toBe(heightAfterUp);
    });

    it('does not update height when no resultsPanesRef container', () => {
      // Renders and immediately fires mousedown on resizer
      render(<ResultsView {...defaultProps} />);
      const resizer = document.querySelector('.horizontal-resizer');
      // Should not throw even if container measures are 0
      expect(() => {
        fireEvent.mouseDown(resizer, { clientY: 100 });
        fireEvent.mouseMove(document, { clientY: 200 });
        fireEvent.mouseUp(document);
      }).not.toThrow();
    });
  });
});
