import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { describe, expect, it } from 'vitest';
import {
    KviewButtonGroup,
    KviewSegmentedControl,
    KviewTabs,
    KviewToggle,
} from '@kview/ui-core/vue';

describe('kView Vue choice primitives', () => {
    it('owns tab relationships, selection, panels and roving keyboard focus', async () => {
        const tabItems = [
            { id: 'overview', label: 'Overview', icon: 'dashboard' },
            { id: 'performance', label: 'Performance', badge: 8 },
            { id: 'activity', label: 'Activity' },
        ];
        const wrapper = mount(KviewTabs, {
            attachTo: document.body,
            props: {
                id: 'fund-sections',
                defaultValue: 'overview',
                label: 'Sections du fund',
                tabs: tabItems,
            },
            slots: {
                overview: '<p>Fund overview</p>',
                performance: '<p>Performance metrics</p>',
                activity: '<p>Recent activity</p>',
            },
        });

        try {
            const tabs = wrapper.findAll<HTMLButtonElement>('[role="tab"]');

            expect(wrapper.get('[role="tablist"]').attributes('aria-label')).toBe('Sections du fund');
            expect(wrapper.classes()).toContain('ui-tabs');
            expect(tabs.every((tab) => tab.classes().includes('ui-tab'))).toBe(true);
            expect(tabs.map((tab) => tab.attributes('tabindex'))).toEqual(['0', '-1', '-1']);
            expect(tabs[0].attributes('aria-controls')).toBe('fund-sections_overview_panel');
            expect(wrapper.get('#fund-sections_overview_panel').attributes('aria-labelledby')).toBe('fund-sections_overview_tab');
            expect(wrapper.get('#fund-sections_overview_panel').classes()).toContain('ui-tab-panel');
            expect(wrapper.get('#fund-sections_performance_panel').attributes('hidden')).toBeDefined();
            expect(wrapper.html()).not.toContain('data-ui-');

            await tabs[0].trigger('keydown', { key: 'End' });
            await nextTick();

            expect(tabs[2].attributes('aria-selected')).toBe('true');
            expect(document.activeElement).toBe(tabs[2].element);
            expect(wrapper.get('#fund-sections_activity_panel').attributes('hidden')).toBeUndefined();

            await tabs[2].trigger('keydown', { key: 'Home' });
            await nextTick();
            expect(document.activeElement).toBe(tabs[0].element);

            await tabs[0].trigger('keydown', { key: 'ArrowLeft' });
            await nextTick();
            expect(document.activeElement).toBe(tabs[2].element);

            await tabs[2].trigger('keydown', { key: 'ArrowRight' });
            await nextTick();
            expect(document.activeElement).toBe(tabs[0].element);
            expect(wrapper.emitted('update:modelValue')?.at(-1)).toEqual(['overview']);

            await wrapper.setProps({ modelValue: 'performance' });
            expect(tabs[1].attributes('aria-selected')).toBe('true');

            await wrapper.setProps({ modelValue: null });
            expect(tabs[0].attributes('aria-selected')).toBe('true');
            expect(wrapper.get('#fund-sections_overview_panel').attributes('hidden')).toBeUndefined();

            await wrapper.setProps({ modelValue: undefined });
            await wrapper.findAll('[role="tab"]')[2].trigger('click');
            expect(wrapper.findAll('[role="tab"]')[2].attributes('aria-selected')).toBe('true');

            await wrapper.setProps({ tabs: tabItems.slice(0, 2) });
            expect(wrapper.findAll('[role="tab"]')[0].attributes('aria-selected')).toBe('true');

            await wrapper.setProps({ tabs: tabItems });
            expect(wrapper.findAll('[role="tab"]')[0].attributes('aria-selected')).toBe('true');
        } finally {
            wrapper.unmount();
        }
    });

    it('keeps segmented buttons, links and disabled items semantically distinct', async () => {
        const wrapper = mount(KviewSegmentedControl, {
            props: {
                label: 'Période',
                size: 'sm',
                variant: 'pills',
                items: [
                    { value: 'qtd', label: 'QTD' },
                    { value: 'ytd', label: 'YTD', active: true },
                    { value: 'one-year', label: '1Y' },
                    { value: 'max', label: 'Max', disabled: true },
                    { value: 'details', label: 'Details', href: '/details' },
                ],
            },
        });

        expect(wrapper.get('[role="group"]').attributes('aria-label')).toBe('Période');
        expect(wrapper.classes()).toEqual(expect.arrayContaining([
            'ui-segmented-control',
            'ui-segmented-control--sm',
            'ui-segmented-control--pills',
        ]));
        expect(wrapper.get('button[aria-pressed="true"]').text()).toBe('YTD');
        expect(wrapper.get('a[href="/details"]').attributes('aria-current')).toBeUndefined();
        expect(wrapper.get('button[disabled]').attributes('aria-pressed')).toBe('false');

        await wrapper.findAll('button')[2].trigger('click');

        expect(wrapper.findAll('button')[2].attributes('aria-pressed')).toBe('true');
        expect(wrapper.emitted('update:modelValue')?.at(-1)).toEqual(['one-year']);
        expect(wrapper.emitted('change')).toEqual([['one-year']]);

        await wrapper.findAll('button')[2].trigger('click');

        expect(wrapper.emitted('update:modelValue')).toHaveLength(2);
        expect(wrapper.emitted('change')).toHaveLength(1);

        await wrapper.get('button[disabled]').trigger('click');

        expect(wrapper.emitted('update:modelValue')).toHaveLength(2);

        await wrapper.setProps({ modelValue: 'details' });

        expect(wrapper.get('a[href="/details"]').attributes('aria-current')).toBe('true');
        expect(wrapper.get('a[href="/details"]').classes()).toContain('is-active');

        await wrapper.setProps({ modelValue: null });

        expect(wrapper.find('[aria-pressed="true"]').exists()).toBe(false);
        expect(wrapper.get('a[href="/details"]').attributes('aria-current')).toBeUndefined();
    });

    it('preserves numeric segmented values in its public v-model contract', async () => {
        const wrapper = mount(KviewSegmentedControl, {
            props: {
                modelValue: 1,
                items: [
                    { value: 1, label: 'Numeric one' },
                    { value: '1', label: 'String one' },
                    { value: 2, label: 'Two' },
                ],
            },
        });

        expect(wrapper.findAll('[aria-pressed="true"]')).toHaveLength(1);
        expect(wrapper.get('[aria-pressed="true"]').text()).toBe('Numeric one');

        await wrapper.findAll('button')[1].trigger('click');

        expect(wrapper.emitted('update:modelValue')).toEqual([['1']]);
        expect(wrapper.emitted('change')).toEqual([['1']]);
    });

    it('selects an active segmented item loaded after mount', async () => {
        const wrapper = mount(KviewSegmentedControl, {
            props: {
                items: [],
            },
        });

        await wrapper.setProps({
            items: [
                { value: 'latest', label: 'Latest', active: true },
                { value: 'archive', label: 'Archive' },
            ],
        });

        expect(wrapper.get('[aria-pressed="true"]').text()).toBe('Latest');
    });

    it('connects toggle state, description and explicit unchecked form value', async () => {
        const wrapper = mount(KviewToggle, {
            props: {
                name: 'preferences[compact]',
                modelValue: false,
                uncheckedValue: '0',
                label: 'Mode compact',
                description: 'Réduit la densité des lignes.',
                size: 'sm',
                variant: 'bare',
                inputAttributes: {
                    'aria-describedby': 'server-error',
                },
            },
        });

        const input = wrapper.get<HTMLInputElement>('[role="switch"]');

        expect(input.attributes('id')).toBe('preferences_compact');
        expect(wrapper.classes()).toEqual(expect.arrayContaining([
            'ui-toggle',
            'ui-toggle--sm',
            'ui-toggle--bare',
        ]));
        expect(input.attributes('aria-describedby')).toBe('server-error preferences_compact_description');
        expect(wrapper.get('#preferences_compact_description').text()).toBe('Réduit la densité des lignes.');
        expect(wrapper.get('input[type="hidden"]').attributes('value')).toBe('0');

        await input.setValue(true);

        expect(wrapper.emitted('update:modelValue')).toEqual([[true]]);
        expect(wrapper.emitted('change')).toEqual([[true]]);

        await wrapper.setProps({ modelValue: true, disabled: true });

        expect(input.element.checked).toBe(true);
        expect(input.attributes('disabled')).toBeDefined();
        expect(wrapper.find('input[type="hidden"]').exists()).toBe(false);
    });

    it('groups adjacent commands without inventing selection state', () => {
        const wrapper = mount(KviewButtonGroup, {
            props: {
                label: 'Actions d’export',
                size: 'sm',
            },
            slots: {
                default: '<button type="button">CSV</button><button type="button">Excel</button>',
            },
        });

        const group = wrapper.get('[role="group"]');

        expect(group.attributes('aria-label')).toBe('Actions d’export');
        expect(group.classes()).toContain('ui-button-group--sm');
        expect(group.findAll('button')).toHaveLength(2);
        expect(group.html()).not.toContain('aria-pressed');
    });
});
