// @vitest-environment jsdom
import { beforeEach, afterEach, describe, expect, it, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
// import userEvent from '@testing-library/user-event';
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 }
        },
        connected: true
    },
    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 }
    }
}));

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

// Mock components
vi.mock('./components/AlertFeed', () => ({ AlertFeed: () => <div>AlertFeedMock</div> }));
vi.mock('./components/MarketOpportunities', () => ({ AISetups: () => <div>AISetups</div>, TopVolatile: () => <div>TopVolatile</div> }));
vi.mock('./tabs/OverviewTab', () => ({ OverviewTab: () => <div>OverviewTab</div> }));
vi.mock('./tabs/SignalsTab', () => ({ SignalsTab: () => <div>SignalsTab</div> }));
vi.mock('./tabs/PositionsTab', () => ({ PositionsTab: () => <div>PositionsTab</div> }));
vi.mock('./tabs/HistoryTab', () => ({ HistoryTab: () => <div>HistoryTab</div> }));
vi.mock('./tabs/SettingsTab', () => ({ SettingsTab: () => <div>SettingsTab</div> }));
vi.mock('./tabs/EntriesTab', () => ({ EntriesTab: () => <div>EntriesTab</div> }));
vi.mock('./tabs/AdminTab', () => ({ AdminTab: () => <div>AdminTab</div> }));
vi.mock('./components/TradeProfileManager', () => ({ TradeProfileManager: () => <div>TradeProfileManager</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> }));

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 }
        };

        fetchTradeProfilesMock.mockResolvedValue([]);
        createTradeProfileMock.mockResolvedValue({});
        updateTradeProfileMock.mockResolvedValue({});

        vi.stubGlobal('location', { pathname: '/' });
    });

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

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

    it('renders main dashboard and handles tab switching', async () => {
        authMock.user = { id: 'u1', email: 'test@demo.com' };
        render(<App />);

        expect(screen.getByText('Trading Bot Dashboard')).toBeInTheDocument();

        const positionsBtn = screen.getByText('Positions & Orders');
        fireEvent.click(positionsBtn);
        expect(screen.getByText('PositionsTab')).toBeInTheDocument();

        const historyBtn = screen.getByText('Trade History');
        fireEvent.click(historyBtn);
        expect(screen.getByText('HistoryTab')).toBeInTheDocument();
    });

    it('guards admin tab', async () => {
        authMock.user = { id: 'u1', email: 'test@demo.com' };
        authMock.profile = { role: 'user' };
        render(<App />);
        expect(screen.queryByText(/Admin/i)).not.toBeInTheDocument();
    });

    it('allows admin tab access for admin role', async () => {
        authMock.user = { id: 'u1', email: 'test@demo.com' };
        authMock.profile = { role: 'admin' };
        render(<App />);

        const adminBtn = screen.getByText(/Admin/i);
        fireEvent.click(adminBtn);
        expect(screen.getByText('AdminTab')).toBeInTheDocument();
    });

    it('displays different health states', async () => {
        authMock.user = { id: 'u1' };
        const { rerender } = render(<App />);

        expect(screen.getByText('Healthy')).toBeInTheDocument();

        socketMock.botState.health = { tradingLoopHealthy: false, reconciliationLoopHealthy: true, capitalInvariantViolations: 0 };
        rerender(<App />);
        expect(screen.getByText('Degraded')).toBeInTheDocument();

        socketMock.botState.health = { tradingLoopHealthy: true, reconciliationLoopHealthy: true, capitalInvariantViolations: 1 };
        rerender(<App />);
        expect(screen.getByText('Unhealthy')).toBeInTheDocument();
    });

    it('handles logout', async () => {
        authMock.user = { id: 'u1' };
        render(<App />);
        const logoutBtn = screen.getByText('Logout');
        fireEvent.click(logoutBtn);
        expect(authMock.signOut).toHaveBeenCalled();
    });
});

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');
    });
});
