/* eslint-disable @typescript-eslint/no-explicit-any */
import { render, screen } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';

// ── Mocks ─────────────────────────────────────────────────────────────────────

vi.mock('@inertiajs/react', () => ({
    Head: ({ title }: { title: string }) => <title>{title}</title>,
    Link: ({ href, children, ...rest }: any) => (
        <a href={href} {...rest}>
            {children}
        </a>
    ),
    router: {
        get: vi.fn(),
        post: vi.fn(),
        put: vi.fn(),
        patch: vi.fn(),
        delete: vi.fn(),
        visit: vi.fn(),
    },
    usePage: vi.fn(() => ({
        props: {
            auth: { adminRole: 'super_admin', adminPermissions: [] },
            flash: {},
            errors: {},
        },
    })),
}));

vi.mock('@/Layouts/AdminLayout', () => ({
    default: ({ children, title }: any) => (
        <div data-testid="admin-layout" data-title={title}>
            {children}
        </div>
    ),
}));

vi.mock('@/lib/api', () => ({
    api: {
        get: vi.fn(),
        post: vi.fn(),
        put: vi.fn(),
        patch: vi.fn(),
        delete: vi.fn(),
    },
}));

vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }));

vi.mock('@tanstack/react-query', () => ({
    useQuery: vi.fn(() => ({
        data: undefined,
        isLoading: false,
        isError: false,
        refetch: vi.fn(),
    })),
    useQueryClient: vi.fn(() => ({
        invalidateQueries: vi.fn(),
        setQueryData: vi.fn(),
    })),
    keepPreviousData: undefined,
}));

// ── Imports (after mocks) ─────────────────────────────────────────────────────

import AuditLogsShow from '../Show';

const LOG_ID = '019efe5c-2f8e-7038-9c63-25c49a749457';

function makeLog(overrides = {}) {
    return {
        id: LOG_ID,
        scope: 'admin',
        event: 'user.update',
        category: 'auth',
        action: 'update',
        status: 'success',
        severity: 'warning',
        actor_type: 'admin',
        actor_name: 'Alice Admin',
        actor_role: 'super_admin',
        auditable_type: 'App\\Models\\User',
        actor_id: 'actor-uuid-001',
        auditable_id: 'rec-uuid-002',
        ip_address: '10.0.0.1',
        user_agent: 'Mozilla/5.0 (Macintosh)',
        url: '/admin/users/1',
        http_method: 'PUT',
        branch_id: null,
        review_status: null,
        reviewed_at: null,
        reviewed_by_name: null,
        created_at: '2025-01-15T08:30:00Z',
        changes: [],
        tags: [],
        notes: [],
        ...overrides,
    };
}

