import { describe, it, expect } from 'vitest';
import { screen, waitFor, within } from '@testing-library/react';
import { HttpResponse, http } from 'msw';
import { renderRoute } from './render';
import { server } from './mocks/server';

describe('Positions page', () => {
  // -------------------------------------------------------------------------
  // 1. Renders positions table with data
  // -------------------------------------------------------------------------
  it('renders positions table with ticker and quantity', async () => {
    renderRoute('/positions');
    await waitFor(() => {
      expect(screen.getByText('AAPL')).toBeInTheDocument();
    });
    const row = screen.getByText('AAPL').closest('tr')!;
    expect(row).toHaveTextContent('10');
  });

  // -------------------------------------------------------------------------
  // 2. Displays formatted USD prices
  // -------------------------------------------------------------------------
  it('displays entry and current prices in USD format', async () => {
    renderRoute('/positions');
    await waitFor(() => {
      expect(screen.getByText('AAPL')).toBeInTheDocument();
    });
    expect(screen.getByText('$185.50')).toBeInTheDocument();
    expect(screen.getByText('$188.20')).toBeInTheDocument();
  });

  // -------------------------------------------------------------------------
  // 3. Displays unrealized and realized PnL
  // -------------------------------------------------------------------------
  it('displays unrealized and realized PnL', async () => {
    renderRoute('/positions');
    await waitFor(() => {
      expect(screen.getByText('AAPL')).toBeInTheDocument();
    });
    const row = screen.getByText('AAPL').closest('tr')!;
    expect(row).toHaveTextContent('$27.00');
    expect(row).toHaveTextContent('$0.00');
  });

  // -------------------------------------------------------------------------
  // 4. PnL color coding — green for positive
  // -------------------------------------------------------------------------
  it('applies green color to positive unrealized PnL', async () => {
    renderRoute('/positions');
    await waitFor(() => {
      expect(screen.getByText('AAPL')).toBeInTheDocument();
    });
    const row = screen.getByText('AAPL').closest('tr')!;
    const pnlEl = within(row).getByText('$27.00');
    expect(pnlEl.className).toContain('text-green');
  });

  // -------------------------------------------------------------------------
  // 5. Totals row renders with correct sums
  // -------------------------------------------------------------------------
  it('renders totals row with correct sums', async () => {
    renderRoute('/positions');
    await waitFor(() => {
      expect(screen.getByText('Totals')).toBeInTheDocument();
    });
    const totalsRow = screen.getByText('Totals').closest('tr')!;
    const cells = within(totalsRow).getAllByRole('cell');
    // Totals: label, qty, cost basis, market value, unrealized, realized, empty
    expect(cells[0]).toHaveTextContent('Totals');
    expect(cells[1]).toHaveTextContent('10');
    // cost basis = 10 * 185.50 = 1855.00
    expect(cells[2]).toHaveTextContent('$1855.00');
    // market value = 10 * 188.20 = 1882.00
    expect(cells[3]).toHaveTextContent('$1882.00');
    // unrealized = 27.00
    expect(cells[4]).toHaveTextContent('$27.00');
    // realized = 0.00
    expect(cells[5]).toHaveTextContent('$0.00');
  });

  // -------------------------------------------------------------------------
  // 6. Empty state — no positions
  // -------------------------------------------------------------------------
  it('shows empty state when no positions exist', async () => {
    server.use(
      http.get('/api/positions', () => HttpResponse.json([])),
    );
    renderRoute('/positions');
    await waitFor(() => {
      expect(screen.getByText('No data')).toBeInTheDocument();
    });
    // Totals row should NOT render when empty
    expect(screen.queryByText('Totals')).not.toBeInTheDocument();
  });

  // -------------------------------------------------------------------------
  // 7. Multiple positions — totals sum correctly
  // -------------------------------------------------------------------------
  it('sums totals correctly with multiple positions', async () => {
    server.use(
      http.get('/api/positions', () => HttpResponse.json([
        { id: 'p1', broker_account_id: null, ticker: 'AAPL', quantity: 10, avg_entry_price: 185.50, current_price: 188.20, unrealized_pnl: 27.00, realized_pnl: 0, updated_at: '2026-04-11T12:00:00Z' },
        { id: 'p2', broker_account_id: null, ticker: 'MSFT', quantity: 5, avg_entry_price: 420.00, current_price: 415.00, unrealized_pnl: -25.00, realized_pnl: 50.00, updated_at: '2026-04-11T12:00:00Z' },
      ])),
    );
    renderRoute('/positions');
    await waitFor(() => {
      expect(screen.getByText('Totals')).toBeInTheDocument();
    });
    const totalsRow = screen.getByText('Totals').closest('tr')!;
    const cells = within(totalsRow).getAllByRole('cell');
    // qty = 10 + 5 = 15
    expect(cells[1]).toHaveTextContent('15');
    // cost basis = (10*185.50) + (5*420.00) = 1855 + 2100 = 3955.00
    expect(cells[2]).toHaveTextContent('$3955.00');
    // market value = (10*188.20) + (5*415.00) = 1882 + 2075 = 3957.00
    expect(cells[3]).toHaveTextContent('$3957.00');
    // unrealized = 27 + (-25) = 2.00
    expect(cells[4]).toHaveTextContent('$2.00');
    // realized = 0 + 50 = 50.00
    expect(cells[5]).toHaveTextContent('$50.00');
  });

  // -------------------------------------------------------------------------
  // 8. Negative PnL gets red color
  // -------------------------------------------------------------------------
  it('applies red color to negative unrealized PnL', async () => {
    server.use(
      http.get('/api/positions', () => HttpResponse.json([
        { id: 'p1', broker_account_id: null, ticker: 'TSLA', quantity: 3, avg_entry_price: 250.00, current_price: 240.00, unrealized_pnl: -30.00, realized_pnl: 0, updated_at: '2026-04-11T12:00:00Z' },
      ])),
    );
    renderRoute('/positions');
    await waitFor(() => {
      expect(screen.getByText('TSLA')).toBeInTheDocument();
    });
    const row = screen.getByText('TSLA').closest('tr')!;
    const pnlEl = within(row).getByText('$-30.00');
    expect(pnlEl.className).toContain('text-red');
  });

  // -------------------------------------------------------------------------
  // 9. Updated timestamp renders
  // -------------------------------------------------------------------------
  it('renders the updated_at timestamp', async () => {
    renderRoute('/positions');
    await waitFor(() => {
      expect(screen.getByText('AAPL')).toBeInTheDocument();
    });
    // The component renders new Date(r.updated_at).toLocaleString()
    // Just verify something date-like appears in the row
    const row = screen.getByText('AAPL').closest('tr')!;
    expect(row).toHaveTextContent('2026');
  });

  // -------------------------------------------------------------------------
  // 10. Page title renders
  // -------------------------------------------------------------------------
  it('renders the page title', async () => {
    renderRoute('/positions');
    await waitFor(() => {
      expect(screen.getByText('Positions')).toBeInTheDocument();
    });
  });
});
