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

vi.mock('../../resources/js/api/apiKeys', () => ({
    listApiKeys: vi.fn(),
    regenerateApiKey: vi.fn(),
}));

vi.mock('../../resources/js/api/webhooks', () => ({
    getWebhookSettings: vi.fn(),
    saveWebhookSettings: vi.fn(),
    testWebhook: vi.fn(),
}));

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

import * as apiKeysApi from '../../resources/js/api/apiKeys';
import * as webhooksApi from '../../resources/js/api/webhooks';
import ApiTab from '../../resources/js/views/settings/ApiTab.vue';

const vuetify = createVuetify();

const flush = () => new Promise((r) => setTimeout(r, 30));

const mountTab = () => mount(ApiTab, { global: { plugins: [vuetify] } });

describe('ApiTab.vue', () => {
    beforeEach(() => {
        vi.clearAllMocks();
        (apiKeysApi.listApiKeys as ReturnType<typeof vi.fn>).mockResolvedValue([]);
        (webhooksApi.getWebhookSettings as ReturnType<typeof vi.fn>).mockResolvedValue(null);
        Object.assign(navigator, { clipboard: { writeText: vi.fn().mockResolvedValue(undefined) } });
    });

    it('загружает и показывает префикс API-ключа', async () => {
        (apiKeysApi.listApiKeys as ReturnType<typeof vi.fn>).mockResolvedValue([
            {
                id: 1,
                name: 'API-ключ',
                key_prefix: 'lpkapi_abc',
                last_used_at: null,
                expires_at: null,
                created_at: null,
            },
        ]);
        const wrapper = mountTab();
        await flush();
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const vm = wrapper.vm as any;
        expect(vm.apiKeyExists).toBe(true);
        expect(vm.apiTokenDisplay).toBe('lpkapi_abc');
    });

    it('copyToken() пишет в буфер и открывает toast', async () => {
        (apiKeysApi.listApiKeys as ReturnType<typeof vi.fn>).mockResolvedValue([
            {
                id: 1,
                name: 'API-ключ',
                key_prefix: 'lpkapi_abc',
                last_used_at: null,
                expires_at: null,
                created_at: null,
            },
        ]);
        const wrapper = mountTab();
        await flush();
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const vm = wrapper.vm as any;
        await vm.copyToken();
        expect(navigator.clipboard.writeText).toHaveBeenCalledWith('lpkapi_abc');
        expect(vm.toastOpen).toBe(true);
    });

    it('confirmRegenerate() показывает полный новый ключ один раз', async () => {
        (apiKeysApi.regenerateApiKey as ReturnType<typeof vi.fn>).mockResolvedValue({
            id: 2,
            name: 'API-ключ',
            key: 'lpkapi_FULLNEWKEYVALUE0000000000',
            key_prefix: 'lpkapi_FUL',
        });
        const wrapper = mountTab();
        await flush();
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const vm = wrapper.vm as any;
        await vm.confirmRegenerate();
        expect(apiKeysApi.regenerateApiKey).toHaveBeenCalled();
        expect(vm.apiTokenDisplay).toBe('lpkapi_FULLNEWKEYVALUE0000000000');
        expect(vm.fullKeyShown).toBe(true);
    });

    it('загружает настройки webhook', async () => {
        (webhooksApi.getWebhookSettings as ReturnType<typeof vi.fn>).mockResolvedValue({
            target_url: 'https://crm.example.ru/hook',
            secret_prefix: 'whsec_abc',
            events: ['deal.created'],
            is_active: true,
        });
        const wrapper = mountTab();
        await flush();
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const vm = wrapper.vm as any;
        expect(vm.webhookUrl).toBe('https://crm.example.ru/hook');
        expect(vm.secretDisplay).toBe('whsec_abc');
    });

    it('saveWebhook() вызывает saveWebhookSettings и показывает secret один раз', async () => {
        (webhooksApi.saveWebhookSettings as ReturnType<typeof vi.fn>).mockResolvedValue({
            target_url: 'https://crm.example.ru/hook',
            secret_prefix: 'whsec_new',
            events: ['deal.created'],
            is_active: true,
            secret: 'whsec_FULLSECRETVALUE0000',
        });
        const wrapper = mountTab();
        await flush();
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const vm = wrapper.vm as any;
        vm.webhookUrl = 'https://crm.example.ru/hook';
        await vm.saveWebhook();
        expect(webhooksApi.saveWebhookSettings).toHaveBeenCalledWith({ target_url: 'https://crm.example.ru/hook' });
        expect(vm.secretDisplay).toBe('whsec_FULLSECRETVALUE0000');
        expect(vm.fullSecretShown).toBe(true);
        expect(vm.webhookSuccess).toBeTruthy();
    });

    it('runWebhookTest() вызывает testWebhook и открывает toast с результатом', async () => {
        (webhooksApi.testWebhook as ReturnType<typeof vi.fn>).mockResolvedValue({
            ok: true,
            status: 200,
            message: 'Тестовый запрос доставлен (HTTP 200).',
        });
        const wrapper = mountTab();
        await flush();
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const vm = wrapper.vm as any;
        await vm.runWebhookTest();
        expect(webhooksApi.testWebhook).toHaveBeenCalled();
        expect(vm.toastOpen).toBe(true);
        expect(vm.toastText).toContain('HTTP 200');
    });

    it('loadApiKey() выставляет apiKeyError при reject', async () => {
        (apiKeysApi.listApiKeys as ReturnType<typeof vi.fn>).mockRejectedValue(new Error('boom'));
        const wrapper = mountTab();
        await flush();
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const vm = wrapper.vm as any;
        expect(vm.apiKeyError).toBeTruthy();
    });

    it('loadWebhook() выставляет webhookError при reject', async () => {
        (webhooksApi.getWebhookSettings as ReturnType<typeof vi.fn>).mockRejectedValue(new Error('boom'));
        const wrapper = mountTab();
        await flush();
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const vm = wrapper.vm as any;
        expect(vm.webhookError).toBeTruthy();
    });
});
