import { describe, it, expect, beforeEach, vi } from 'vitest';

vi.mock('../../resources/js/api/client', () => ({
    apiClient: {
        get: vi.fn(),
        post: vi.fn(),
        patch: vi.fn(),
        delete: vi.fn(),
    },
    ensureCsrfCookie: vi.fn(),
}));

import {
    login,
    register,
    me,
    logout,
    verifyTwoFactor,
    useRecoveryCode,
    twoFactorInit,
    twoFactorConfirm,
    twoFactorDisable,
    twoFactorRegenerateRecoveryCodes,
    forgotPassword,
    resetPassword,
    updateNotificationPreferences,
} from '../../resources/js/api/auth';
import { apiClient, ensureCsrfCookie } from '../../resources/js/api/client';

const FAKE_USER = {
    id: 1,
    email: 'demo@x.ru',
    first_name: 'D',
    last_name: 'U',
    tenant_id: 1,
    totp_enabled: false,
    last_login_at: null,
};

describe('api/auth', () => {
    beforeEach(() => vi.clearAllMocks());

    it('login() POSTs /api/auth/login + calls ensureCsrfCookie + unwraps data', async () => {
        vi.mocked(apiClient.post).mockResolvedValue({ data: { user: FAKE_USER, requires_2fa: false } });
        const result = await login({ email: 'a@x.ru', password: 'pw' });
        expect(ensureCsrfCookie).toHaveBeenCalledOnce();
        expect(apiClient.post).toHaveBeenCalledWith('/api/auth/login', { email: 'a@x.ru', password: 'pw' });
        expect(result.requires_2fa).toBe(false);
        expect(result.user.email).toBe('demo@x.ru');
    });

    it('register() POSTs /api/auth/register с accept-флагами + captcha (G1/SP3a)', async () => {
        vi.mocked(apiClient.post).mockResolvedValue({
            data: { status: 'pending_email_confirm', email: 'a@x.ru', expires_at: '2026-06-18T12:00:00+00:00' },
        });
        await register({ email: 'a@x.ru', password: 'pw', accept_offer: true, accept_pdn: true, captcha_token: 'tok' });
        expect(ensureCsrfCookie).toHaveBeenCalledOnce();
        expect(apiClient.post).toHaveBeenCalledWith('/api/auth/register', {
            email: 'a@x.ru',
            password: 'pw',
            accept_offer: true,
            accept_pdn: true,
            captcha_token: 'tok',
        });
    });

    it('me() GETs /api/auth/me + unwraps data.user', async () => {
        vi.mocked(apiClient.get).mockResolvedValue({ data: { user: FAKE_USER } });
        const result = await me();
        expect(apiClient.get).toHaveBeenCalledWith('/api/auth/me');
        expect(result.id).toBe(1);
    });

    it('logout() POSTs /api/auth/logout + ensureCsrfCookie', async () => {
        vi.mocked(apiClient.post).mockResolvedValue({ data: {} });
        await logout();
        expect(ensureCsrfCookie).toHaveBeenCalledOnce();
        expect(apiClient.post).toHaveBeenCalledWith('/api/auth/logout');
    });

    it('verifyTwoFactor() POSTs /api/auth/2fa/verify с code', async () => {
        vi.mocked(apiClient.post).mockResolvedValue({ data: { user: FAKE_USER, requires_2fa: false } });
        await verifyTwoFactor('123456');
        expect(ensureCsrfCookie).toHaveBeenCalledOnce();
        expect(apiClient.post).toHaveBeenCalledWith('/api/auth/2fa/verify', { code: '123456' });
    });

    it('useRecoveryCode() POSTs /api/auth/2fa/recovery-use с code + возвращает remaining', async () => {
        vi.mocked(apiClient.post).mockResolvedValue({
            data: { user: FAKE_USER, requires_2fa: false, recovery_codes_remaining: 7 },
        });
        const r = await useRecoveryCode('xxxx-yyyy');
        expect(ensureCsrfCookie).toHaveBeenCalledOnce();
        expect(apiClient.post).toHaveBeenCalledWith('/api/auth/2fa/recovery-use', { code: 'xxxx-yyyy' });
        expect(r.recovery_codes_remaining).toBe(7);
    });

    it('twoFactorInit() POSTs /api/2fa/init + возвращает secret+qr_url', async () => {
        vi.mocked(apiClient.post).mockResolvedValue({ data: { secret: 'JBSW', qr_url: 'otpauth://...' } });
        const r = await twoFactorInit();
        expect(ensureCsrfCookie).toHaveBeenCalledOnce();
        expect(apiClient.post).toHaveBeenCalledWith('/api/2fa/init');
        expect(r.secret).toBe('JBSW');
    });

    it('twoFactorConfirm() POSTs /api/2fa/confirm с code', async () => {
        vi.mocked(apiClient.post).mockResolvedValue({ data: { recovery_codes: ['a', 'b'], message: 'ok' } });
        await twoFactorConfirm('000000');
        expect(apiClient.post).toHaveBeenCalledWith('/api/2fa/confirm', { code: '000000' });
    });

    it('twoFactorDisable() POSTs /api/2fa/disable с паролем', async () => {
        vi.mocked(apiClient.post).mockResolvedValue({ data: { message: 'disabled' } });
        await twoFactorDisable('current-pw');
        expect(apiClient.post).toHaveBeenCalledWith('/api/2fa/disable', { password: 'current-pw' });
    });

    it('twoFactorRegenerateRecoveryCodes() POSTs /api/2fa/regenerate-recovery-codes', async () => {
        vi.mocked(apiClient.post).mockResolvedValue({ data: { recovery_codes: ['x', 'y', 'z'], message: 'ok' } });
        const r = await twoFactorRegenerateRecoveryCodes('pw');
        expect(apiClient.post).toHaveBeenCalledWith('/api/2fa/regenerate-recovery-codes', { password: 'pw' });
        expect(r.recovery_codes.length).toBe(3);
    });

    it('forgotPassword() POSTs /api/auth/forgot с email', async () => {
        vi.mocked(apiClient.post).mockResolvedValue({ data: { message: 'sent' } });
        await forgotPassword('a@x.ru');
        expect(apiClient.post).toHaveBeenCalledWith('/api/auth/forgot', { email: 'a@x.ru' });
    });

    it('resetPassword() POSTs /api/auth/reset-password с token+email+password', async () => {
        vi.mocked(apiClient.post).mockResolvedValue({ data: { message: 'reset' } });
        const payload = { token: 't', email: 'a@x.ru', password: 'newpw', password_confirmation: 'newpw' };
        await resetPassword(payload);
        expect(apiClient.post).toHaveBeenCalledWith('/api/auth/reset-password', payload);
    });

    it('updateNotificationPreferences() PATCH /api/auth/me/notification-preferences', async () => {
        vi.mocked(apiClient.patch).mockResolvedValue({ data: { user: FAKE_USER } });
        const payload = { prefs: { new_lead: { inapp: true } }, sound_enabled: false };
        await updateNotificationPreferences(payload);
        expect(ensureCsrfCookie).toHaveBeenCalledOnce();
        expect(apiClient.patch).toHaveBeenCalledWith('/api/auth/me/notification-preferences', payload);
    });
});
