// #region Test.Dashboard.DataGrid [C:3] [TYPE Module] [SEMANTICS test,dashboard,grid]
// @BRIEF Unit tests for DashboardDataGrid — mounting, selection, sort, filter, pagination, loading states.
// @LAYER UI (Tests)
// @RELATION BINDS_TO -> [Dashboard.DataGrid]
// @TEST_CONTRACT: Props -> Rendered UI
// @TEST_SCENARIO: empty_state -> Renders empty message when data is empty
// @TEST_SCENARIO: data_rows -> Renders correct number of rows from data
// @TEST_SCENARIO: column_headers -> Renders column labels from columns prop
// @TEST_SCENARIO: selection -> Checkbox toggles selectedIds, select-all works
// @TEST_SCENARIO: sort -> Clicking sortable column header changes sort direction
// @TEST_SCENARIO: filter -> Typing in filter narrows displayed rows
// @TEST_SCENARIO: pagination -> Paginated grid renders correct page with nav
// @TEST_SCENARIO: loading_state -> Loading prop shows skeleton rows
// @TEST_SCENARIO: custom_render -> Column render function overrides default display
// @TEST_EDGE: filtered_empty -> Filter with no matches shows empty state
// @TEST_EDGE: no_columns -> Component renders without column definitions
// @TEST_INVARIANT: features_opt_in -> { selectable, sortable, filterable, paginated } default to false
// @INVARIANT: All interactive features are opt-in via boolean props

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/svelte';
import DashboardDataGrid from '../DashboardDataGrid.svelte';

// ── i18n mock ──────────────────────────────────────────────────
vi.mock('$lib/i18n/index.svelte.js', () => ({
  t: {
    subscribe: (fn: (v: any) => void) => {
      fn({
        dashboard: {
          title: 'Title',
          last_modified: 'Last Modified',
          search: 'Search...',
          showing: 'Showing {start}-{end} of {total}',
          previous: 'Prev',
          next: 'Next',
        },
        common: {
          no_data: 'No items',
        },
      });
      return () => {};
    },
  },
}));

// ── Fixtures ───────────────────────────────────────────────────
const sampleColumns = [
  { key: 'title', label: 'Title', sortable: true },
  { key: 'last_modified', label: 'Last Modified', sortable: true },
];

const sampleData = [
  { id: 1, title: 'Dashboard A', last_modified: '2025-01-15' },
  { id: 2, title: 'Dashboard B', last_modified: '2025-02-20' },
  { id: 3, title: 'Dashboard C', last_modified: '2025-03-10' },
];

