import { nextTick } from 'vue';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { mountFull, pagination, rows } from './support/kviewCrudTableFixtures';

/**
 * Client-side export (shared `table-export` builder with the Blade engine)
 * and the `labels` prop that makes every generic string in the engine
 * localizable (see table-contract.md "Exposure, i18n and package coverage").
 */
afterEach(() => {
    document.body.innerHTML = '';
    vi.restoreAllMocks();
});

beforeEach(() => {
    window.localStorage.clear();
});

describe('KviewCrudTable export and labels', () => {
    it('exports the visible view as CSV through the shared builder', async () => {
        const blobs: Blob[] = [];
        const createObjectURL = vi.fn((blob: Blob) => {
            blobs.push(blob);
            return 'blob:mock';
        });
        vi.stubGlobal('URL', Object.assign(Object.create(URL), {
            createObjectURL,
            revokeObjectURL: vi.fn(),
        }));

        mountFull();

        document.querySelector<HTMLButtonElement>('.erp-table-import-export')!.click();
        await nextTick();

        const csvButton = Array.from(document.querySelectorAll<HTMLButtonElement>('#lot2-table_export .erp-export-option'))
            .find((button) => button.textContent?.includes('Export CSV'));
        expect(csvButton).toBeDefined();
        csvButton!.click();
        await nextTick();

        expect(blobs).toHaveLength(1);
        const text = await new Promise<string>((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = () => resolve(String(reader.result));
            reader.onerror = () => reject(reader.error);
            reader.readAsText(blobs[0]);
        });
        expect(text).toContain('"GP","Funds"');
        expect(text).toContain('"Alpha Capital","3"');
        vi.unstubAllGlobals();
    });

    it('routes every generic table control through the labels dictionary', async () => {
        const rowsWithActions = rows.map((row) => ({
            ...row,
            actions: [{ type: 'view' as const, label: 'Voir la fiche', url: `/gps/${row.id}` }],
        }));

        const wrapper = mountFull({
            rows: rowsWithActions,
            createUrl: '/gps/create',
            labels: {
                newRecord: 'Nouvel enregistrement',
                deleteSelected: 'Supprimer la selection',
                deleteSelectedConfirm: 'Supprimer les enregistrements selectionnes ?',
                exportLabel: 'Importer / Exporter',
                settings: 'Reglages du tableau',
                search: 'Rechercher dans ce tableau',
                rowsPerPage: 'Lignes par page',
                pagination: 'Pagination de :table',
                previousPage: 'Page precedente',
                nextPage: 'Page suivante',
                rowActions: 'Actions de ligne',
                selectedCount: ':count selectionnes',
                showingRange: ':first - :last affiches sur :total',
                filterColumn: 'Filtrer :name',
                filterPlaceholder: 'Filtrer',
                filterValue: 'Valeur du filtre',
                reorderColumn: 'Reordonner :name',
                moveUp: 'Monter :name',
                moveDown: 'Descendre :name',
                resizeColumn: 'Redimensionner :name',
                widthPixels: ':count pixels de large',
                selectAll: 'Selectionner toutes les lignes visibles',
                horizontalScroll: 'Faire defiler horizontalement le tableau :table',
                selectRow: 'Selectionner :name',
                record: 'enregistrement',
                records: 'Enregistrements',
                clear: 'Effacer',
                apply: 'Appliquer',
                closeFilter: 'Fermer le filtre',
                operators: { contains: 'Contient' },
            },
        });
        await nextTick();

        const search = wrapper.get('input[type="search"]');
        expect(search.attributes('aria-label')).toBe('Rechercher dans ce tableau');
        expect(search.attributes('placeholder')).toBe('Rechercher dans ce tableau');
        expect(document.querySelector('.erp-table-settings-trigger')?.getAttribute('aria-label')).toBe('Reglages du tableau');
        expect(document.querySelector('.erp-table-import-export')?.getAttribute('aria-label')).toBe('Importer / Exporter');
        const createCommand = document.querySelector<HTMLElement>('.erp-table-create');
        expect(createCommand?.getAttribute('aria-label')).toBe('Nouvel enregistrement');
        expect(createCommand?.classList.contains('ui-icon-button--secondary')).toBe(true);
        expect(createCommand?.classList.contains('ui-icon-button--md')).toBe(true);
        expect(wrapper.get('.erp-page-size-form label').text()).toBe('Lignes par page');
        expect(wrapper.get('nav.pagination-nav').attributes('aria-label')).toBe('Pagination de General Partners');
        expect(wrapper.findAll('.erp-pagination-boundary')[0].get('.ui-visually-hidden').text()).toBe('Page precedente');
        expect(wrapper.findAll('.erp-pagination-boundary')[1].get('.ui-visually-hidden').text()).toBe('Page suivante');
        expect(wrapper.get('.erp-table-actions-head').text()).toBe('Actions de ligne');
        expect(wrapper.get('.erp-table-footnote').text()).toBe('1 - 25 affiches sur 51');
        expect(wrapper.get('.erp-table-persistent-horizontal-scroll').attributes('aria-label'))
            .toBe('Faire defiler horizontalement le tableau General Partners');

        const separator = document.querySelector<HTMLElement>('.erp-column-resize');
        expect(separator?.getAttribute('aria-label')).toBe('Redimensionner GP');
        expect(separator?.getAttribute('aria-valuetext')).toBe('160 pixels de large');

        const filterTrigger = document.querySelector<HTMLButtonElement>('.erp-column-filter-trigger');
        expect(filterTrigger?.getAttribute('aria-label')).toBe('Filtrer GP');
        filterTrigger!.click();
        await nextTick();

        const filterValue = document.querySelector<HTMLInputElement>('#lot2-table_filter_name input[type="search"]');
        expect(filterValue?.getAttribute('placeholder')).toBe('Filtrer');
        expect(filterValue?.getAttribute('aria-label')).toBe('Valeur du filtre');
        expect(document.querySelector('#lot2-table_filter_name .erp-filter-clear')?.textContent).toBe('Effacer');
        expect(document.querySelector('#lot2-table_filter_name .erp-filter-apply')?.textContent).toBe('Appliquer');

        const firstRow = wrapper.get('.erp-table-select-cell input[type="checkbox"]');
        expect(firstRow.attributes('aria-label')).toBe('Selectionner Alpha Capital');
        await firstRow.setValue(true);
        expect(wrapper.text()).toContain('1 selectionnes');
        expect(document.querySelector('.erp-bulk-delete-trigger')?.getAttribute('aria-label')).toBe('Supprimer la selection');
    });

    it('localizes the default empty state and its create action through labels', () => {
        const wrapper = mountFull({
            rows: [],
            createUrl: '/gps/create',
            pagination: pagination({ total: 0, from: null, to: null, lastPage: 1, links: [] }),
            labels: {
                newRecord: 'Nouvel enregistrement',
                emptyTitle: 'Aucun enregistrement',
                emptyText: 'Modifiez les filtres ou creez un nouvel enregistrement.',
                showing: ':count affiches sur :total',
            },
        });

        expect(wrapper.text()).toContain('Aucun enregistrement');
        expect(wrapper.text()).toContain('Modifiez les filtres ou creez un nouvel enregistrement.');
        expect(wrapper.get('.erp-table-empty-state a').text()).toContain('Nouvel enregistrement');
        expect(wrapper.get('.erp-table-footnote').text()).toBe('0 affiches sur 0');
    });
});
