import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { render, screen } from '@testing-library/react';
import { describe, expect, it, vi, beforeEach } from 'vitest';

// Isolate the dashboard's loading/empty/error branching by mocking the query
// hooks — no QueryClient or timers needed.
const queryHooks = vi.hoisted(() => ({
    useIdentitySyncStatus: vi.fn(),
    useIdentitySyncJournal: vi.fn(),
    useIdentitySyncQuarantine: vi.fn(),
    useResolveQuarantineItem: vi.fn(),
    useResetBreaker: vi.fn(),
}));

vi.mock('../src/platform/features/identity-sync/identitySyncQueries', () => queryHooks);

vi.mock('@nexuscrm/host-sdk', async (importOriginal) => {
    const actual = await importOriginal<typeof import('@nexuscrm/host-sdk')>();
    return {
        ...actual,
        useSystemPermission: () => true,
        useHostNotifications: () => ({ success: vi.fn(), error: vi.fn(), info: vi.fn(), warning: vi.fn() }),
        formatApiError: (err: unknown) => ({ message: err instanceof Error ? err.message : 'error' }),
    };
});

import { IdentitySyncDashboard, deriveInitialTab } from '../src/platform/features/identity-sync/IdentitySyncDashboard';

const STATUS_OK = {
    breaker: {
        status: 'open',
        failureCount: 5,
        failureThreshold: 5,
        cooldownSeconds: 60,
        openedAt: '2026-07-15T09:00:00.000Z',
        lastFailureAt: '2026-07-15T09:00:00.000Z',
        lastError: 'Upstream SCIM endpoint timed out',
    },
    lastRun: {
        runId: 'run-1',
        startedAt: '2026-07-15T08:00:00.000Z',
        finishedAt: '2026-07-15T08:05:00.000Z',
        status: 'partial',
        processed: 120,
        provisioned: 10,
        updated: 100,
        deactivated: 3,
        skipped: 5,
        quarantined: 2,
        errors: 1,
    },
    config: {
        provisioningSource: 'scim',
        defaultProfile: 'Standard User',
        exemptPrincipals: ['break-glass@example.com'],
        breakerFailureThreshold: 5,
        breakerCooldownSeconds: 60,
    },
};

function renderDashboard(path = '/setup/identity-sync') {
    return render(
        <MemoryRouter initialEntries={[path]}>
            <IdentitySyncDashboard />
        </MemoryRouter>,
    );
}

describe('deriveInitialTab', () => {
    it('maps deep-linked child routes to their tab, defaulting to activity', () => {
        expect(deriveInitialTab('/setup/identity-sync')).toBe('activity');
        expect(deriveInitialTab('/setup/identity-sync/activity')).toBe('activity');
        expect(deriveInitialTab('/setup/identity-sync/quarantine')).toBe('quarantine');
        expect(deriveInitialTab('/setup/identity-sync/settings')).toBe('activity');
    });
});

describe('IdentitySyncDashboard branching', () => {
    beforeEach(() => {
        vi.clearAllMocks();
        queryHooks.useIdentitySyncStatus.mockReturnValue({ data: STATUS_OK, isLoading: false, error: null, refetch: vi.fn() });
        queryHooks.useIdentitySyncJournal.mockReturnValue({ data: { events: [], total: 0 }, isLoading: false, error: null, refetch: vi.fn() });
        queryHooks.useIdentitySyncQuarantine.mockReturnValue({ data: { items: [], total: 0 }, isLoading: false, error: null, refetch: vi.fn() });
        queryHooks.useResolveQuarantineItem.mockReturnValue({ mutateAsync: vi.fn(), isPending: false });
        queryHooks.useResetBreaker.mockReturnValue({ mutateAsync: vi.fn().mockResolvedValue(undefined), isPending: false });
    });

    it('always renders the page header', () => {
        renderDashboard();
        expect(screen.getByRole('heading', { name: 'Identity Sync' })).toBeInTheDocument();
    });

    it('renders the health summary (breaker + last-run stats) when status loads', () => {
        renderDashboard();
        expect(screen.getByText('Circuit Breaker')).toBeInTheDocument();
        expect(screen.getByText('Open')).toBeInTheDocument();
        expect(screen.getByText('Upstream SCIM endpoint timed out')).toBeInTheDocument();
        // Last-run stat tiles.
        expect(screen.getByText('Processed')).toBeInTheDocument();
        expect(screen.getByText('Quarantined')).toBeInTheDocument();
        // Reset control is offered while the breaker is open (ManageUsers granted).
        expect(screen.getByRole('button', { name: /Reset Breaker/i })).toBeInTheDocument();
    });

    it('shows a skeleton (no summary, no error) while status is loading', () => {
        queryHooks.useIdentitySyncStatus.mockReturnValue({ data: undefined, isLoading: true, error: null, refetch: vi.fn() });
        renderDashboard();
        expect(screen.queryByText('Circuit Breaker')).not.toBeInTheDocument();
        expect(screen.queryByText('Error Loading Status')).not.toBeInTheDocument();
        // Header still present.
        expect(screen.getByRole('heading', { name: 'Identity Sync' })).toBeInTheDocument();
    });

    it('shows an error state with retry when status fails', () => {
        queryHooks.useIdentitySyncStatus.mockReturnValue({ data: undefined, isLoading: false, error: new Error('boom'), refetch: vi.fn() });
        renderDashboard();
        expect(screen.getByText('Error Loading Status')).toBeInTheDocument();
        expect(screen.getByRole('button', { name: 'Retry' })).toBeInTheDocument();
    });

    it('shows the Activity empty state on the default tab when the journal is empty', () => {
        renderDashboard();
        expect(screen.getByText('No sync activity yet')).toBeInTheDocument();
    });

    it('keeps the one-time SCIM token minting operation without restoring a policy editor', () => {
        renderDashboard();
        expect(screen.getByRole('button', { name: 'Generate token' })).toBeInTheDocument();
        expect(screen.getByText(/Tenant policy is supplied by the installed L2 pack/i)).toBeInTheDocument();
    });

    it('shows the Activity error state when the journal fails', () => {
        queryHooks.useIdentitySyncJournal.mockReturnValue({ data: undefined, isLoading: false, error: new Error('nope'), refetch: vi.fn() });
        renderDashboard();
        expect(screen.getByText('Error Loading Activity')).toBeInTheDocument();
    });

    it('does not expose a configuration-editor tab', () => {
        renderDashboard('/setup/identity-sync/settings');
        expect(screen.queryByText('Enable SCIM provisioning')).not.toBeInTheDocument();
        expect(screen.queryByText('Save configuration')).not.toBeInTheDocument();
        expect(screen.getByText('No sync activity yet')).toBeInTheDocument();
    });
});
