import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { afterEach, describe, expect, it } from 'vitest';
import { KviewPivotTable } from '@kview/ui-data/vue';
import type {
    KviewPivotTableColumn,
    KviewPivotTableGroup,
} from '@kview/ui-data/vue';

const columns: KviewPivotTableColumn[] = [
    { key: 'investor', label: 'Investor', type: 'entity', minWidth: 180, sortable: true },
    { key: 'fund', label: 'Fund', type: 'entity', minWidth: 210, sortable: true },
    {
        key: 'commitment',
        label: 'Commitment (EUR m)',
        type: 'scaled-number',
        alignment: 'end',
        dividerBefore: true,
        sortable: true,
    },
    { key: 'remaining', label: 'Remaining %', type: 'percentage', alignment: 'end', sortable: true },
];

const groups: KviewPivotTableGroup[] = [{
    id: 'atlas',
    label: 'Atlas Pension Trust',
    meta: '1 investment',
    rows: [{
        id: 'investment-1',
        href: '/investments/investment-1',
        cells: {
            investor: { value: 'Atlas Pension Trust', url: '/investors/atlas' },
            fund: { value: 'Alpha Growth IV', url: '/funds/alpha-growth' },
            commitment: { value: 12.5, formatted: '12.5' },
            remaining: { value: 0.24, formatted: '24.0%' },
        },
    }],
    summary: {
        label: 'Subtotal — Atlas Pension Trust',
        labelColumnSpan: 2,
        cells: {
            commitment: { value: 12.5, formatted: '12.5' },
            remaining: { value: 0.24, formatted: '24.0%' },
        },
    },
}];

afterEach(() => {
    document.body.innerHTML = '';
});

