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

/**
 * Per-column filter behavior owned by `useKviewCrudTableFilters` and
 * rendered through the private `KviewCrudTableFilterPanel` sub-component:
 * text, date and multiselect operators, and the apply/clear commit contract.
 */
afterEach(() => {
    document.body.innerHTML = '';
    vi.restoreAllMocks();
});

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

describe('KviewCrudTable filters', () => {
    it('applies a column filter through its popover and reports the intent', async () => {
        const wrapper = mountFull();

        const trigger = document.querySelector<HTMLButtonElement>('.erp-column-filter-trigger');
        expect(trigger).not.toBeNull();
        trigger!.click();
        await nextTick();

        const value = document.querySelector<HTMLInputElement>('#lot2-table_filter_name input[aria-label="Filter value"]');
        expect(value).not.toBeNull();
        value!.value = 'alpha';
        value!.dispatchEvent(new Event('input', { bubbles: true }));
        await nextTick();

        document.querySelector<HTMLButtonElement>('#lot2-table_filter_name .erp-filter-apply')!.click();
        await nextTick();

        expect(wrapper.emitted('update:filters')?.[0]).toEqual([
            { name: { operator: 'contains', value: 'alpha' } },
        ]);
    });

    it('uses a native date input and comparison contract for date filters', async () => {
        const wrapper = mountFull({
            columns: [column({
                key: 'due_date',
                label: 'Due date',
                type: 'date',
                filter: { type: 'date' },
            })],
            rows: [],
        });

        document.querySelector<HTMLButtonElement>('.erp-column-filter-trigger')!.click();
        await nextTick();

        const value = document.querySelector<HTMLInputElement>('#lot2-table_filter_due_date input[type="date"]');
        expect(value).not.toBeNull();
        value!.value = '2026-07-20';
        value!.dispatchEvent(new Event('input', { bubbles: true }));
        await nextTick();

        document.querySelector<HTMLButtonElement>('#lot2-table_filter_due_date .erp-filter-apply')!.click();
        await nextTick();

        expect(wrapper.emitted('update:filters')?.[0]).toEqual([
            { due_date: { operator: '=', value: '2026-07-20' } },
        ]);
    });

    it('applies an accessible option-driven multiselect filter with the in contract', async () => {
        const statusColumn = column({
            key: 'status',
            label: 'Status',
            type: 'status',
            filter: {
                type: 'multiselect',
                options: {
                    draft: 'Draft',
                    confirmed: 'Confirmed',
                    cancelled: 'Cancelled',
                },
            },
        });
        const wrapper = mountFull({
            columns: [statusColumn],
            filters: { status: { operator: 'in', value: 'confirmed' } },
        });

        const trigger = document.querySelector<HTMLButtonElement>('[aria-label="Filter Status"]');
        expect(trigger).not.toBeNull();
        trigger!.click();
        await nextTick();

        const fieldset = document.querySelector<HTMLFieldSetElement>('#lot2-table_filter_status fieldset');
        expect(fieldset).not.toBeNull();
        expect(fieldset!.querySelector('legend')?.textContent?.trim()).toBe('Filter Status');

        const labels = Array.from(fieldset!.querySelectorAll('label'));
        expect(labels.map((label) => label.textContent?.trim())).toEqual(['Draft', 'Confirmed', 'Cancelled']);
        labels.forEach((label) => {
            expect(label.htmlFor).toBe(label.querySelector('input')?.id);
        });

        const checkboxes = Array.from(fieldset!.querySelectorAll<HTMLInputElement>('input[type="checkbox"]'));
        expect(checkboxes.map((checkbox) => checkbox.checked)).toEqual([false, true, false]);
        checkboxes[0].click();
        await nextTick();

        document.querySelector<HTMLButtonElement>('#lot2-table_filter_status .erp-filter-apply')!.click();
        await nextTick();

        expect(wrapper.emitted('update:filters')?.[0]).toEqual([
            { status: { operator: 'in', value: 'draft,confirmed' } },
        ]);
        expect(trigger!.getAttribute('aria-expanded')).toBe('false');
    });

    it('clears an active multiselect filter and closes its popover', async () => {
        const wrapper = mountFull({
            columns: [column({
                key: 'status',
                label: 'Status',
                filter: {
                    type: 'multiselect',
                    options: { draft: 'Draft', confirmed: 'Confirmed' },
                },
            })],
            filters: { status: { operator: 'in', value: 'draft,confirmed' } },
        });

        const trigger = document.querySelector<HTMLButtonElement>('[aria-label="Filter Status"]');
        trigger!.click();
        await nextTick();

        document.querySelector<HTMLButtonElement>('#lot2-table_filter_status .erp-filter-clear')!.click();
        await nextTick();

        expect(wrapper.emitted('update:filters')?.[0]).toEqual([{}]);
        expect(trigger!.getAttribute('aria-expanded')).toBe('false');
    });
});
