import React from 'react';
import { renderHook } from '@testing-library/react';
import { SectionProvider, useSectionContext, SectionProviderProps, getLevel } from '../context';
import { SectionLevel } from '../types';

describe('useSectionContext', () => {
    const render = (props?: Partial<SectionProviderProps>) =>
        renderHook(() => useSectionContext(), {
            wrapper: ({ children }: { children?: React.ReactNode }) => (
                <SectionProvider {...props}>{children}</SectionProvider>
            ),
        });

    test('returns default values', () => {
        const { result } = render();

        expect(result.current).toMatchObject({
            expandable: false,
            level: 'top',
        });
    });

    describe('expandable', () => {
        test('defaults to false', () => {
            const { result } = render();
            expect(result.current.expandable).toBe(false);
        });

        test('is passed through', () => {
            const { result } = render({ expandable: true });
            expect(result.current.expandable).toBe(true);
        });
    });

    describe('level', () => {
        test('level is inferred from parent section context', () => {
            const { result } = renderHook(() => useSectionContext(), {
                wrapper: ({ children }: { children?: React.ReactNode }) => (
                    <SectionProvider level="sub">
                        <SectionProvider>{children}</SectionProvider>
                    </SectionProvider>
                ),
            });

            expect(result.current).toMatchObject({
                expandable: false,
                level: 'nested',
            });
        });

        test('can be controlled with level prop', () => {
            const { result } = renderHook(() => useSectionContext(), {
                wrapper: ({ children }: { children?: React.ReactNode }) => (
                    <SectionProvider level="sub">
                        <SectionProvider level="top">{children}</SectionProvider>
                    </SectionProvider>
                ),
            });

            expect(result.current).toMatchObject({
                level: 'top',
            });
        });
    });
});

describe('getLevel', () => {
    beforeEach(() => {
        vi.spyOn(console, 'error').mockImplementation(() => {
            // empty
        });
    });
    afterEach(() => {
        vi.restoreAllMocks();
    });

    describe('returns correct level relative to parent', () => {
        test.each([
            ['top', 'sub'],
            ['sub', 'nested'],
            ['nested', 'nested'],
            ['asd', 'top'],
            [undefined, 'top'],
        ] as [SectionLevel, string][])('%s', (level, result) => {
            expect(getLevel(level)).toEqual(result);
        });
    });

    test('logs error if level is nested too deep', () => {
        const consoleSpy = vi.spyOn(console, 'error');
        getLevel('nested');
        expect(consoleSpy).toHaveBeenCalledWith(
            'Section hierarchy too deep. Nested sections should not contain other sections.'
        );
    });
});