describe('KviewPivotTable', () => {
    it('renders typed ERP cells, grouped rows and a footer summary', () => {
        const wrapper = mount(KviewPivotTable, {
            props: {
                id: 'commitment-pivot',
                tableLabel: 'Commitment positions',
                columns,
                groups,
            },
        });

        expect(wrapper.get('[role="region"]').attributes('aria-label')).toBe('Commitment positions');
        expect(wrapper.get('caption').text()).toBe('Commitment positions');
        expect(wrapper.get('.erp-pivot-table__group-control').attributes('aria-expanded')).toBe('true');
        expect(wrapper.get('.erp-pivot-table__group-copy').text()).toContain('1 investment');
        expect(wrapper.get('.erp-cell-link').text()).toBe('Atlas Pension Trust');
        expect(wrapper.findAll('.erp-cell-number').map((cell) => cell.text())).toContain('24.0%');
        expect(wrapper.get('th.erp-pivot-table__summary-label').attributes('colspan')).toBe('2');
        expect(wrapper.get('th.erp-pivot-table__summary-label').text()).toBe('Subtotal — Atlas Pension Trust');
        expect(wrapper.get('th.erp-pivot-table__divider-before').text()).toContain('Commitment');
    });

    it('collapses one row group accessibly without removing its summary', async () => {
        const wrapper = mount(KviewPivotTable, {
            props: {
                id: 'collapsible-pivot',
                columns,
                groups,
            },
        });
        const control = wrapper.get<HTMLButtonElement>('.erp-pivot-table__group-control');
        const rowsId = control.attributes('aria-controls');

        expect(wrapper.get(`#${rowsId}`).attributes('hidden')).toBeUndefined();
        await control.trigger('click');
        await nextTick();

        expect(control.attributes('aria-expanded')).toBe('false');
        expect(wrapper.get(`#${rowsId}`).attributes()).toHaveProperty('hidden');
        expect(wrapper.get('.erp-pivot-table__summary-row').text()).toContain('Subtotal');
        expect(wrapper.emitted('group-toggle')?.[0]).toEqual([groups[0], false]);
    });

    it('moves an adaptive summary between the collapsed heading and expanded footer', async () => {
        const wrapper = mount(KviewPivotTable, {
            props: {
                id: 'adaptive-pivot',
                columns,
                groups,
                summaryPosition: 'adaptive',
            },
        });
        const control = wrapper.get<HTMLButtonElement>('.erp-pivot-table__group-control');
        const rowsId = control.attributes('aria-controls');

        expect(wrapper.get('.erp-pivot-table__group-row').text()).toContain('Atlas Pension Trust');
        expect(wrapper.get('.erp-pivot-table__group-row').text()).not.toContain('24.0%');
        expect(wrapper.get('.erp-pivot-table__summary-row').text()).toContain('Subtotal — Atlas Pension Trust');
        expect(wrapper.get('.erp-pivot-table__summary-row').text()).toContain('24.0%');

        await control.trigger('click');
        await nextTick();

        const collapsedGroupRow = wrapper.get('.erp-pivot-table__group-row');

        expect(control.attributes('aria-expanded')).toBe('false');
        expect(wrapper.get(`#${rowsId}`).attributes()).toHaveProperty('hidden');
        expect(wrapper.find('.erp-pivot-table__summary-row').exists()).toBe(false);
        expect(collapsedGroupRow.classes()).toContain('erp-pivot-table__group-row--adaptive-summary');
        expect(collapsedGroupRow.text()).toContain('Atlas Pension Trust');
        expect(collapsedGroupRow.text()).toContain('24.0%');
        expect(collapsedGroupRow.text()).not.toContain('Subtotal —');

        await control.trigger('click');
        await nextTick();

        expect(control.attributes('aria-expanded')).toBe('true');
        expect(wrapper.get(`#${rowsId}`).attributes('hidden')).toBeUndefined();
        expect(wrapper.get('.erp-pivot-table__group-row').text()).not.toContain('24.0%');
        expect(wrapper.get('.erp-pivot-table__summary-row').text()).toContain('24.0%');
    });

    it('supports a controlled expanded-groups model and header summaries', async () => {
        const wrapper = mount(KviewPivotTable, {
            props: {
                id: 'controlled-pivot',
                columns,
                groups,
                summaryPosition: 'group-header',
                expandedGroups: ['atlas'],
            },
        });

        expect(wrapper.find('.erp-pivot-table__summary-row').exists()).toBe(false);
        expect(wrapper.get('.erp-pivot-table__group-heading').attributes('colspan')).toBe('2');
        expect(wrapper.get('.erp-pivot-table__group-row').text()).toContain('24.0%');

        await wrapper.get('.erp-pivot-table__group-control').trigger('click');

        expect(wrapper.emitted('update:expandedGroups')?.[0]).toEqual([[]]);
    });

    it('activates a data row with pointer or keyboard but ignores nested links', async () => {
        const wrapper = mount(KviewPivotTable, {
            props: {
                id: 'interactive-pivot',
                columns,
                groups,
            },
        });
        const row = wrapper.get<HTMLTableRowElement>('.erp-pivot-table__data-row');
        wrapper.get('.erp-detail-table__row-link').element.addEventListener('click', (event) => event.preventDefault());

        await row.trigger('click');
        await row.trigger('keydown', { key: 'Enter' });
        await row.trigger('keydown', { key: ' ' });
        expect(wrapper.emitted('row-activate')).toHaveLength(3);

        const nestedLink = wrapper.get('a.erp-cell-link');
        nestedLink.element.addEventListener('click', (event) => event.preventDefault());
        await nestedLink.trigger('click');
        expect(wrapper.emitted('row-activate')).toHaveLength(3);
    });

    it('keeps the shared empty state inside the named scroll region', () => {
        const wrapper = mount(KviewPivotTable, {
            props: {
                id: 'empty-pivot',
                tableLabel: 'Empty pivot',
                columns,
                groups: [],
                emptyTitle: 'No positions',
                emptyText: 'Try another filter.',
            },
        });

        expect(wrapper.get('.ui-empty-state').text()).toContain('No positions');
        expect(wrapper.get('.ui-empty-state').text()).toContain('Try another filter.');
        expect(wrapper.get('.erp-detail-table__empty-row td').attributes('colspan')).toBe('4');
    });

    it('expands and collapses every group from one accessible toolbar', async () => {
        const wrapper = mount(KviewPivotTable, {
            props: {
                id: 'bulk-groups-pivot',
                columns,
                groups: [
                    ...groups,
                    { ...groups[0], id: 'second', label: 'Second investor' },
                ],
            },
        });

        const collapseAll = wrapper.findAll<HTMLButtonElement>('.erp-pivot-table__toolbar-button')
            .find((button) => button.text().includes('Collapse all'))!;

        await collapseAll.trigger('click');
        await nextTick();

        expect(wrapper.findAll('.erp-pivot-table__group-control').every((control) => (
            control.attributes('aria-expanded') === 'false'
        ))).toBe(true);
        expect(wrapper.emitted('groups-toggle')?.[0]).toEqual([false]);

        const expandAll = wrapper.findAll<HTMLButtonElement>('.erp-pivot-table__toolbar-button')
            .find((button) => button.text().includes('Expand all'))!;
        await expandAll.trigger('click');
        await nextTick();

        expect(wrapper.findAll('.erp-pivot-table__group-control').every((control) => (
            control.attributes('aria-expanded') === 'true'
        ))).toBe(true);
        expect(wrapper.emitted('groups-toggle')?.[1]).toEqual([true]);
    });

    it('sorts rows inside each group and exposes aria-sort only on the active header', async () => {
        const sortableGroups: KviewPivotTableGroup[] = [{
            ...groups[0],
            rows: [
                {
                    ...groups[0].rows[0],
                    id: 'zeta',
                    cells: {
                        ...groups[0].rows[0].cells,
                        fund: { value: 'Zeta Direct Lending' },
                    },
                },
                {
                    ...groups[0].rows[0],
                    id: 'alpha',
                    cells: {
                        ...groups[0].rows[0].cells,
                        fund: { value: 'Alpha Growth IV' },
                    },
                },
            ],
        }];
        const wrapper = mount(KviewPivotTable, {
            props: {
                id: 'sortable-pivot',
                columns,
                groups: sortableGroups,
            },
        });
        const fundSort = wrapper.get<HTMLButtonElement>('button[aria-label="Sort Fund ascending"]');

        await fundSort.trigger('click');
        await nextTick();

        expect(wrapper.findAll('.erp-pivot-table__data-row').map((row) => row.text())).toEqual([
            expect.stringContaining('Alpha Growth IV'),
            expect.stringContaining('Zeta Direct Lending'),
        ]);
        expect(fundSort.element.closest('th')?.getAttribute('aria-sort')).toBe('ascending');
        expect(wrapper.findAll('th[aria-sort]')).toHaveLength(1);

        await fundSort.trigger('click');
        await nextTick();

        expect(wrapper.findAll('.erp-pivot-table__data-row').map((row) => row.text())).toEqual([
            expect.stringContaining('Zeta Direct Lending'),
            expect.stringContaining('Alpha Growth IV'),
        ]);
        expect(fundSort.element.closest('th')?.getAttribute('aria-sort')).toBe('descending');
        expect(wrapper.emitted('sort-change')?.at(-1)).toEqual([{ key: 'fund', direction: 'desc' }]);
    });

    it('sorts group keys and keeps normalized disclosure ids unique', async () => {
        const groupedRows: KviewPivotTableGroup[] = [
            {
                ...groups[0],
                id: 'lp/1',
                label: 'Zeta Investor',
                sortValues: { investor: 'Zeta Investor' },
            },
            {
                ...groups[0],
                id: 'lp 1',
                label: 'Alpha Investor',
                sortValues: { investor: 'Alpha Investor' },
            },
        ];
        const wrapper = mount(KviewPivotTable, {
            props: {
                id: 'group-sort-pivot',
                columns,
                groups: groupedRows,
            },
        });

        const controlledIds = wrapper.findAll('.erp-pivot-table__group-control')
            .map((control) => control.attributes('aria-controls'));

        expect(new Set(controlledIds).size).toBe(2);

        await wrapper.get<HTMLButtonElement>('button[aria-label="Sort Investor ascending"]').trigger('click');
        await nextTick();

        expect(wrapper.findAll('.erp-pivot-table__group-copy').map((copy) => copy.text())).toEqual([
            expect.stringContaining('Alpha Investor'),
            expect.stringContaining('Zeta Investor'),
        ]);
    });

    it('sorts localized dates by their canonical descriptor values', async () => {
        const dateColumns: KviewPivotTableColumn[] = [
            { key: 'date', label: 'Date', type: 'date', sortable: true },
        ];
        const dateGroups: KviewPivotTableGroup[] = [{
            id: 'dates',
            label: 'Dates',
            rows: [
                { id: 'later', cells: { date: { value: '2026-02-01', formatted: '01/02/2026' } } },
                { id: 'earlier', cells: { date: { value: '2025-12-31', formatted: '31/12/2025' } } },
            ],
        }];
        const wrapper = mount(KviewPivotTable, {
            props: {
                id: 'date-sort-pivot',
                columns: dateColumns,
                groups: dateGroups,
            },
        });

        await wrapper.get<HTMLButtonElement>('button[aria-label="Sort Date ascending"]').trigger('click');
        await nextTick();

        expect(wrapper.findAll('.erp-pivot-table__data-row').map((row) => row.text())).toEqual([
            '31/12/2025',
            '01/02/2026',
        ]);
    });
});
