// @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 { ReconciliationAuditPanel } from './ReconciliationAuditPanel';

const { getPlatformAccessTokenMock } = vi.hoisted(() => ({
    getPlatformAccessTokenMock: vi.fn()
}));

vi.mock('../lib/authSession', () => ({
    getPlatformAccessToken: getPlatformAccessTokenMock
}));

vi.mock('../lib/runtime', () => ({
    tradingRuntime: { tradingApiUrl: 'https://trading.test' }
}));

const jsonResponse = (payload: unknown, ok = true, status = 200) => ({
    ok,
    status,
    json: vi.fn(async () => payload)
}) as unknown as Response;

const auditRows = [
    {
        id: 1,
        batch_id: 'batch-applied-123456',
        profile_id: 'profile-123456789',
        symbol: 'SOL/USDT',
        trade_id: 'trade-1',
        backfill_order_id: 'bfill-1',
        exchange_order_id: 'exchange-1',
        filled_qty: 2,
        filled_price: 101.5,
        dry_run: false,
        decision: 'APPLIED',
        reason: 'matched_exchange_fill',
        metadata: { matchedBy: 'clientOrderId', exchangeSubTag: 'client-sub-tag-123456789' },
        created_at: '2026-05-05T12:00:00.000Z'
    }
];

const manualRows = [
    {
        id: 2,
        batch_id: 'batch-review-123456',
        profile_id: 'profile-review-123',
        symbol: 'BTC/USDT',
        trade_id: 'trade-review',
        dry_run: true,
        decision: 'NO_GO',
        reason: 'missing_fill_evidence_for_large_remainder',
        metadata: {
            remaining: 1.25,
            openQty: 2.5,
            dustThreshold: 0.01,
            evidenceRows: 3,
            evidenceRowsUsed: 1,
            unmatchedEvidenceCount: 2
        },
        created_at: '2026-05-05T12:30:00.000Z'
    }
];

const batches = [
    {
        batchId: 'batch-applied-123456',
        firstSeenAt: '2026-05-05T12:00:00.000Z',
        lastSeenAt: '2026-05-05T12:10:00.000Z',
        profileIds: ['profile-123456789'],
        symbols: ['SOL/USDT'],
        totalRows: 4,
        byDecision: { APPLIED: 3, NO_GO: 1 },
        dryRunRows: 0,
        appliedRows: 3,
        revertedRows: 0
    }
];

const mockFetchPayloads = () => {
    const fetchMock = vi.fn()
        .mockResolvedValueOnce(jsonResponse({
            success: true,
            rows: auditRows,
            pagination: { totalCount: 1, hasMore: false, limit: 50, offset: 0 }
        }))
        .mockResolvedValueOnce(jsonResponse({ success: true, batches }))
        .mockResolvedValueOnce(jsonResponse({
            success: true,
            rows: manualRows,
            pagination: { totalCount: 1, hasMore: false, limit: 200, offset: 0 }
        }))
        .mockResolvedValue(jsonResponse({
            success: true,
            rows: [],
            batches: [],
            pagination: { totalCount: 0, hasMore: false, limit: 50, offset: 0 }
        }));
    vi.stubGlobal('fetch', fetchMock);
    return fetchMock;
};

describe('ReconciliationAuditPanel', () => {
    beforeEach(() => {
        getPlatformAccessTokenMock.mockReset();
        getPlatformAccessTokenMock.mockResolvedValue('token-abc');
    });

    it('renders audit summaries, filters, manual review rows, and revert action', async () => {
        const user = userEvent.setup();
        const fetchMock = mockFetchPayloads();
        vi.stubGlobal('confirm', vi.fn(() => false));

        render(<ReconciliationAuditPanel />);

        await waitFor(() => {
            expect(screen.getByText('Reconciliation EXIT Backfill Audit')).toBeInTheDocument();
            expect(screen.getByText('Manual Review Queue')).toBeInTheDocument();
            expect(screen.getAllByText('SOL/USDT').length).toBeGreaterThan(0);
            expect(screen.getByText('BTC/USDT')).toBeInTheDocument();
        });

        expect(screen.getByText('3')).toBeInTheDocument();
        expect(screen.getByText('1 large-remainder case')).toBeInTheDocument();
        expect(screen.getByRole('button', { name: /Revert Batch/i })).toBeInTheDocument();

        await user.type(screen.getByPlaceholderText('Symbol (e.g. SOL/USDT)'), 'eth/usdt');
        await user.click(screen.getByRole('button', { name: /Apply Filters/i }));

        await waitFor(() => {
            expect(fetchMock).toHaveBeenCalledTimes(6);
        });
        expect(String(fetchMock.mock.calls[3][0])).toContain('symbol=ETH%2FUSDT');
    });
});
