import { render, screen, fireEvent, within } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';

import { RecordListHeader } from '../src/platform/features/record/components/RecordListHeader';
import type { ListView, SObjectDescribe, SObjectField } from '../src/platform/types';

// Acceptance for the list-view toolbar redesign (#363). P0 established style
// unification + CTA wrap-proofing; P1 ("control folding 10→5") collapses the
// low-frequency controls behind a single "More" menu and moves list-lifecycle
// actions onto the list picker. These assertions encode both:
//   • the primary CTA can never wrap and search stays the flexible middle axis;
//   • the resident Sorted-by badge, the standalone Columns/Refresh buttons, the
//     view-mode toggle, and the settings gear are all gone from the toolbar;
//   • Edit columns / Reset column widths / View as board / Refresh live inside
//     the "More" overflow menu;
//   • the list picker owns New / Clone / Delete list view;
//   • the Filters trigger active state is a tinted outline, never a second
//     filled-blue primary.

const fields: SObjectField[] = [
  {
    name: 'Name',
    label: 'Account Name',
    type: 'string',
    custom: false,
    readable: true,
    createable: true,
    updateable: true,
    nillable: false,
    nameField: true,
  },
];

const accountMetadata: SObjectDescribe = {
  name: 'Account',
  label: 'Account',
  labelPlural: 'Accounts',
  custom: false,
  keyPrefix: '001',
  createable: true,
  updateable: true,
  deletable: true,
  retrieveable: true,
  searchable: true,
  triggerable: true,
  undeletable: false,
  mergeable: true,
  deprecatedAndHidden: false,
  layoutable: true,
  queryable: true,
  replicateable: true,
  feedEnabled: true,
  fields,
};

const savedView: ListView = { id: 'view-1', label: 'My Accounts' } as ListView;

function renderHeader(overrides: {
  activeFilterExpr?: string;
  selectedView?: ListView | null;
  onSelectFields?: () => void;
  onResetColumnWidths?: () => void;
  setViewMode?: (mode: 'list' | 'kanban') => void;
  onNewViewClick?: () => void;
  onCloneViewClick?: () => void;
  onDeleteViewClick?: (viewId: string) => void;
} = {}) {
  return render(
    <RecordListHeader
      objectMetadata={accountMetadata}
      localSearch=""
      setLocalSearch={vi.fn()}
      onRefresh={vi.fn()}
      activeFilterExpr={overrides.activeFilterExpr ?? ''}
      setActiveFilterExpr={vi.fn()}
      setActiveFilterLogic={vi.fn()}
      customActions={[]}
      selectedRecordsCount={0}
      onCustomActionClick={vi.fn()}
      onCreateNew={vi.fn()}
      selectedView={overrides.selectedView ?? null}
      setSelectedView={vi.fn()}
      listViews={overrides.selectedView ? [overrides.selectedView] : []}
      onSaveViewClick={vi.fn()}
      onCloneViewClick={overrides.onCloneViewClick ?? vi.fn()}
      onNewViewClick={overrides.onNewViewClick ?? vi.fn()}
      onDeleteViewClick={overrides.onDeleteViewClick ?? vi.fn()}
      onSelectFields={overrides.onSelectFields ?? vi.fn()}
      onResetColumnWidths={overrides.onResetColumnWidths ?? vi.fn()}
      viewMode="list"
      setViewMode={overrides.setViewMode ?? vi.fn()}
    />,
  );
}

describe('list toolbar P0 style unification (#363)', () => {
  it('wrap-proofs the primary CTA: nowrap + shrink-0 + uniform height', () => {
    renderHeader();

    const cta = screen.getByRole('button', { name: /New Account/ });
    expect(cta.className).toContain('whitespace-nowrap');
    expect(cta.className).toContain('shrink-0');
    expect(cta.className).toContain('h-8');
  });

  it('makes search the flexible middle axis with a usable minimum width', () => {
    renderHeader();

    const search = screen.getByPlaceholderText('Search Accounts...');
    // input itself is uniform height
    expect(search.className).toContain('h-8');
    // its wrapper flexes to take spare width but never collapses below the
    // floor; P1 folding freed toolbar width so the floor is back to 140px.
    const wrapper = search.parentElement as HTMLElement;
    expect(wrapper.className).toContain('flex-1');
    expect(wrapper.className).toContain('min-w-[140px]');
  });

  it('renders the Filters trigger as an outline control when inactive', () => {
    renderHeader();

    const filters = screen.getByRole('button', { name: /Filters/ });
    expect(filters.className).toContain('border');
    expect(filters.className).not.toContain('bg-blue-600');
    expect(filters.className).toContain('h-8');
  });

  it('keeps the Filters active state a tinted outline — never a second filled-blue primary', () => {
    renderHeader({ activeFilterExpr: "Name = 'Acme'" });

    const filters = screen.getByRole('button', { name: /Filters/ });
    expect(filters.className).toContain('bg-blue-50');
    expect(filters.className).toContain('border-blue-300');
    expect(filters.className).not.toContain('bg-blue-600');
  });
});

