// @vitest-environment jsdom
import { beforeEach, afterEach, describe, expect, it, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import App, { resolveProfileNameForAction, buildChatApplyPayload } from './App';

const { authMock, socketMock, fetchTradeProfilesMock, createTradeProfileMock, updateTradeProfileMock } = vi.hoisted(() => ({
    authMock: { user: null as any, profile: null as any, loading: false, signOut: vi.fn() },
    socketMock: {
        botState: {
            settings: { isAlgoEnabled: true },
            symbols: {},
            health: { tradingLoopHealthy: true, reconciliationLoopHealthy: true, capitalInvariantViolations: 0 },
            alerts: [],
            positions: [],
            orders: [],
            history: [],
            uptime: 0,
        },
        connected: true,
        socket: null,
    },
    fetchTradeProfilesMock: vi.fn(),
    createTradeProfileMock: vi.fn(),
    updateTradeProfileMock: vi.fn()
}));

vi.mock('./components/AuthContext', () => ({
    useAuth: () => authMock
}));

vi.mock('./hooks/useWebSocket', () => ({
    useWebSocket: () => socketMock,
    DEFAULT_BOT_STATE: {
        settings: { isAlgoEnabled: true },
        symbols: {},
        health: { tradingLoopHealthy: true, reconciliationLoopHealthy: true, capitalInvariantViolations: 0 },
        alerts: [],
        positions: [],
        orders: [],
        history: [],
        uptime: 0,
    }
}));

vi.mock('./lib/profileApi', () => ({
    fetchTradeProfiles: fetchTradeProfilesMock,
    createTradeProfile: createTradeProfileMock,
    updateTradeProfile: updateTradeProfileMock
}));

// Mock all layout and view components — they have external dependencies
vi.mock('./components/layout/AppShell', () => ({
    AppShell: () => (
        <div data-testid="app-shell">
            <nav>
                <a href="/">Home</a>
                <a href="/portfolio">Portfolio</a>
                <a href="/research">Research</a>
                <a href="/settings">Settings</a>
            </nav>
            <main data-testid="main-content">Dashboard Content</main>
        </div>
    )
}));

vi.mock('./components/AlertFeed', () => ({ AlertFeed: () => <div>AlertFeedMock</div> }));
vi.mock('./components/MarketOpportunities', () => ({
    AISetups: () => <div>AISetups</div>,
    TopVolatile: () => <div>TopVolatile</div>
}));
vi.mock('./components/ChatControl', () => ({
    ChatControl: ({ onApplyProfile }: any) => (
        <button onClick={() => onApplyProfile('create_profile', { name: 'New' })}>ApplyChat</button>
    )
}));
vi.mock('./components/Login', () => ({ Login: () => <div>LoginMock</div> }));
vi.mock('./components/ResetPassword', () => ({ ResetPassword: () => <div>ResetPasswordMock</div> }));
vi.mock('./backtest/flags', () => ({
    useBacktestFeatureGate: () => ({ enabled: false, loading: false }),
    isBacktestBuildEnabled: () => false,
}));
vi.mock('./hooks/useTabFeatureFlags', () => ({
    useTabFeatureFlags: () => ({ flags: { marketplace: false } })
}));

describe('App Component DOM', () => {
    beforeEach(() => {
        vi.useFakeTimers();
        authMock.user = null;
        authMock.profile = null;
        authMock.loading = false;
        socketMock.botState = {
            settings: { isAlgoEnabled: true },
            symbols: {},
            health: { tradingLoopHealthy: true, reconciliationLoopHealthy: true, capitalInvariantViolations: 0 },
            alerts: [],
            positions: [],
            orders: [],
            history: [],
            uptime: 0,
        };
        fetchTradeProfilesMock.mockResolvedValue([]);
        createTradeProfileMock.mockResolvedValue({});
        updateTradeProfileMock.mockResolvedValue({});
    });

    afterEach(() => {
        vi.useRealTimers();
    });

    it('renders login when not authenticated', () => {
        render(<App />);
        expect(screen.getByText('LoginMock')).toBeInTheDocument();
    });

    it('renders main dashboard when authenticated', async () => {
        authMock.user = { id: 'u1', email: 'test@demo.com' };
        render(<App />);
        expect(screen.getByTestId('app-shell')).toBeInTheDocument();
        expect(screen.getByTestId('main-content')).toBeInTheDocument();
    });

    it('shows sidebar nav links when authenticated', () => {
        authMock.user = { id: 'u1', email: 'test@demo.com' };
        render(<App />);
        expect(screen.getByText('Portfolio')).toBeInTheDocument();
        expect(screen.getByText('Research')).toBeInTheDocument();
        expect(screen.getByText('Settings')).toBeInTheDocument();
    });

    it('admin sees settings route (not hidden)', () => {
        authMock.user = { id: 'u1', email: 'test@demo.com' };
        authMock.profile = { role: 'admin' };
        render(<App />);
        // Admin can access settings which includes admin panel
        expect(screen.getByText('Settings')).toBeInTheDocument();
    });

    it('non-admin user still has settings nav', () => {
        authMock.user = { id: 'u1', email: 'test@demo.com' };
        authMock.profile = { role: 'user' };
        render(<App />);
        expect(screen.getByText('Settings')).toBeInTheDocument();
    });
});

describe('App Logic Helpers', () => {
    it('resolveProfileNameForAction appends time on collision', () => {
        const profiles = [{ name: 'Alpha' }];
        const res = resolveProfileNameForAction('create_profile', 'Alpha', profiles, () => '123');
        expect(res).toBe('Alpha (123)');
    });

    it('buildChatApplyPayload uses defaults', () => {
        const payload = buildChatApplyPayload({}, 'u1', 'Name');
        expect(payload.symbols).toBe('BTC/USDT');
    });
});
