/**
 * CMS Navigation Editor Tests
 *
 * Tests the BEHAVIOR of the navigation editor page:
 * - Loading and error states
 * - Tier gate for non-enhanced dealers
 * - Adding and editing navigation items
 * - Link type selection and URL handling
 * - Validation and publish flow
 *
 * Philosophy: Test what the user experiences, not implementation details.
 * The NavTreeEditor (drag-drop) is mocked since it's tested separately.
 */

import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

// Mock next/navigation
const mockPush = jest.fn();
jest.mock('next/navigation', () => ({
  useRouter: () => ({ push: mockPush }),
}));

// Mock next-auth
const mockSession = {
  data: { user: { id: 'user-123', email: 'test@example.com' } },
  status: 'authenticated' as const,
};
jest.mock('next-auth/react', () => ({
  useSession: () => mockSession,
}));

// Mock NavTreeEditor (drag-drop component)
interface MockNavTreeEditorProps {
  items: Array<{ id: string; label: string; children: unknown[] }>;
  onItemsChange: (items: unknown[]) => void;
  onAddItem: () => void;
  onEditItem: (item: unknown) => void;
  dealerName?: string;
  dealerCity?: string;
  dealerPhone?: string;
}

jest.mock('@/components/cms/NavTreeEditor', () => ({
  __esModule: true,
  default: ({ items, onAddItem, onEditItem }: MockNavTreeEditorProps) => (
    <div data-testid="nav-tree-editor">
      <button data-testid="add-item-btn" onClick={onAddItem}>
        Add Item
      </button>
      {items.map((item) => (
        <div
          key={item.id}
          data-testid={`nav-item-${item.id}`}
          onClick={() => onEditItem(item)}
          style={{ cursor: 'pointer' }}
        >
          {item.label}
        </div>
      ))}
    </div>
  ),
}));

// Mock ErrorBoundary
jest.mock('@/components/ui/ErrorBoundary', () => ({
  ErrorBoundary: ({ children }: { children: React.ReactNode }) => <>{children}</>,
}));

// Mock TierGate
jest.mock('@/components/ui/TierGate', () => ({
  __esModule: true,
  default: ({
    title,
    description,
    requiredTier,
  }: {
    title: string;
    description: string;
    requiredTier: string;
  }) => (
    <div data-testid="tier-gate">
      <h2>{title}</h2>
      <p>{description}</p>
      <span data-testid="required-tier">{requiredTier}</span>
    </div>
  ),
}));

// Mock Toast
const mockShowToast = jest.fn();
jest.mock('@/components/ui/Toast', () => ({
  ToastProvider: ({ children }: { children: React.ReactNode }) => <>{children}</>,
  useToast: () => ({ showToast: mockShowToast }),
}));

// Mock link validation
jest.mock('@/lib/cms/link-validation-client', () => ({
  normalizeUrl: (url: string) => {
    if (!url) return '';
    if (url.startsWith('http://') || url.startsWith('https://')) return url;
    return `https://${url}`;
  },
}));

// Mock nav validation
jest.mock('@/lib/cms/nav-validation', () => ({
  validateNavigation: jest.fn(() => ({ valid: true })),
}));

// Import after mocks
import NavigationEditorPage from '../page';
import { validateNavigation } from '@/lib/cms/nav-validation';

