import { describe, it, expect, beforeEach, vi } from 'vitest';
import { mount } from '@vue/test-utils';
import { createPinia, setActivePinia } from 'pinia';
import { createVuetify } from 'vuetify';

vi.mock('../../resources/js/api/auth', () => ({
    updateNotificationPreferences: vi.fn(),
}));

vi.mock('../../resources/js/api/client', () => ({
    apiClient: {},
    ensureCsrfCookie: vi.fn(),
    extractValidationErrors: vi.fn(() => null),
    extractErrorMessage: vi.fn(() => 'Произошла ошибка.'),
    extractRateLimitRetry: vi.fn(() => null),
}));

import * as authApi from '../../resources/js/api/auth';
import NotificationsTab from '../../resources/js/views/settings/NotificationsTab.vue';
import { useAuthStore } from '../../resources/js/stores/auth';
import type { AuthUser } from '../../resources/js/api/auth';

const mockUser: AuthUser = {
    id: 1,
    email: 'test@example.ru',
    first_name: 'Иван',
    last_name: 'Петров',
    tenant_id: 1,
    totp_enabled: false,
    last_login_at: null,
    notification_preferences: {
        new_lead: { inapp: true, push: true, email: false },
        low_balance: { email: true },
        zero_balance: { email: true },
        topup_success: { email: true },
        invoice_paid: { email: true },
        new_device_login: { email: true },
        marketing: { email: false },
    },
    sound_enabled: true,
};

const factory = (user: AuthUser | null = mockUser) => {
    setActivePinia(createPinia());
    const auth = useAuthStore();
    auth.user = user;
    return mount(NotificationsTab, {
        global: { plugins: [createVuetify()] },
    });
};

describe('NotificationsTab.vue (schema-aligned)', () => {
    beforeEach(() => vi.clearAllMocks());

    it('содержит ровно 7 schema-aligned событий', () => {
        const wrapper = factory();
        const text = wrapper.text();
        [
            'Новый лид',
            'Низкий баланс',
            'Нулевой баланс',
            'Пополнение успешно',
            'Счёт оплачен',
            'Новое устройство',
            'Анонсы и промо',
        ].forEach((label) => expect(text).toContain(label));
        expect(text).not.toContain('Напоминание');
    });

    it('содержит ровно 2 канала (inapp/email) — без push и sms', () => {
        const wrapper = factory();
        const text = wrapper.text();
        expect(text).toContain('В приложении');
        expect(text).toContain('Email');
        expect(text).not.toContain('Push');
        expect(text).not.toContain('SMS');
    });

    it('legacy-events отсутствуют (Дубликат / Webhook упал и т.д.)', () => {
        const wrapper = factory();
        const text = wrapper.text();
        ['Дубликат / антифрод', 'Срок напоминания', 'Webhook упал', 'Месячный отчёт', 'Назначен менеджер'].forEach(
            (legacy) => expect(text).not.toContain(legacy),
        );
    });

    it('читает prefs из auth.user при mount: new_lead.email=false / low_balance.email=true', () => {
        const wrapper = factory();
        const newLeadEmail = wrapper.find('[data-testid="pref-new_lead-email"] input');
        const lowBalanceEmail = wrapper.find('[data-testid="pref-low_balance-email"] input');
        expect((newLeadEmail.element as HTMLInputElement).checked).toBe(false);
        expect((lowBalanceEmail.element as HTMLInputElement).checked).toBe(true);
    });

    it('Сохранить disabled пока ничего не изменено', () => {
        const wrapper = factory();
        const saveBtn = wrapper.find('[data-testid="save-btn"]');
        expect(saveBtn.attributes('disabled')).toBeDefined();
    });

    it('после переключения checkbox Сохранить становится enabled', async () => {
        const wrapper = factory();
        const checkbox = wrapper.find('[data-testid="pref-new_lead-email"] input');
        await checkbox.setValue(true);
        const saveBtn = wrapper.find('[data-testid="save-btn"]');
        expect(saveBtn.attributes('disabled')).toBeUndefined();
    });

    it('save() вызывает API и показывает success-alert', async () => {
        vi.mocked(authApi.updateNotificationPreferences).mockResolvedValue({
            ...mockUser,
            notification_preferences: {
                ...mockUser.notification_preferences,
                new_lead: { inapp: true, push: true, email: true },
            },
        });

        const wrapper = factory();
        const checkbox = wrapper.find('[data-testid="pref-new_lead-email"] input');
        await checkbox.setValue(true);
        await wrapper.find('[data-testid="save-btn"]').trigger('click');
        await new Promise((resolve) => setTimeout(resolve, 0));
        await wrapper.vm.$nextTick();

        expect(authApi.updateNotificationPreferences).toHaveBeenCalled();
        const callArg = vi.mocked(authApi.updateNotificationPreferences).mock.calls[0]![0];
        expect(callArg.prefs?.new_lead?.email).toBe(true);
        expect(wrapper.find('[data-testid="notifications-save-success"]').exists()).toBe(true);
    });

    it('save() при reject показывает error-alert', async () => {
        vi.mocked(authApi.updateNotificationPreferences).mockRejectedValue(new Error('500'));

        const wrapper = factory();
        const checkbox = wrapper.find('[data-testid="pref-new_lead-email"] input');
        await checkbox.setValue(true);
        await wrapper.find('[data-testid="save-btn"]').trigger('click');
        await new Promise((resolve) => setTimeout(resolve, 0));
        await wrapper.vm.$nextTick();

        expect(wrapper.find('[data-testid="notifications-save-error"]').exists()).toBe(true);
    });

    it('Отменить возвращает prefs к оригиналу (auth.user)', async () => {
        const wrapper = factory();
        const checkbox = wrapper.find('[data-testid="pref-new_lead-email"] input');
        await checkbox.setValue(true);
        await wrapper.find('[data-testid="reset-btn"]').trigger('click');
        await wrapper.vm.$nextTick();
        // dirty снова false → save disabled.
        expect(wrapper.find('[data-testid="save-btn"]').attributes('disabled')).toBeDefined();
    });

    it('sound_enabled читается из auth.user (default true)', () => {
        const wrapper = factory();
        const sw = wrapper.find('[data-testid="sound-enabled-switch"] input');
        expect((sw.element as HTMLInputElement).checked).toBe(true);
    });
});