describe('list toolbar P1 control folding 10→5 (#363)', () => {
  it('removes the resident Sorted-by badge, standalone Columns/Refresh, view-mode toggle, and settings gear', () => {
    renderHeader();

    // No resident Sorted-by badge on the toolbar anymore.
    expect(screen.queryByText(/Sorted by/)).not.toBeInTheDocument();
    // No standalone Columns / Refresh buttons — folded into More.
    expect(screen.queryByRole('button', { name: /^Columns$/ })).not.toBeInTheDocument();
    expect(screen.queryByRole('button', { name: /^Refresh$/ })).not.toBeInTheDocument();
    // No settings gear — its actions moved to the list picker + More.
    expect(screen.queryByRole('button', { name: 'List view controls' })).not.toBeInTheDocument();
  });

  it('exposes a single "More" overflow trigger sized to the toolbar', () => {
    renderHeader();

    const more = screen.getByRole('button', { name: 'More list actions' });
    expect(more).toHaveTextContent('More');
    expect(more.className).toContain('h-8');
    expect(more).toHaveAttribute('aria-haspopup', 'menu');
  });

  it('folds Edit columns / Reset column widths / View as board / Refresh into the More menu', () => {
    const onSelectFields = vi.fn();
    const onResetColumnWidths = vi.fn();
    const setViewMode = vi.fn();
    renderHeader({ onSelectFields, onResetColumnWidths, setViewMode });

    fireEvent.click(screen.getByRole('button', { name: 'More list actions' }));

    const menu = screen.getByRole('menu', { name: 'More list actions' });
    const items = within(menu);
    expect(items.getByRole('menuitem', { name: /Edit columns/ })).toBeInTheDocument();
    expect(items.getByRole('menuitem', { name: /Reset column widths/ })).toBeInTheDocument();
    // In list mode the toggle offers the board view.
    expect(items.getByRole('menuitem', { name: /View as board/ })).toBeInTheDocument();
    expect(items.getByRole('menuitem', { name: /Refresh/ })).toBeInTheDocument();

    fireEvent.click(items.getByRole('menuitem', { name: /Edit columns/ }));
    expect(onSelectFields).toHaveBeenCalledOnce();
  });

  it('drops Edit columns / Reset column widths from More when their handlers are absent', () => {
    render(
      <RecordListHeader
        objectMetadata={accountMetadata}
        localSearch=""
        setLocalSearch={vi.fn()}
        onRefresh={vi.fn()}
        activeFilterExpr=""
        setActiveFilterExpr={vi.fn()}
        setActiveFilterLogic={vi.fn()}
        customActions={[]}
        selectedRecordsCount={0}
        onCustomActionClick={vi.fn()}
        onCreateNew={vi.fn()}
        selectedView={null}
        setSelectedView={vi.fn()}
        listViews={[]}
        onSaveViewClick={vi.fn()}
        onCloneViewClick={vi.fn()}
        onNewViewClick={vi.fn()}
        onDeleteViewClick={vi.fn()}
        viewMode="list"
        setViewMode={vi.fn()}
      />,
    );

    fireEvent.click(screen.getByRole('button', { name: 'More list actions' }));
    const menu = screen.getByRole('menu', { name: 'More list actions' });
    expect(within(menu).queryByRole('menuitem', { name: /Edit columns/ })).not.toBeInTheDocument();
    expect(within(menu).queryByRole('menuitem', { name: /Reset column widths/ })).not.toBeInTheDocument();
    // Refresh + View mode are always present.
    expect(within(menu).getByRole('menuitem', { name: /Refresh/ })).toBeInTheDocument();
    expect(within(menu).getByRole('menuitem', { name: /View as board/ })).toBeInTheDocument();
  });

  it('offers New list view from the list picker, and gates Clone/Delete on a selected view', () => {
    // No selected view: only New list view is offered.
    const { unmount } = renderHeader();
    fireEvent.click(screen.getByRole('button', { name: /All Records/ }));
    expect(screen.getByRole('button', { name: /New list view/ })).toBeInTheDocument();
    expect(screen.queryByRole('button', { name: /Clone list view/ })).not.toBeInTheDocument();
    expect(screen.queryByRole('button', { name: /Delete list view/ })).not.toBeInTheDocument();
    unmount();

    // Selected view: Clone + Delete appear alongside New.
    const onCloneViewClick = vi.fn();
    const onDeleteViewClick = vi.fn();
    renderHeader({ selectedView: savedView, onCloneViewClick, onDeleteViewClick });
    fireEvent.click(screen.getByRole('button', { name: /My Accounts/ }));
    expect(screen.getByRole('button', { name: /New list view/ })).toBeInTheDocument();
    fireEvent.click(screen.getByRole('button', { name: /Clone list view/ }));
    expect(onCloneViewClick).toHaveBeenCalledOnce();

    fireEvent.click(screen.getByRole('button', { name: /My Accounts/ }));
    fireEvent.click(screen.getByRole('button', { name: /Delete list view/ }));
    expect(onDeleteViewClick).toHaveBeenCalledWith(savedView.id);
  });
});