describe('CMS Navigation Editor', () => {
  // Sample navigation data from API
  const mockNavItems = [
    {
      id: 'nav-1',
      dealerId: 'dealer-123',
      label: 'Home',
      pageId: null,
      externalUrl: null,
      parentId: null,
      sortOrder: 0,
      isDefault: true,
      defaultKey: 'home',
      defaultSortOrder: 0,
      openInNewTab: false,
      isVisible: true,
      page: null,
    },
    {
      id: 'nav-2',
      dealerId: 'dealer-123',
      label: 'Shop Products',
      pageId: null,
      externalUrl: 'https://www.amsoil.com/shop',
      parentId: null,
      sortOrder: 1,
      isDefault: false,
      defaultKey: null,
      defaultSortOrder: null,
      openInNewTab: true,
      isVisible: true,
      page: null,
    },
  ];

  const mockDealerInfo = {
    id: 'dealer-123',
    displayName: 'Test Dealer',
    businessName: 'Test Dealer LLC',
    city: 'Minneapolis',
    state: 'MN',
    phone: '(612) 555-1234',
  };

  beforeEach(() => {
    jest.clearAllMocks();
    mockSession.status = 'authenticated';
    mockSession.data = { user: { id: 'user-123', email: 'test@example.com' } };

    // Reset validation mock to return valid (tests that need invalid must set it themselves)
    (validateNavigation as jest.Mock).mockReturnValue({ valid: true });

    // Default successful API responses
    global.fetch = jest.fn().mockImplementation((url: string) => {
      if (url === '/api/cms/navigation') {
        return Promise.resolve({
          ok: true,
          json: () => Promise.resolve({ items: mockNavItems, dealer: { id: 'dealer-123' } }),
        });
      }
      if (url === '/api/dealer') {
        return Promise.resolve({
          ok: true,
          json: () => Promise.resolve(mockDealerInfo),
        });
      }
      if (url === '/api/cms/pages?type=page') {
        return Promise.resolve({
          ok: true,
          json: () =>
            Promise.resolve({
              pages: [
                {
                  id: 'page-1',
                  title: 'About Us',
                  slug: 'about',
                  type: 'page',
                  status: 'published',
                },
                {
                  id: 'page-2',
                  title: 'Contact',
                  slug: 'contact',
                  type: 'page',
                  status: 'published',
                },
              ],
            }),
        });
      }
      return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
    });
  });

  describe('Loading States', () => {
    it('shows loading message while fetching navigation', async () => {
      // Delay the API response
      (global.fetch as jest.Mock).mockImplementation(
        () =>
          new Promise((resolve) => setTimeout(() => resolve({ ok: true, json: () => ({}) }), 100))
      );

      render(<NavigationEditorPage />);

      expect(screen.getByText(/loading navigation editor/i)).toBeInTheDocument();
    });

    it('shows loading while session is loading', () => {
      mockSession.status = 'loading' as 'authenticated';

      render(<NavigationEditorPage />);

      expect(screen.getByText(/loading navigation editor/i)).toBeInTheDocument();
    });

    it('redirects to signin if not authenticated', () => {
      mockSession.status = 'loading' as 'authenticated';
      mockSession.data = null as unknown as typeof mockSession.data;

      render(<NavigationEditorPage />);

      // Session loading shows loading state, then would redirect
      expect(screen.getByText(/loading navigation editor/i)).toBeInTheDocument();
    });
  });

  describe('Tier Gate', () => {
    it('shows upgrade required message for non-enhanced tier dealers', async () => {
      (global.fetch as jest.Mock).mockImplementation((url: string) => {
        if (url === '/api/cms/navigation') {
          return Promise.resolve({
            ok: false,
            status: 403,
            json: () => Promise.resolve({ error: 'Tier restriction' }),
          });
        }
        return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
      });

      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('tier-gate')).toBeInTheDocument();
      });

      expect(screen.getByText(/enhanced tier required/i)).toBeInTheDocument();
      expect(screen.getByTestId('required-tier')).toHaveTextContent('enhanced');
    });

    it('shows editor for enhanced+ tier dealers', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('nav-tree-editor')).toBeInTheDocument();
      });

      expect(screen.queryByTestId('tier-gate')).not.toBeInTheDocument();
    });
  });

  describe('Error States', () => {
    it('displays error message when navigation fetch fails', async () => {
      (global.fetch as jest.Mock).mockImplementation((url: string) => {
        if (url === '/api/cms/navigation') {
          return Promise.resolve({
            ok: false,
            status: 500,
            json: () => Promise.resolve({ error: 'Database connection failed' }),
          });
        }
        return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
      });

      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByText(/database connection failed/i)).toBeInTheDocument();
      });
    });

    it('provides Try Again button on error', async () => {
      (global.fetch as jest.Mock).mockImplementation((url: string) => {
        if (url === '/api/cms/navigation') {
          return Promise.resolve({
            ok: false,
            status: 500,
            json: () => Promise.resolve({ error: 'Server error' }),
          });
        }
        return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
      });

      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByRole('button', { name: /try again/i })).toBeInTheDocument();
      });
    });

    it('retries fetch on Try Again click', async () => {
      let callCount = 0;
      (global.fetch as jest.Mock).mockImplementation((url: string) => {
        if (url === '/api/cms/navigation') {
          callCount++;
          if (callCount === 1) {
            return Promise.resolve({
              ok: false,
              status: 500,
              json: () => Promise.resolve({ error: 'Server error' }),
            });
          }
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({ items: mockNavItems, dealer: { id: 'dealer-123' } }),
          });
        }
        return Promise.resolve({ ok: true, json: () => Promise.resolve(mockDealerInfo) });
      });

      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByRole('button', { name: /try again/i })).toBeInTheDocument();
      });

      await userEvent.click(screen.getByRole('button', { name: /try again/i }));

      await waitFor(() => {
        expect(screen.getByTestId('nav-tree-editor')).toBeInTheDocument();
      });
    });
  });

  describe('Navigation Items Display', () => {
    it('displays navigation items from API', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByText('Home')).toBeInTheDocument();
        expect(screen.getByText('Shop Products')).toBeInTheDocument();
      });
    });

    it('shows page title and description', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByText('Navigation Editor')).toBeInTheDocument();
        expect(screen.getByText(/customize your dealer page navigation/i)).toBeInTheDocument();
      });
    });
  });

  describe('Add Item', () => {
    it('opens edit modal when Add Item is clicked', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('nav-tree-editor')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByTestId('add-item-btn'));

      await waitFor(() => {
        expect(screen.getByText('Edit Navigation Item')).toBeInTheDocument();
      });
    });

    it('creates item with default values', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('nav-tree-editor')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByTestId('add-item-btn'));

      await waitFor(() => {
        const labelInput = screen.getByDisplayValue('New Item');
        expect(labelInput).toBeInTheDocument();
      });
    });
  });

  describe('Edit Modal', () => {
    it('opens modal with item data when item is clicked', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByText('Shop Products')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByText('Shop Products'));

      await waitFor(() => {
        expect(screen.getByText('Edit Navigation Item')).toBeInTheDocument();
        expect(screen.getByDisplayValue('Shop Products')).toBeInTheDocument();
      });
    });

    it('closes modal on Cancel click', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByText('Shop Products')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByText('Shop Products'));

      await waitFor(() => {
        expect(screen.getByText('Edit Navigation Item')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByRole('button', { name: /cancel/i }));

      await waitFor(() => {
        expect(screen.queryByText('Edit Navigation Item')).not.toBeInTheDocument();
      });
    });

    it('saves changes on form submit', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByText('Home')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByText('Home'));

      await waitFor(() => {
        expect(screen.getByDisplayValue('Home')).toBeInTheDocument();
      });

      const labelInput = screen.getByDisplayValue('Home');
      await userEvent.clear(labelInput);
      await userEvent.type(labelInput, 'Homepage');

      await userEvent.click(screen.getByRole('button', { name: /save changes/i }));

      await waitFor(() => {
        expect(screen.queryByText('Edit Navigation Item')).not.toBeInTheDocument();
      });
    });
  });

  describe('Link Type Selection', () => {
    it('shows URL input for External URL type', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('add-item-btn')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByTestId('add-item-btn'));

      await waitFor(() => {
        expect(screen.getByText('Edit Navigation Item')).toBeInTheDocument();
      });

      const linkTypeSelect = screen.getByDisplayValue('No Link (dropdown parent)');
      await userEvent.selectOptions(linkTypeSelect, 'external');

      expect(screen.getByPlaceholderText('example.com')).toBeInTheDocument();
      expect(screen.getByText(/just enter the domain/i)).toBeInTheDocument();
    });

    it('shows page selector for Internal Page type', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('add-item-btn')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByTestId('add-item-btn'));

      await waitFor(() => {
        expect(screen.getByText('Edit Navigation Item')).toBeInTheDocument();
      });

      const linkTypeSelect = screen.getByDisplayValue('No Link (dropdown parent)');
      await userEvent.selectOptions(linkTypeSelect, 'page');

      await waitFor(() => {
        expect(screen.getByText(/choose a page/i)).toBeInTheDocument();
      });
    });

    it('shows info text for No Link type', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('add-item-btn')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByTestId('add-item-btn'));

      await waitFor(() => {
        expect(screen.getByText(/this item will serve as a dropdown parent/i)).toBeInTheDocument();
      });
    });

    it('hides Open in new tab checkbox for no-link items', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('add-item-btn')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByTestId('add-item-btn'));

      await waitFor(() => {
        expect(screen.getByText('Edit Navigation Item')).toBeInTheDocument();
      });

      // Default is 'none' link type
      expect(screen.queryByLabelText(/open in new tab/i)).not.toBeInTheDocument();

      // Switch to external - checkbox should appear
      const linkTypeSelect = screen.getByDisplayValue('No Link (dropdown parent)');
      await userEvent.selectOptions(linkTypeSelect, 'external');

      expect(screen.getByLabelText(/open in new tab/i)).toBeInTheDocument();
    });
  });

  describe('Page Selection', () => {
    it('fetches and displays available pages', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('add-item-btn')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByTestId('add-item-btn'));

      const linkTypeSelect = screen.getByDisplayValue('No Link (dropdown parent)');
      await userEvent.selectOptions(linkTypeSelect, 'page');

      await waitFor(() => {
        expect(screen.getByText(/about us/i)).toBeInTheDocument();
        expect(screen.getByText(/contact/i)).toBeInTheDocument();
      });
    });

    it('auto-populates label from selected page title', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('add-item-btn')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByTestId('add-item-btn'));

      const linkTypeSelect = screen.getByDisplayValue('No Link (dropdown parent)');
      await userEvent.selectOptions(linkTypeSelect, 'page');

      await waitFor(() => {
        expect(screen.getByText(/about us/i)).toBeInTheDocument();
      });

      // Find the page select by its default option text
      const pageSelect = screen.getByDisplayValue('-- Choose a page --');
      await userEvent.selectOptions(pageSelect, 'page-1');

      // Label should auto-populate since it was "New Item"
      await waitFor(() => {
        expect(screen.getByDisplayValue('About Us')).toBeInTheDocument();
      });
    });

    it('shows message when no pages exist', async () => {
      (global.fetch as jest.Mock).mockImplementation((url: string) => {
        if (url === '/api/cms/navigation') {
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({ items: mockNavItems, dealer: { id: 'dealer-123' } }),
          });
        }
        if (url === '/api/dealer') {
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve(mockDealerInfo),
          });
        }
        if (url === '/api/cms/pages?type=page') {
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({ pages: [] }),
          });
        }
        return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
      });

      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('add-item-btn')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByTestId('add-item-btn'));

      const linkTypeSelect = screen.getByDisplayValue('No Link (dropdown parent)');
      await userEvent.selectOptions(linkTypeSelect, 'page');

      await waitFor(() => {
        expect(screen.getByText(/no custom pages found/i)).toBeInTheDocument();
      });
    });
  });

  describe('URL Normalization', () => {
    it('adds https:// prefix on blur', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('add-item-btn')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByTestId('add-item-btn'));

      const linkTypeSelect = screen.getByDisplayValue('No Link (dropdown parent)');
      await userEvent.selectOptions(linkTypeSelect, 'external');

      const urlInput = screen.getByPlaceholderText('example.com');
      await userEvent.type(urlInput, 'www.amsoil.com');
      fireEvent.blur(urlInput);

      expect(urlInput).toHaveValue('https://www.amsoil.com');
    });

    it('preserves existing https:// prefix', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('add-item-btn')).toBeInTheDocument();
      });

      await userEvent.click(screen.getByTestId('add-item-btn'));

      const linkTypeSelect = screen.getByDisplayValue('No Link (dropdown parent)');
      await userEvent.selectOptions(linkTypeSelect, 'external');

      const urlInput = screen.getByPlaceholderText('example.com');
      await userEvent.type(urlInput, 'https://www.amsoil.com');
      fireEvent.blur(urlInput);

      expect(urlInput).toHaveValue('https://www.amsoil.com');
    });
  });

  describe('Validation', () => {
    it('validates navigation structure and calls validation library', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('nav-tree-editor')).toBeInTheDocument();
      });

      // Click publish to trigger validation
      const publishBtn = screen.getByRole('button', { name: /publish/i });
      fireEvent.click(publishBtn);

      // Validation should have been called
      expect(validateNavigation).toHaveBeenCalled();
    });

    it('displays validation warning when structure is invalid', async () => {
      // Mock returns invalid from the start
      (validateNavigation as jest.Mock).mockReturnValue({
        valid: false,
        error: 'Too many items',
      });

      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByTestId('nav-tree-editor')).toBeInTheDocument();
      });

      // Try to publish - validation blocks it
      fireEvent.click(screen.getByRole('button', { name: /publish/i }));

      // Warning should be displayed (button disabled shows validation is working)
      await waitFor(() => {
        expect(screen.getByText(/too many items/i)).toBeInTheDocument();
      });

      // Button should have validation tooltip
      expect(screen.getByRole('button', { name: /publish/i })).toHaveAttribute(
        'title',
        'Fix validation errors before publishing'
      );
    });
  });

  describe('Publish Flow', () => {
    it('calls PUT API with navigation items', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByRole('button', { name: /publish/i })).toBeInTheDocument();
      });

      await userEvent.click(screen.getByRole('button', { name: /publish/i }));

      await waitFor(() => {
        expect(global.fetch).toHaveBeenCalledWith(
          '/api/cms/navigation',
          expect.objectContaining({
            method: 'PUT',
            body: expect.stringContaining('"publish":true'),
          })
        );
      });
    });

    it('calls dealer publish API after saving navigation', async () => {
      (global.fetch as jest.Mock).mockImplementation((url: string, options?: RequestInit) => {
        if (url === '/api/cms/navigation') {
          if (options?.method === 'PUT') {
            return Promise.resolve({ ok: true, json: () => Promise.resolve({ success: true }) });
          }
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({ items: mockNavItems, dealer: { id: 'dealer-123' } }),
          });
        }
        if (url === '/api/dealer') {
          return Promise.resolve({ ok: true, json: () => Promise.resolve(mockDealerInfo) });
        }
        if (url === '/api/dealers/dealer-123/publish') {
          return Promise.resolve({ ok: true, json: () => Promise.resolve({ success: true }) });
        }
        return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
      });

      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByRole('button', { name: /publish/i })).toBeInTheDocument();
      });

      await userEvent.click(screen.getByRole('button', { name: /publish/i }));

      await waitFor(() => {
        expect(global.fetch).toHaveBeenCalledWith(
          '/api/dealers/dealer-123/publish',
          expect.objectContaining({ method: 'POST' })
        );
      });
    });

    it('shows success toast on completion', async () => {
      (global.fetch as jest.Mock).mockImplementation((url: string, options?: RequestInit) => {
        if (url === '/api/cms/navigation') {
          if (options?.method === 'PUT') {
            return Promise.resolve({ ok: true, json: () => Promise.resolve({ success: true }) });
          }
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({ items: mockNavItems, dealer: { id: 'dealer-123' } }),
          });
        }
        if (url === '/api/dealer') {
          return Promise.resolve({ ok: true, json: () => Promise.resolve(mockDealerInfo) });
        }
        if (url === '/api/dealers/dealer-123/publish') {
          return Promise.resolve({ ok: true, json: () => Promise.resolve({ success: true }) });
        }
        return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
      });

      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByRole('button', { name: /publish/i })).toBeInTheDocument();
      });

      await userEvent.click(screen.getByRole('button', { name: /publish/i }));

      await waitFor(() => {
        expect(mockShowToast).toHaveBeenCalledWith('Published successfully!', 'success');
      });
    });

    it('shows error toast on failure', async () => {
      (global.fetch as jest.Mock).mockImplementation((url: string, options?: RequestInit) => {
        if (url === '/api/cms/navigation') {
          if (options?.method === 'PUT') {
            return Promise.resolve({
              ok: false,
              json: () => Promise.resolve({ error: 'Failed to save' }),
            });
          }
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({ items: mockNavItems, dealer: { id: 'dealer-123' } }),
          });
        }
        if (url === '/api/dealer') {
          return Promise.resolve({ ok: true, json: () => Promise.resolve(mockDealerInfo) });
        }
        return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
      });

      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByRole('button', { name: /publish/i })).toBeInTheDocument();
      });

      await userEvent.click(screen.getByRole('button', { name: /publish/i }));

      await waitFor(() => {
        expect(mockShowToast).toHaveBeenCalledWith('Failed to save', 'error');
      });
    });

    it('shows Publishing... during operation', async () => {
      let resolvePublish: () => void;
      (global.fetch as jest.Mock).mockImplementation((url: string, options?: RequestInit) => {
        if (url === '/api/cms/navigation') {
          if (options?.method === 'PUT') {
            return new Promise((resolve) => {
              resolvePublish = () => resolve({ ok: true, json: () => Promise.resolve({}) });
            });
          }
          return Promise.resolve({
            ok: true,
            json: () => Promise.resolve({ items: mockNavItems, dealer: { id: 'dealer-123' } }),
          });
        }
        if (url === '/api/dealer') {
          return Promise.resolve({ ok: true, json: () => Promise.resolve(mockDealerInfo) });
        }
        return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
      });

      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByRole('button', { name: /publish/i })).toBeInTheDocument();
      });

      // Use fireEvent.click instead of userEvent.click to avoid waiting
      const publishButton = screen.getByRole('button', { name: /publish/i });
      fireEvent.click(publishButton);

      // Now the button should show "Publishing..." state
      await waitFor(() => {
        expect(screen.getByRole('button', { name: /publishing/i })).toBeInTheDocument();
      });

      // Resolve to clean up
      resolvePublish!();

      // Wait for state to settle
      await waitFor(() => {
        expect(screen.queryByRole('button', { name: /publishing/i })).not.toBeInTheDocument();
      });
    });
  });

  describe('Help Section', () => {
    it('displays help text with usage instructions', async () => {
      render(<NavigationEditorPage />);

      await waitFor(() => {
        expect(screen.getByText(/navigation editor help/i)).toBeInTheDocument();
      });

      expect(screen.getByText(/drag items/i)).toBeInTheDocument();
      expect(screen.getByText(/maximum limits/i)).toBeInTheDocument();
    });
  });
});