describe('DashboardDataGrid', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  // @TEST_SCENARIO: empty_state
  it('renders empty state when data is empty', () => {
    render(DashboardDataGrid, { data: [], columns: sampleColumns });
    expect(screen.getByText('No items')).toBeDefined();
  });

  // @TEST_SCENARIO: column_headers
  it('renders column headers from columns prop', () => {
    render(DashboardDataGrid, { data: sampleData, columns: sampleColumns });
    expect(screen.getByText('Title')).toBeDefined();
    expect(screen.getByText('Last Modified')).toBeDefined();
  });

  // @TEST_SCENARIO: data_rows
  it('renders correct number of data rows', () => {
    render(DashboardDataGrid, { data: sampleData, columns: sampleColumns });
    expect(screen.getByText('Dashboard A')).toBeDefined();
    expect(screen.getByText('Dashboard B')).toBeDefined();
    expect(screen.getByText('Dashboard C')).toBeDefined();
    expect(screen.getByText('2025-01-15')).toBeDefined();
  });

  // @TEST_SCENARIO: selection
  it('toggles selection on checkbox click when selectable', async () => {
    const { container } = render(DashboardDataGrid, {
      data: sampleData,
      columns: sampleColumns,
      selectable: true,
      selectedIds: [],
    });

    const checkboxes = container.querySelectorAll('input[type="checkbox"]');
    expect(checkboxes.length).toBeGreaterThanOrEqual(4); // 1 select-all + 3 rows

    // Click first row checkbox
    await fireEvent.click(checkboxes[1]);
    // selectedIds is handled internally via $bindable; component re-renders
    // Check that the first row checkbox becomes checked
    expect((checkboxes[1] as HTMLInputElement).checked).toBe(true);
  });

  // @TEST_SCENARIO: sort
  it('toggles sort direction on sortable column header click', async () => {
    const { container } = render(DashboardDataGrid, {
      data: sampleData,
      columns: sampleColumns,
      sortable: true,
      sortColumn: 'title',
      sortDirection: 'asc',
    });

    // Title column header should have aria-sort="ascending"
    const titleHeaders = container.querySelectorAll('th[aria-sort]');
    expect(titleHeaders.length).toBeGreaterThanOrEqual(1);

    // Click title header to toggle sort
    const titleHeader = screen.getByText('Title');
    await fireEvent.click(titleHeader);

    // After click, aria-sort should now be "descending"
    const descHeaders = container.querySelectorAll('th[aria-sort="descending"]');
    expect(descHeaders.length).toBeGreaterThanOrEqual(1);
  });

  // @TEST_SCENARIO: filter
  it('filters data rows when filter text changes', async () => {
    render(DashboardDataGrid, {
      data: sampleData,
      columns: sampleColumns,
      filterable: true,
      filterText: 'Dashboard B',
    });

    // Only "Dashboard B" should be visible
    expect(screen.getByText('Dashboard B')).toBeDefined();
    // "Dashboard A" and "Dashboard C" should be hidden
    expect(screen.queryByText('Dashboard A')).toBeNull();
    expect(screen.queryByText('Dashboard C')).toBeNull();
    // Filter input renders
    expect(screen.getByPlaceholderText('Search...')).toBeDefined();
  });

  // @TEST_SCENARIO: pagination
  it('shows pagination controls when paginated', () => {
    render(DashboardDataGrid, {
      data: sampleData,
      columns: sampleColumns,
      paginated: true,
      pageSize: 2,
    });

    // Prev/Next buttons
    expect(screen.getByText('Prev')).toBeDefined();
    expect(screen.getByText('Next')).toBeDefined();

    // Showing X-Y of Z
    expect(screen.getByText(/Showing 1-2 of 3/)).toBeDefined();
  });

  // @TEST_SCENARIO: loading_state
  it('shows skeleton rows when loading', () => {
    const { container } = render(DashboardDataGrid, {
      data: [],
      columns: sampleColumns,
      loading: true,
      loadingRows: 3,
    });

    // Should have animate-pulse class on the skeleton container
    const skeleton = container.querySelector('.animate-pulse');
    expect(skeleton).toBeDefined();

    // Should NOT show empty state text when loading
    expect(screen.queryByText('No items')).toBeNull();
  });

  // @TEST_SCENARIO: custom_render
  it('uses column render function when provided', () => {
    const columnsWithRender = [
      { key: 'title', label: 'Title', render: (item: any) => `Custom: ${item.title}` },
    ];

    render(DashboardDataGrid, {
      data: sampleData,
      columns: columnsWithRender,
    });

    expect(screen.getByText('Custom: Dashboard A')).toBeDefined();
    expect(screen.getByText('Custom: Dashboard B')).toBeDefined();
    // Default (item[key]) should NOT appear
    expect(screen.queryByText('Dashboard A')).toBeNull();
  });

  // @TEST_EDGE: filtered_empty
  it('shows empty state when filter matches nothing', () => {
    render(DashboardDataGrid, {
      data: sampleData,
      columns: sampleColumns,
      filterable: true,
      filterText: 'NONEXISTENT',
    });

    expect(screen.getByText('No items')).toBeDefined();
  });

  // @TEST_EDGE: no_columns
  it('renders without crashing when columns is empty', () => {
    const { container } = render(DashboardDataGrid, {
      data: sampleData,
      columns: [],
    });

    // Table renders but with empty cells (no column definitions to display)
    const table = container.querySelector('table');
    expect(table).toBeDefined();
    // Rows still render (data is present), but each cell is empty
    const rows = container.querySelectorAll('tbody tr');
    expect(rows.length).toBe(3);
  });

  // @TEST_INVARIANT: features_opt_in
  it('does not render checkboxes when selectable is false', () => {
    const { container } = render(DashboardDataGrid, {
      data: sampleData,
      columns: sampleColumns,
      selectable: false,
    });

    const checkboxes = container.querySelectorAll('input[type="checkbox"]');
    expect(checkboxes.length).toBe(0);
  });

  it('does not render filter input when filterable is false', () => {
    render(DashboardDataGrid, {
      data: sampleData,
      columns: sampleColumns,
      filterable: false,
    });

    expect(screen.queryByPlaceholderText('Search...')).toBeNull();
  });

  it('does not render pagination when paginated is false', () => {
    render(DashboardDataGrid, {
      data: sampleData,
      columns: sampleColumns,
      paginated: false,
    });

    expect(screen.queryByText('Prev')).toBeNull();
    expect(screen.queryByText('Next')).toBeNull();
  });

  // ── Server-side pagination ────────────────────────────────────
  it('uses serverTotal for pagination count when provided', () => {
    render(DashboardDataGrid, {
      data: sampleData.slice(0, 2), // Only 2 items visible
      columns: sampleColumns,
      paginated: true,
      pageSize: 2,
      serverTotal: 100, // Server says 100 total
    });

    // Should show "Showing 1-2 of 100" not "Showing 1-2 of 3"
    expect(screen.getByText(/Showing 1-2 of 100/)).toBeDefined();
  });

  it('uses serverTotalPages for page count when provided', () => {
    render(DashboardDataGrid, {
      data: sampleData.slice(0, 2),
      columns: sampleColumns,
      paginated: true,
      pageSize: 2,
      serverTotal: 100,
      serverTotalPages: 50,
    });

    // Next should be enabled (page 0 < 49)
    const nextBtn = screen.getByText('Next');
    expect((nextBtn as HTMLButtonElement).disabled).toBe(false);
  });

  it('disables next button on last server-side page', () => {
    render(DashboardDataGrid, {
      data: [{ id: 99, title: 'Last', last_modified: '2025-06-01' }],
      columns: sampleColumns,
      paginated: true,
      pageSize: 1,
      page: 2,
      serverTotal: 3,
      serverTotalPages: 3,
    });

    const nextBtn = screen.getByText('Next');
    expect((nextBtn as HTMLButtonElement).disabled).toBe(true);
  });

  // ── hideFilter ────────────────────────────────────────────────
  it('hides filter input when hideFilter is true', () => {
    render(DashboardDataGrid, {
      data: sampleData,
      columns: sampleColumns,
      filterable: true,
      hideFilter: true,
    });

    expect(screen.queryByPlaceholderText('Search...')).toBeNull();
  });

  // ── Custom cell snippet (via raw render, tested as HTML injection) ──
  it('renders raw HTML when column has raw:true and render function', () => {
    const badgeColumns = [
      { key: 'status', label: 'Status', render: (item: any) => `<span class="badge">${item.status}</span>`, raw: true },
    ];
    const badgeData = [
      { id: 1, status: 'published' },
    ];

    const { container } = render(DashboardDataGrid, {
      data: badgeData,
      columns: badgeColumns,
    });

    const badge = container.querySelector('.badge');
    expect(badge).toBeDefined();
    expect(badge?.textContent).toBe('published');
  });
});
// #endregion Test.Dashboard.DataGrid
