import { render, screen, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { vi, describe, it, expect, beforeEach } from 'vitest';
import { AdminBalancesClient } from '../admin-balances-client';

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

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

describe('AdminBalancesClient', () => {
  beforeEach(() => {
    balancesMock.mockReset();
  });

  it('renders summary tiles + per-store rows when balances load', async () => {
    balancesMock.mockResolvedValue({
      data: {
        total_pending_cents: 1234500,
        total_available_cents: 9876500,
        stores: [
          {
            store_id: 'store-aaa',
            store_name: 'Northern Atelier',
            pending_cents: 12500,
            available_cents: 87500,
          },
          {
            store_id: 'store-bbb',
            store_name: 'Coastal Goods',
            pending_cents: 6000,
            available_cents: 14000,
          },
        ],
      },
    });

    render(wrap(<AdminBalancesClient />));
    await waitFor(() =>
      expect(
        screen.getByTestId('admin-balances-summary'),
      ).toBeInTheDocument(),
    );

    // Total tiles
    expect(screen.getByText('$12345.00')).toBeInTheDocument();
    expect(screen.getByText('$98765.00')).toBeInTheDocument();

    // Per-store rows
    expect(
      screen.getByTestId('admin-balances-row-store-aaa'),
    ).toBeInTheDocument();
    expect(screen.getByText('Northern Atelier')).toBeInTheDocument();
    expect(screen.getByText('Coastal Goods')).toBeInTheDocument();
  });

  it('renders empty state when zero stores have balances', async () => {
    balancesMock.mockResolvedValue({
      data: {
        total_pending_cents: 0,
        total_available_cents: 0,
        stores: [],
      },
    });
    render(wrap(<AdminBalancesClient />));
    expect(
      await screen.findByTestId('admin-balances-empty'),
    ).toBeInTheDocument();
  });

  it('renders loading state', () => {
    balancesMock.mockReturnValue(new Promise(() => {}));
    render(wrap(<AdminBalancesClient />));
    expect(screen.getByTestId('admin-balances-loading')).toBeInTheDocument();
  });

  it('renders error state on failure', async () => {
    balancesMock.mockRejectedValue(new Error('boom'));
    render(wrap(<AdminBalancesClient />));
    expect(
      await screen.findByTestId('admin-balances-error'),
    ).toBeInTheDocument();
  });

  it('store name links to /admin/stores/[id]', async () => {
    balancesMock.mockResolvedValue({
      data: {
        total_pending_cents: 0,
        total_available_cents: 100,
        stores: [
          {
            store_id: 'store-xyz',
            store_name: 'Click Me',
            pending_cents: 0,
            available_cents: 100,
          },
        ],
      },
    });
    render(wrap(<AdminBalancesClient />));
    const link = await screen.findByRole('link', { name: /Click Me/i });
    expect(link).toHaveAttribute('href', '/admin/stores/store-xyz');
  });
});