describe('AuditLogsShow', () => {
    beforeEach(() => {
        vi.clearAllMocks();
    });

    it('renders inside AdminLayout with title "Audit Log"', () => {
        render(<AuditLogsShow log={makeLog()} />);
        expect(screen.getByTestId('admin-layout')).toHaveAttribute(
            'data-title',
            'Audit Log',
        );
    });

    it('renders the event name as the main heading', () => {
        render(<AuditLogsShow log={makeLog()} />);
        expect(screen.getByText('user.update')).toBeInTheDocument();
    });

    it('renders a "Back to audit logs" link pointing to /admin/audit', () => {
        render(<AuditLogsShow log={makeLog()} />);
        const link = screen.getByText('Back to audit logs').closest('a');
        expect(link).toHaveAttribute('href', '/admin/audit');
    });

    it('renders the actor name in the Actor section', () => {
        render(<AuditLogsShow log={makeLog()} />);
        expect(screen.getByText('Alice Admin')).toBeInTheDocument();
    });

    it('renders the IP address in the Request Context section', () => {
        render(<AuditLogsShow log={makeLog()} />);
        expect(screen.getByText('10.0.0.1')).toBeInTheDocument();
    });

    it('renders the HTTP method and URL', () => {
        render(<AuditLogsShow log={makeLog()} />);
        expect(screen.getByText('PUT')).toBeInTheDocument();
        expect(screen.getByText('/admin/users/1')).toBeInTheDocument();
    });

    it('renders the severity badge for the log', () => {
        render(<AuditLogsShow log={makeLog({ severity: 'critical' })} />);
        // Multiple SeverityBadge instances may be rendered (header card)
        expect(screen.getAllByText('Critical').length).toBeGreaterThan(0);
    });

    it('renders the status badge for the log', () => {
        render(<AuditLogsShow log={makeLog({ status: 'failed' })} />);
        expect(screen.getByText('Failed')).toBeInTheDocument();
    });

    it('renders the Affected Record section when auditable_type is set', () => {
        render(<AuditLogsShow log={makeLog()} />);
        // Model short name: 'App\Models\User' → 'User'
        expect(screen.getByText('User')).toBeInTheDocument();
    });

    it('renders field changes table when log has changes', () => {
        render(
            <AuditLogsShow
                log={makeLog({
                    changes: [
                        {
                            field: 'email',
                            old_value: 'old@test.com',
                            new_value: 'new@test.com',
                        },
                    ],
                })}
            />,
        );
        expect(screen.getByText('email')).toBeInTheDocument();
        expect(screen.getByText('old@test.com')).toBeInTheDocument();
        expect(screen.getByText('new@test.com')).toBeInTheDocument();
    });

    it('renders the "Field Changes (N)" heading with correct count', () => {
        render(
            <AuditLogsShow
                log={makeLog({
                    changes: [
                        { field: 'name', old_value: 'A', new_value: 'B' },
                        {
                            field: 'email',
                            old_value: 'x@x.com',
                            new_value: 'y@y.com',
                        },
                    ],
                })}
            />,
        );
        expect(screen.getByText('Field Changes (2)')).toBeInTheDocument();
    });

    it('renders tags when present', () => {
        render(
            <AuditLogsShow
                log={makeLog({
                    tags: [{ key: 'env', value: 'production' }],
                })}
            />,
        );
        expect(screen.getByText('env=')).toBeInTheDocument();
        expect(screen.getByText('production')).toBeInTheDocument();
    });

    it('renders the NoteForm "Respond to this event" section', () => {
        render(<AuditLogsShow log={makeLog()} />);
        expect(screen.getByText('Respond to this event')).toBeInTheDocument();
        expect(screen.getAllByText('Add Note').length).toBeGreaterThan(0);
    });

    it('renders "No responses yet" when notes list is empty', () => {
        render(<AuditLogsShow log={makeLog({ notes: [] })} />);
        expect(screen.getByText('No responses yet')).toBeInTheDocument();
    });

    it('renders existing notes in the investigation timeline', () => {
        render(
            <AuditLogsShow
                log={makeLog({
                    notes: [
                        {
                            id: 'n-1',
                            type: 'reviewed',
                            body: 'All looks fine.',
                            admin_name: 'Bob Reviewer',
                            created_at: '2025-01-16T09:00:00Z',
                        },
                    ],
                })}
            />,
        );
        expect(screen.getByText('Bob Reviewer')).toBeInTheDocument();
        expect(screen.getByText('All looks fine.')).toBeInTheDocument();
    });

    it('renders the review banner when review_status and reviewed_at are set', () => {
        render(
            <AuditLogsShow
                log={makeLog({
                    review_status: 'reviewed',
                    reviewed_at: '2025-01-17T12:00:00Z',
                    reviewed_by_name: 'Carol',
                })}
            />,
        );
        expect(screen.getByText('Carol')).toBeInTheDocument();
        // The banner text includes "Reviewed by Carol"
        expect(screen.getAllByText(/reviewed/i).length).toBeGreaterThan(0);
    });

    it('does NOT render the changes table when changes array is empty', () => {
        render(<AuditLogsShow log={makeLog({ changes: [] })} />);
        expect(screen.queryByText(/Field Changes/i)).not.toBeInTheDocument();
    });

    it('does NOT render the tags section when tags array is empty', () => {
        render(<AuditLogsShow log={makeLog({ tags: [] })} />);
        // The Tags section header is rendered only when tags.length > 0
        expect(screen.queryByText(/^Tags$/i)).not.toBeInTheDocument();
    });
});
