// @vitest-environment jsdom
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { AppContext, type AppContextValue } from '../context/AppContext';
import { HomeView } from './HomeView';

const {
  fetchChartBarsMock,
  fetchResearchEarningsMock,
  fetchResearchMetricsMock,
  fetchResearchProfileMock,
} = vi.hoisted(() => ({
  fetchChartBarsMock: vi.fn(),
  fetchResearchEarningsMock: vi.fn(),
  fetchResearchMetricsMock: vi.fn(),
  fetchResearchProfileMock: vi.fn(),
}));

vi.mock('../lib/marketApi', () => ({
  fetchChartBars: fetchChartBarsMock,
  fetchResearchEarnings: fetchResearchEarningsMock,
  fetchResearchMetrics: fetchResearchMetricsMock,
  fetchResearchProfile: fetchResearchProfileMock,
}));

const appContext: AppContextValue = {
  botState: {
    settings: { isAlgoEnabled: true },
    symbols: {
      AAPL: {
        price: 212.42,
        changeToday: 1.5,
      },
    },
    health: { tradingLoopHealthy: true, reconciliationLoopHealthy: true, capitalInvariantViolations: 0 },
    alerts: [],
    positions: [],
    orders: [],
    history: [],
    uptime: 0,
  } as any,
  socket: null,
  connected: true,
  activeSymbol: 'AAPL',
  setActiveSymbol: vi.fn(),
  isAdmin: false,
  user: { id: 'u1' },
  profile: {},
  showBacktestTab: false,
  showMarketplaceTab: false,
  handleSignOut: vi.fn(),
};

function renderTickerHeader(contextValue: AppContextValue = appContext) {
  return render(
    <AppContext.Provider value={contextValue}>
      <MemoryRouter initialEntries={['/']}>
        <Routes>
          <Route path="/" element={<HomeView />} />
          <Route path="/watchlist" element={<div>Watchlist route</div>} />
          <Route path="/alerts" element={<div>Alerts route</div>} />
        </Routes>
      </MemoryRouter>
    </AppContext.Provider>,
  );
}

describe('TickerHeader', () => {
  beforeEach(() => {
    fetchChartBarsMock.mockResolvedValue([]);
    fetchResearchEarningsMock.mockResolvedValue([]);
    fetchResearchMetricsMock.mockResolvedValue({});
    fetchResearchProfileMock.mockReset();
  });

  it('loads the company name from the research profile', async () => {
    fetchResearchProfileMock.mockResolvedValueOnce({ companyName: 'Apple Inc.' });

    renderTickerHeader();

    expect(screen.getByRole('heading', { name: 'AAPL' })).toBeInTheDocument();
    await waitFor(() => expect(screen.getAllByText('Apple Inc.').length).toBeGreaterThan(0));
  });

  it('opens watchlist and alerts routes from header actions', async () => {
    fetchResearchProfileMock.mockResolvedValue({ companyName: 'Apple Inc.', exchangeShortName: 'NYSE' });
    const user = userEvent.setup();

    const firstRender = renderTickerHeader();

    await user.click(screen.getByRole('button', { name: /open watchlist/i }));
    expect(screen.getByText('Watchlist route')).toBeInTheDocument();
    firstRender.unmount();

    renderTickerHeader();
    await user.click(screen.getByRole('button', { name: /open alerts/i }));
    expect(screen.getByText('Alerts route')).toBeInTheDocument();
  });

  it('shares the research profile request between header and research cards', async () => {
    fetchResearchProfileMock.mockResolvedValueOnce({
      companyName: 'Apple Inc.',
      sector: 'Technology',
    });

    renderTickerHeader();

    await waitFor(() => expect(screen.getAllByText('Apple Inc.').length).toBeGreaterThan(0));
    expect(fetchResearchProfileMock).toHaveBeenCalledTimes(1);
  });

  it('shows the latest chart bar timestamp instead of the render time', async () => {
    fetchResearchProfileMock.mockResolvedValue({ companyName: 'Apple Inc.', exchangeShortName: 'NYSE' });
    fetchChartBarsMock.mockResolvedValueOnce([
      { ts: Date.UTC(2024, 0, 3, 19, 30), open: 210, high: 213, low: 209, close: 212, volume: 1000 },
      { ts: Date.UTC(2024, 0, 3, 20, 30), open: 212, high: 214, low: 211, close: 213, volume: 1200 },
    ]);

    renderTickerHeader();

    expect(screen.getByText(/Latest bar pending ET/)).toBeInTheDocument();
    await waitFor(() => {
      expect(screen.getByText(/Jan 3, 2024, 03:30 PM ET · NYSE/)).toBeInTheDocument();
    });
  });

  it('falls back to a neutral exchange marker when profile exchange is unavailable', async () => {
    fetchResearchProfileMock.mockResolvedValue({ companyName: 'Apple Inc.' });

    renderTickerHeader();

    await waitFor(() => expect(screen.getByText(/Latest bar pending ET · —/)).toBeInTheDocument());
  });

  it('derives quick stats from chart bars for symbols missing bot indicators', async () => {
    fetchResearchProfileMock.mockResolvedValue({ companyName: 'Microsoft Corporation' });
    fetchChartBarsMock.mockResolvedValueOnce(
      Array.from({ length: 220 }, (_, index) => ({
        ts: Date.UTC(2024, 0, 1 + index),
        open: 100,
        high: 100,
        low: 100,
        close: 100,
        volume: 1000,
      })),
    );
    const searchedContext: AppContextValue = {
      ...appContext,
      activeSymbol: 'MSFT',
      botState: {
        ...appContext.botState,
        symbols: {},
      } as any,
    };

    renderTickerHeader(searchedContext);

    await waitFor(() => expect(screen.getByText('50.0')).toBeInTheDocument());
    expect(screen.getAllByText('100.00').length).toBeGreaterThanOrEqual(2);
  });

  it('uses configured crypto symbols for empty-state suggestions', async () => {
    const user = userEvent.setup();
    const setActiveSymbol = vi.fn();
    const cryptoContext: AppContextValue = {
      ...appContext,
      activeSymbol: '',
      setActiveSymbol,
      profile: { symbols: 'BTC/USDT, ETH/USDT', market_type: 'crypto' },
      botState: {
        ...appContext.botState,
        symbols: {},
      } as any,
    };

    renderTickerHeader(cryptoContext);

    expect(screen.getByRole('button', { name: 'BTC/USDT' })).toBeInTheDocument();
    expect(screen.queryByRole('button', { name: 'AAPL' })).not.toBeInTheDocument();

    await user.click(screen.getByRole('button', { name: 'ETH/USDT' }));
    expect(setActiveSymbol).toHaveBeenCalledWith('ETH/USDT');
  });
});
