import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import {
    afterEach,
    beforeEach,
    describe,
    expect,
    it,
    vi,
} from 'vitest';
import SettingsAdminPanel from '@/components/application/settings/SettingsAdminPanel.vue';
import type { SettingsPayload } from '@/types/settings';

const admin = (): NonNullable<SettingsPayload['admin']> => ({
    links: {
        currencies: '/exchange-rates',
        capitalAccounts: '/capital-accounts/validate',
        dropdowns: '/dropdowns',
    },
    storeUrl: '/dynamic-fields',
    fields: [{
        id: 'field-1',
        model: 'fund',
        modelLabel: 'Fund',
        displayName: 'Strategy',
        fieldName: 'strategy',
        fieldType: 'string',
        inputType: null,
        order: 100,
        description: null,
        validation: null,
        dropdownValue: null,
        readOnly: false,
        updateUrl: '/dynamic-fields/field-1',
        deleteUrl: '/dynamic-fields/field-1',
    }],
    selectedField: {
        id: 'field-1',
        model: 'fund',
        modelLabel: 'Fund',
        displayName: 'Strategy',
        fieldName: 'strategy',
        fieldType: 'string',
        inputType: null,
        order: 100,
        description: null,
        validation: null,
        dropdownValue: null,
        readOnly: false,
        updateUrl: '/dynamic-fields/field-1',
        deleteUrl: '/dynamic-fields/field-1',
    },
    options: {
        models: [{ value: 'fund', label: 'Fund' }],
        fieldTypes: [{ value: 'string', label: 'String' }],
        inputTypes: [{ value: '', label: 'Automatic' }],
    },
});

const flush = async (): Promise<void> => {
    await nextTick();
    await new Promise((resolve) => setTimeout(resolve, 0));
    await nextTick();
};

beforeEach(() => {
    class ResizeObserverStub {
        observe(): void {}

        unobserve(): void {}

        disconnect(): void {}
    }

    Object.defineProperty(window, 'ResizeObserver', {
        configurable: true,
        value: ResizeObserverStub,
    });

    if (!window.PointerEvent) {
        Object.defineProperty(window, 'PointerEvent', {
            configurable: true,
            value: MouseEvent,
        });
    }

    Element.prototype.scrollIntoView = vi.fn();
    HTMLElement.prototype.hasPointerCapture = vi.fn(() => false);
    HTMLElement.prototype.releasePointerCapture = vi.fn();
});

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

describe('SettingsAdminPanel', () => {
    it('uses the shared destructive confirmation and preserves the native delete payload', async () => {
        const wrapper = mount(SettingsAdminPanel, {
            props: {
                admin: admin(),
                errors: {},
                busy: false,
            },
            attachTo: document.body,
        });
        const deleteTrigger = wrapper.findAll<HTMLButtonElement>('button')
            .find((button) => button.text().trim() === 'Delete');

        expect(deleteTrigger).toBeDefined();
        expect(deleteTrigger?.attributes('aria-haspopup')).toBe('dialog');
        expect(deleteTrigger?.attributes('aria-controls')).toBe('settings-delete-field-dialog');

        deleteTrigger?.element.focus();
        await deleteTrigger?.trigger('click');
        await flush();

        const dialog = document.body.querySelector<HTMLElement>('#settings-delete-field-dialog');
        const cancel = document.body.querySelector<HTMLButtonElement>('.ui-confirm-dialog__cancel');

        expect(dialog?.getAttribute('role')).toBe('alertdialog');
        expect(dialog?.textContent).toContain('Delete dynamic field?');
        expect(dialog?.textContent).toContain('Existing values will no longer be displayed.');
        expect(document.activeElement).toBe(cancel);

        document.dispatchEvent(new KeyboardEvent('keydown', {
            key: 'Escape',
            bubbles: true,
            cancelable: true,
        }));
        await flush();

        expect(document.body.querySelector('#settings-delete-field-dialog')).toBeNull();
        expect(document.activeElement).toBe(deleteTrigger?.element);
        expect(wrapper.emitted('submit')).toBeUndefined();

        await deleteTrigger?.trigger('click');
        await flush();
        document.body.querySelector<HTMLButtonElement>('.ui-confirm-dialog__accept')?.click();
        await flush();

        const submission = wrapper.emitted('submit')?.[0];
        const data = submission?.[1] as FormData;

        expect(submission?.[0]).toBe('/dynamic-fields/field-1');
        expect(data.get('_method')).toBe('DELETE');
        expect(submission?.[2]).toBe(false);
        expect(document.body.querySelector('#settings-delete-field-dialog')).toBeNull();

        wrapper.unmount();
    });
});
