// @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 { TradeProfileManager } from './TradeProfileManager';
import { tableNameTransactions } from '../lib/const';

const {
    authState,
    fromMock,
    historySelectMock,
    fetchTradeProfilesMock,
    fetchCurrentUserProfileMock,
    createTradeProfileMock,
    updateTradeProfileMock,
    deleteTradeProfileMock,
    setTradeProfileActiveMock
} = vi.hoisted(() => ({
    authState: {
        user: { id: 'user-1', email: 'owner@demo.test' } as any,
        profile: { role: 'admin' } as any
    },
    fromMock: vi.fn(),
    historySelectMock: vi.fn(),
    fetchTradeProfilesMock: vi.fn(),
    fetchCurrentUserProfileMock: vi.fn(),
    createTradeProfileMock: vi.fn(),
    updateTradeProfileMock: vi.fn(),
    deleteTradeProfileMock: vi.fn(),
    setTradeProfileActiveMock: vi.fn()
}));

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

vi.mock('../lib/supabaseClient', () => ({
    supabase: {
        from: fromMock
    }
}));

vi.mock('../lib/profileApi', () => ({
    fetchTradeProfiles: fetchTradeProfilesMock,
    fetchCurrentUserProfile: fetchCurrentUserProfileMock,
    createTradeProfile: createTradeProfileMock,
    updateTradeProfile: updateTradeProfileMock,
    deleteTradeProfile: deleteTradeProfileMock,
    setTradeProfileActive: setTradeProfileActiveMock
}));

