import { describe, it, expect, vi, beforeEach } from 'vitest';
import { mount, flushPromises } from '@vue/test-utils';
import { createVuetify } from 'vuetify';
import { createRouter, createMemoryHistory } from 'vue-router';
import AdminIncidentDetailView from '../../resources/js/views/admin/AdminIncidentDetailView.vue';
import type { ApiAdminIncidentDetail } from '../../resources/js/api/admin';

vi.mock('../../resources/js/api/admin', async (importOriginal) => {
    const orig = await importOriginal<typeof import('../../resources/js/api/admin')>();
    return {
        ...orig,
        getAdminIncidentDetail: vi.fn(),
        notifyIncidentRkn: vi.fn(),
    };
});

const adminApi = await import('../../resources/js/api/admin');

beforeEach(() => {
    vi.clearAllMocks();
});

function makeDetail(overrides: Partial<ApiAdminIncidentDetail> = {}): ApiAdminIncidentDetail {
    return {
        id: 7,
        incident_id: 'INC-2026-0516-0007',
        type: 'data_breach',
        severity: 'high',
        summary: 'Утечка данных тенантов',
        root_cause: 'Неправильная RLS-политика',
        postmortem_url: 'https://example.com/postmortem',
        started_at: '2026-05-16T10:00:00Z',
        detected_at: '2026-05-16T10:30:00Z',
        resolved_at: null,
        status: 'investigating',
        affected_tenants: [
            { id: 1, organization_name: 'Окна Москва ООО' },
            { id: 2, organization_name: 'ИП Петров' },
        ],
        affected_users_count: 42,
        notification_sent_at: null,
        rkn_notified: false,
        rkn_notified_at: null,
        rkn_deadline_at: '2026-05-17T10:30:00Z',
        created_by_admin: 'admin@liderra.ru',
        closed_by_admin: null,
        created_at: '2026-05-16T10:35:00Z',
        updated_at: '2026-05-16T10:35:00Z',
        ...overrides,
    };
}

const buildRouter = (id: number) => {
    const router = createRouter({
        history: createMemoryHistory(),
        routes: [
            { path: '/admin/incidents', name: 'admin-incidents', component: { template: '<div />' } },
            {
                path: '/admin/incidents/:id',
                name: 'admin-incident-detail',
                component: AdminIncidentDetailView,
            },
        ],
    });
    return router.push({ name: 'admin-incident-detail', params: { id } }).then(() => router);
};

const mountDetail = async (id: number) => {
    const router = await buildRouter(id);
    await router.isReady();
    const wrapper = mount(AdminIncidentDetailView, {
        global: {
            plugins: [createVuetify(), router],
            stubs: { teleport: true },
        },
    });
    await flushPromises();
    return wrapper;
};

describe('AdminIncidentDetailView.vue', () => {
    it('вызывает getAdminIncidentDetail с id из route и рендерит summary/incident_id/severity', async () => {
        vi.mocked(adminApi.getAdminIncidentDetail).mockResolvedValue(makeDetail());
        const wrapper = await mountDetail(7);
        expect(adminApi.getAdminIncidentDetail).toHaveBeenCalledWith(7);
        const text = wrapper.text();
        expect(text).toContain('INC-2026-0516-0007');
        expect(text).toContain('Утечка данных тенантов');
        expect(text).toContain('High');
    });

    it('404 от API → data-testid="incident-not-found"', async () => {
        vi.mocked(adminApi.getAdminIncidentDetail).mockRejectedValue({
            response: { status: 404 },
        });
        const wrapper = await mountDetail(999);
        expect(wrapper.find('[data-testid="incident-not-found"]').exists()).toBe(true);
    });

    it('500 от API → data-testid="incident-fetch-error" + кнопка Повторить', async () => {
        vi.mocked(adminApi.getAdminIncidentDetail).mockRejectedValue({
            response: { status: 500, data: { message: 'Backend error' } },
        });
        const wrapper = await mountDetail(7);
        expect(wrapper.find('[data-testid="incident-fetch-error"]').exists()).toBe(true);
        // retry button calls loadIncident
        vi.mocked(adminApi.getAdminIncidentDetail).mockResolvedValue(makeDetail());
        const retryBtn = wrapper.find(
            '[data-testid="incident-fetch-error"] button, [data-testid="incident-fetch-error"] .v-btn',
        );
        expect(retryBtn.exists()).toBe(true);
    });

    it('data_breach + rkn_notified=false → data-testid="rkn-notify-btn" видна', async () => {
        vi.mocked(adminApi.getAdminIncidentDetail).mockResolvedValue(
            makeDetail({ type: 'data_breach', rkn_notified: false }),
        );
        const wrapper = await mountDetail(7);
        expect(wrapper.find('[data-testid="rkn-notify-btn"]').exists()).toBe(true);
    });

    it('клик rkn-notify → confirm → вызывает notifyIncidentRkn, карточка обновляется (rkn_notified=true, кнопка исчезает)', async () => {
        vi.mocked(adminApi.getAdminIncidentDetail).mockResolvedValue(
            makeDetail({ type: 'data_breach', rkn_notified: false }),
        );
        const notified = makeDetail({
            type: 'data_breach',
            rkn_notified: true,
            rkn_notified_at: '2026-05-16T11:00:00Z',
        });
        vi.mocked(adminApi.notifyIncidentRkn).mockResolvedValue(notified);

        const wrapper = await mountDetail(7);
        // open dialog via btn
        await wrapper.find('[data-testid="rkn-notify-btn"]').trigger('click');
        await wrapper.vm.$nextTick();

        // call confirmRkn directly via defineExpose
        const vm = wrapper.vm as unknown as {
            confirmRkn: () => Promise<void>;
            incident: ApiAdminIncidentDetail | null;
            rknDialog: boolean;
        };
        await vm.confirmRkn();
        await flushPromises();

        expect(adminApi.notifyIncidentRkn).toHaveBeenCalledWith(7);
        expect(vm.incident?.rkn_notified).toBe(true);
        expect(wrapper.find('[data-testid="rkn-notify-btn"]').exists()).toBe(false);
    });

    it('type !== data_breach → кнопка РКН-notify отсутствует', async () => {
        vi.mocked(adminApi.getAdminIncidentDetail).mockResolvedValue(
            makeDetail({ type: 'service_outage', rkn_notified: false }),
        );
        const wrapper = await mountDetail(7);
        expect(wrapper.find('[data-testid="rkn-notify-btn"]').exists()).toBe(false);
    });

    it('rkn_notified=true → показывает "РКН уведомлён", кнопки нет', async () => {
        vi.mocked(adminApi.getAdminIncidentDetail).mockResolvedValue(
            makeDetail({ type: 'data_breach', rkn_notified: true, rkn_notified_at: '2026-05-17T08:00:00Z' }),
        );
        const wrapper = await mountDetail(7);
        expect(wrapper.find('[data-testid="rkn-notify-btn"]').exists()).toBe(false);
        expect(wrapper.text()).toContain('РКН уведомлён');
    });

    it('ошибка от notifyIncidentRkn → data-testid="rkn-error" виден', async () => {
        vi.mocked(adminApi.getAdminIncidentDetail).mockResolvedValue(
            makeDetail({ type: 'data_breach', rkn_notified: false }),
        );
        vi.mocked(adminApi.notifyIncidentRkn).mockRejectedValue(new Error('РКН endpoint недоступен'));

        const wrapper = await mountDetail(7);
        const vm = wrapper.vm as unknown as {
            confirmRkn: () => Promise<void>;
            rknError: string;
        };
        await vm.confirmRkn();
        await flushPromises();
        await wrapper.vm.$nextTick();

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