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

vi.mock('../../resources/js/api/auth', () => ({
    login: vi.fn(),
    register: vi.fn(),
    me: vi.fn(),
    logout: vi.fn(),
    verifyTwoFactor: vi.fn(),
    forgotPassword: vi.fn(),
    resetPassword: vi.fn(),
}));

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

import * as authApi from '../../resources/js/api/auth';
import { useAuthStore } from '../../resources/js/stores/auth';
import ResetPasswordView from '../../resources/js/views/auth/ResetPasswordView.vue';

const mountReset = async (path = '/reset/abc-token-xyz?email=user@example.ru') => {
    const pinia = createPinia();
    setActivePinia(pinia);
    const router = createRouter({
        history: createMemoryHistory(),
        routes: [
            { path: '/reset/:token', name: 'reset-password', component: ResetPasswordView },
            { path: '/login', name: 'login', component: { template: '<div>stub</div>' } },
        ],
    });
    await router.push(path);
    await router.isReady();
    return mount(ResetPasswordView, {
        global: { plugins: [pinia, createVuetify(), router] },
    });
};

describe('ResetPasswordView.vue', () => {
    beforeEach(() => {
        vi.clearAllMocks();
        vi.useFakeTimers();
    });

    it('монтируется и содержит заголовок «Новый пароль»', async () => {
        const wrapper = await mountReset();
        expect(wrapper.text()).toContain('Новый пароль');
    });

    it('предзаполняет email из query-параметра', async () => {
        const wrapper = await mountReset('/reset/some-token?email=preset@example.ru');
        const emailInput = wrapper.find('input[type="email"]');
        expect((emailInput.element as HTMLInputElement).value).toBe('preset@example.ru');
    });

    it('содержит поля пароля + подтверждения с autocomplete=new-password', async () => {
        const wrapper = await mountReset();
        const passwordInputs = wrapper.findAll('input[type="password"]');
        expect(passwordInputs.length).toBe(2);
        passwordInputs.forEach((input) => {
            expect(input.attributes('autocomplete')).toBe('new-password');
        });
    });

    it('после успешного submit показывает success-state и скрывает форму', async () => {
        vi.mocked(authApi.resetPassword).mockResolvedValue({ message: 'Пароль успешно изменён.' });

        const wrapper = await mountReset('/reset/valid-token?email=user@example.ru');

        await wrapper.findAll('input[type="password"]')[0].setValue('new-strong-pass-1234');
        await wrapper.findAll('input[type="password"]')[1].setValue('new-strong-pass-1234');
        await wrapper.find('form').trigger('submit.prevent');

        await wrapper.vm.$nextTick();
        await wrapper.vm.$nextTick();

        expect(wrapper.find('[data-testid="reset-success"]').exists()).toBe(true);
        expect(wrapper.find('form').exists()).toBe(false);
        expect(authApi.resetPassword).toHaveBeenCalledWith(
            expect.objectContaining({
                token: 'valid-token',
                email: 'user@example.ru',
                password: 'new-strong-pass-1234',
                password_confirmation: 'new-strong-pass-1234',
            }),
        );
    });

    it('при 429 показывает lockout-alert через auth.lockoutSeconds', async () => {
        const wrapper = await mountReset();
        const auth = useAuthStore();
        auth.lockoutSeconds = 600;
        await wrapper.vm.$nextTick();

        const alert = wrapper.find('[data-testid="lockout-alert"]');
        expect(alert.exists()).toBe(true);
        expect(alert.text()).toContain('10 мин');
    });

    it('A4: показывает ошибку при несовпадении пароля и подтверждения', async () => {
        const wrapper = await mountReset();
        const pwInputs = wrapper.findAll('input[type="password"]');
        await pwInputs[0].setValue('new-strong-pass-1234');
        await pwInputs[1].setValue('different-pass-9999');
        await wrapper.vm.$nextTick();
        expect(wrapper.text()).toContain('Пароли не совпадают');
    });

    it('A9: переключатель видимости пароля имеет accessible-name и работает', async () => {
        const wrapper = await mountReset();
        const toggle = wrapper.find('[aria-label="Показать пароль"]');
        expect(toggle.exists()).toBe(true);
        expect(toggle.attributes('role')).toBe('button');
        await toggle.trigger('click');
        expect(wrapper.find('[aria-label="Скрыть пароль"]').exists()).toBe(true);

        // keyboard activation (Enter) — toggle back
        await wrapper.find('[aria-label="Скрыть пароль"]').trigger('keydown', { key: 'Enter' });
        expect(wrapper.find('[aria-label="Показать пароль"]').exists()).toBe(true);
    });
});