describe('TradeProfileManager DOM flow', () => {
    beforeEach(() => {
        authState.user = { id: 'user-1', email: 'owner@demo.test' };
        authState.profile = { role: 'admin' };

        fromMock.mockReset();
        historySelectMock.mockReset();
        fetchTradeProfilesMock.mockReset();
        fetchCurrentUserProfileMock.mockReset();
        createTradeProfileMock.mockReset();
        updateTradeProfileMock.mockReset();
        deleteTradeProfileMock.mockReset();
        setTradeProfileActiveMock.mockReset();

        fetchTradeProfilesMock.mockResolvedValue([
            {
                id: 'profile-1',
                user_id: 'user-1',
                name: 'High Risk Scalper',
                allocated_capital: 3000,
                risk_per_trade_percent: 1.5,
                symbols: 'BTC/USDT, ETH/USDT',
                is_active: true,
                strategy_config: {
                    rules: [
                        { ruleId: 'TrendBiasRule', enabled: true, params: { fastPeriod: 50, slowPeriod: 200 } },
                        { ruleId: 'MomentumRule', enabled: true, params: { rsiPeriod: 14, overbought: 70, oversold: 30 } }
                    ],
                    riskLimits: {
                        maxDailyLossUsd: 100,
                        maxOpenTrades: 3,
                        maxConsecutiveLosses: 2
                    },
                    execution: {
                        orderType: 'market',
                        cooldownMinutes: 30,
                        entryMode: 'both'
                    }
                },
                created_at: '2026-02-15T10:00:00.000Z'
            }
        ]);
        fetchCurrentUserProfileMock.mockResolvedValue({
            user_id: 'user-1',
            email: 'owner@demo.test'
        });

        historySelectMock.mockResolvedValue({
            data: [
                {
                    id: 'h-1',
                    timestamp: '2026-02-15T10:00:00.000Z',
                    symbol: 'BTC/USDT',
                    side: 'BUY',
                    size: 1,
                    entry_price: 100,
                    exit_price: 110,
                    pnl: 10,
                    pnl_percent: 10,
                    reason: 'TP',
                    profile_id: 'profile-1',
                    created_at: '2026-02-15T10:00:01.000Z',
                    trade_id: 'TRD-1',
                    source: 'MANUAL'
                }
            ],
            error: null
        });

        createTradeProfileMock.mockResolvedValue({ id: 'profile-2' });
        updateTradeProfileMock.mockResolvedValue({ id: 'profile-1' });
        deleteTradeProfileMock.mockResolvedValue(undefined);
        setTradeProfileActiveMock.mockResolvedValue({ id: 'profile-1', is_active: false });

        fromMock.mockImplementation((table: string) => {
            if (table === tableNameTransactions) {
                return {
                    select: historySelectMock
                };
            }
            return {
                select: vi.fn().mockResolvedValue({ data: [], error: null }),
                update: vi.fn(() => ({ eq: vi.fn().mockResolvedValue({ error: null }) })),
                insert: vi.fn().mockResolvedValue({ error: null }),
                delete: vi.fn(() => ({ eq: vi.fn().mockResolvedValue({ error: null }) }))
            };
        });
    });

    it('renders profile cards, supports search filtering, and refreshes data', async () => {
        const user = userEvent.setup();
        render(<TradeProfileManager />);

        await waitFor(() => {
            expect(screen.getAllByText('High Risk Scalper').length).toBeGreaterThan(0);
            expect(screen.getAllByText('owner@demo.test').length).toBeGreaterThan(0);
        });

        await user.type(screen.getByPlaceholderText('Search...'), 'nomatch');
        expect(screen.getByText('No matching profiles')).toBeInTheDocument();
        expect(screen.getByText('Try a different search term')).toBeInTheDocument();

        await user.clear(screen.getByPlaceholderText('Search...'));
        expect(screen.getAllByText('High Risk Scalper').length).toBeGreaterThan(0);

        await user.click(screen.getByTitle('Refresh'));
        await waitFor(() => {
            expect(fetchTradeProfilesMock.mock.calls.length).toBeGreaterThan(1);
        });
    }, 20000);

    it('validates create form, edits rules/execution, and inserts new profile', async () => {
        const user = userEvent.setup();
        render(<TradeProfileManager />);

        await waitFor(() => {
            expect(screen.getAllByText('High Risk Scalper').length).toBeGreaterThan(0);
        });

        await user.click(screen.getByRole('button', { name: /New Profile/i }));
        expect(screen.getByRole('heading', { name: 'Create Profile' })).toBeInTheDocument();

        await user.click(screen.getAllByRole('button', { name: 'Create Profile' }).at(-1)!);
        expect(screen.getByText('Profile name is required')).toBeInTheDocument();

        await user.type(screen.getByPlaceholderText('e.g. BTC Momentum Scalper'), 'Night Session Guard');
        await user.clear(screen.getByPlaceholderText('BTC/USDT, ETH/USDT, SOL/USDT'));
        await user.type(screen.getByPlaceholderText('BTC/USDT, ETH/USDT, SOL/USDT'), 'ETH/USDT,SOL/USDT');

        await user.click(screen.getByRole('button', { name: 'Rules' }));
        await user.click(screen.getByText('Trend Bias'));
        await user.selectOptions(screen.getByRole('combobox'), '24/7');

        await user.click(screen.getByRole('button', { name: 'Risk & Execution' }));
        await user.click(screen.getByRole('button', { name: 'limit' }));
        await user.click(screen.getByRole('button', { name: 'Long Only' }));

        await user.click(screen.getAllByRole('button', { name: 'Create Profile' }).at(-1)!);

        await waitFor(() => {
            expect(createTradeProfileMock).toHaveBeenCalledTimes(1);
            expect(createTradeProfileMock).toHaveBeenCalledWith(expect.objectContaining({
                name: 'Night Session Guard',
                user_id: 'user-1',
                symbols: 'ETH/USDT,SOL/USDT'
            }));
            const insertedPayload = createTradeProfileMock.mock.calls[0][0];
            const sessionRule = insertedPayload?.strategy_config?.rules?.find((rule: any) => rule.ruleId === 'SessionRule');
            expect(sessionRule?.params?.sessions).toBe('24/7');
            expect(screen.getByText('Profile created successfully')).toBeInTheDocument();
        });
    }, 20000);

    it('updates activation state, edits profile, and deletes profile', async () => {
        const user = userEvent.setup();
        render(<TradeProfileManager />);

        await waitFor(() => {
            expect(screen.getAllByText('High Risk Scalper').length).toBeGreaterThan(0);
        });

        await user.click(screen.getByTitle('Pause profile'));
        await waitFor(() => {
            expect(setTradeProfileActiveMock).toHaveBeenCalledWith('profile-1', false);
            expect(screen.getByText('Profile suspended')).toBeInTheDocument();
        });

        await user.click(screen.getByTitle('Edit profile'));
        expect(screen.getByText('Edit Profile')).toBeInTheDocument();
        await user.clear(screen.getByPlaceholderText('e.g. BTC Momentum Scalper'));
        await user.type(screen.getByPlaceholderText('e.g. BTC Momentum Scalper'), 'High Risk Scalper v2');
        await user.click(screen.getByRole('button', { name: 'Save Changes' }));

        await waitFor(() => {
            expect(updateTradeProfileMock).toHaveBeenCalledWith('profile-1', expect.objectContaining({
                name: 'High Risk Scalper v2'
            }));
            expect(screen.getByText('Profile updated')).toBeInTheDocument();
        });

        await user.click(screen.getByTitle('Delete profile'));
        expect(screen.getByText('Delete Profile?')).toBeInTheDocument();
        await user.click(screen.getAllByRole('button', { name: 'Delete' }).at(-1)!);

        await waitFor(() => {
            expect(deleteTradeProfileMock).toHaveBeenCalledWith('profile-1');
            expect(screen.getByText('Profile deleted')).toBeInTheDocument();
        });
    }, 20000);

    it('surfaces update and delete failures in toast feedback', async () => {
        setTradeProfileActiveMock.mockRejectedValueOnce(new Error('permission denied'));
        deleteTradeProfileMock.mockRejectedValueOnce(new Error('foreign key violation'));
        const user = userEvent.setup();
        render(<TradeProfileManager />);

        await waitFor(() => {
            expect(screen.getAllByText('High Risk Scalper').length).toBeGreaterThan(0);
        });

        await user.click(screen.getByTitle('Pause profile'));
        await waitFor(() => {
            expect(screen.getByText('permission denied')).toBeInTheDocument();
        });

        await user.click(screen.getByTitle('Delete profile'));
        await user.click(screen.getAllByRole('button', { name: 'Delete' }).at(-1)!);

        await waitFor(() => {
            expect(screen.getByText('Delete failed: foreign key violation')).toBeInTheDocument();
        });
    }, 20000);
});
