import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { vi, describe, it, expect, beforeEach } from 'vitest';
import { useRouter, usePathname, useSearchParams } from 'next/navigation';
import AdminOrders from '../page';

vi.mock('next/navigation', () => ({
  useRouter: vi.fn(),
  usePathname: vi.fn(() => '/admin/orders'),
  useSearchParams: vi.fn(),
}));

const listMock = vi.fn();
vi.mock('@/lib/api', () => ({
  api: { admin: { listOrders: (...a: unknown[]) => listMock(...a) } },
}));

function wrap(node: React.ReactNode) {
  const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } });
  return <QueryClientProvider client={qc}>{node}</QueryClientProvider>;
}

const orderRow = {
  id: '11111111-2222-3333-4444-555555555555',
  purchase_id: 'pp',
  store: { id: 's1', name: 'Revive' },
  buyer: { first_name: 'Jane', last_name: 'Doe' },
  status: 'pending',
  subtotal: 2500,
  shipping_cost: 500,
  total: 3000,
  item_count: 2,
  created_at: '2026-04-01T00:00:00Z',
};

describe('AdminOrders', () => {
  const replace = vi.fn();
  let currentParams = new URLSearchParams('');

  beforeEach(() => {
    listMock.mockReset();
    replace.mockReset();
    currentParams = new URLSearchParams('');
    vi.mocked(useRouter).mockReturnValue({
      replace: (url: string) => {
        replace(url);
        const qs = url.split('?')[1] ?? '';
        currentParams = new URLSearchParams(qs);
      },
      push: vi.fn(), back: vi.fn(), forward: vi.fn(), refresh: vi.fn(), prefetch: vi.fn(),
    } as unknown as ReturnType<typeof useRouter>);
    vi.mocked(useSearchParams).mockImplementation(
      () => currentParams as unknown as ReturnType<typeof useSearchParams>,
    );
    vi.mocked(usePathname).mockReturnValue('/admin/orders');
  });

  it('renders rows with formatted totals and status', async () => {
    listMock.mockResolvedValue({
      data: [orderRow],
      meta: { current_page: 1, last_page: 1, total: 1, per_page: 15 },
    });
    render(wrap(<AdminOrders />));
    await waitFor(() => expect(screen.getByText('Jane Doe')).toBeInTheDocument());
    expect(screen.getByText('Revive')).toBeInTheDocument();
    expect(screen.getByText('$30.00')).toBeInTheDocument();
    expect(screen.getByText('1 order')).toBeInTheDocument();
    // Truncated id
    expect(screen.getByText('11111111')).toBeInTheDocument();
  });

  it('clicking a status pill writes URL and passes status to the API', async () => {
    listMock.mockResolvedValue({
      data: [],
      meta: { current_page: 1, last_page: 1, total: 0, per_page: 15 },
    });
    const { rerender } = render(wrap(<AdminOrders />));
    fireEvent.click(screen.getByRole('button', { name: 'Shipped' }));
    expect(replace).toHaveBeenCalledWith('/admin/orders?status=shipped');

    rerender(wrap(<AdminOrders />));
    await waitFor(() => {
      const lastCall = listMock.mock.calls[listMock.mock.calls.length - 1][0];
      expect(lastCall).toMatchObject({ status: 'shipped' });
    });
  });

  it('shows empty state when API returns no rows', async () => {
    listMock.mockResolvedValue({
      data: [],
      meta: { current_page: 1, last_page: 1, total: 0, per_page: 15 },
    });
    render(wrap(<AdminOrders />));
    await waitFor(() => expect(screen.getByText('No orders match.')).toBeInTheDocument());
  });

  it('shows error banner when API rejects', async () => {
    listMock.mockRejectedValue(new Error('forbidden'));
    render(wrap(<AdminOrders />));
    await waitFor(() =>
      expect(screen.getByText(/Couldn't load orders/)).toBeInTheDocument(),
    );
  });
});
