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

vi.mock('../../resources/js/api/reminders', () => ({
    listReminders: vi.fn(),
    createReminder: vi.fn(),
    updateReminder: vi.fn(),
    completeReminder: vi.fn(),
    deleteReminder: 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 remindersApi from '../../resources/js/api/reminders';
import { useRemindersStore } from '../../resources/js/stores/reminders';
import type { ApiReminder } from '../../resources/js/api/reminders';

const mockReminder = (id: number, overrides: Partial<ApiReminder> = {}): ApiReminder => ({
    id,
    deal_id: 100 + id,
    text: `Напоминание #${id}`,
    remind_at: new Date(2026, 4, 9, 14 + id, 0).toISOString(),
    completed_at: null,
    is_sent: false,
    sent_at: null,
    created_at: new Date(2026, 4, 9, 12, 0).toISOString(),
    created_by: 1,
    assignee_id: null,
    creator_name: 'Иван Петров',
    ...overrides,
});

describe('useRemindersStore', () => {
    beforeEach(() => {
        setActivePinia(createPinia());
        vi.clearAllMocks();
    });

    it('initial state', () => {
        const store = useRemindersStore();
        expect(store.items).toEqual([]);
        expect(store.counts).toEqual({ active: 0, today: 0, upcoming: 0, overdue: 0 });
    });

    it('load() заполняет items + counts', async () => {
        vi.mocked(remindersApi.listReminders).mockResolvedValue({
            items: [mockReminder(1), mockReminder(2)],
            counts: { active: 2, today: 1, upcoming: 1, overdue: 0 },
        });

        const store = useRemindersStore();
        await store.load();

        expect(store.items).toHaveLength(2);
        expect(store.counts.active).toBe(2);
    });

    it('load() при reject ставит fetchError', async () => {
        vi.mocked(remindersApi.listReminders).mockRejectedValue(new Error('500'));
        const store = useRemindersStore();
        await store.load();
        expect(store.fetchError).toBe(true);
    });

    it('refreshCounts() обновляет только counts', async () => {
        vi.mocked(remindersApi.listReminders).mockResolvedValue({
            items: [mockReminder(1)],
            counts: { active: 5, today: 2, upcoming: 1, overdue: 2 },
        });

        const store = useRemindersStore();
        store.items = [mockReminder(99)]; // pre-populate
        await store.refreshCounts();

        expect(store.counts.active).toBe(5);
        expect(store.items).toHaveLength(1); // не тронуто
    });

    it('create() добавляет в начало + increment active', async () => {
        const newR = mockReminder(99);
        vi.mocked(remindersApi.createReminder).mockResolvedValue(newR);

        const store = useRemindersStore();
        store.counts.active = 3;

        await store.create({ deal_id: 100, remind_at: new Date().toISOString() });
        expect(store.items[0]!.id).toBe(99);
        expect(store.counts.active).toBe(4);
    });

    it('create() при reject возвращает null', async () => {
        vi.mocked(remindersApi.createReminder).mockRejectedValue(new Error('500'));
        const store = useRemindersStore();
        const result = await store.create({ deal_id: 100, remind_at: new Date().toISOString() });
        expect(result).toBeNull();
    });

    it('complete() optimistic + decrement active', async () => {
        vi.mocked(remindersApi.listReminders).mockResolvedValue({
            items: [mockReminder(1)],
            counts: { active: 1, today: 1, upcoming: 0, overdue: 0 },
        });
        vi.mocked(remindersApi.completeReminder).mockResolvedValue(
            mockReminder(1, { completed_at: '2026-05-09T15:00:00Z' }),
        );

        const store = useRemindersStore();
        await store.load();
        await store.complete(1);

        expect(store.counts.active).toBe(0);
        // currentFilter='active' → удалили из items.
        expect(store.items).toHaveLength(0);
    });

    it('complete() при reject — revert', async () => {
        vi.mocked(remindersApi.listReminders).mockResolvedValue({
            items: [mockReminder(1)],
            counts: { active: 1, today: 1, upcoming: 0, overdue: 0 },
        });
        vi.mocked(remindersApi.completeReminder).mockRejectedValue(new Error('500'));

        const store = useRemindersStore();
        await store.load();
        await store.complete(1);

        expect(store.counts.active).toBe(1);
        expect(store.items[0]!.completed_at).toBeNull();
    });

    it('remove() optimistic убирает + decrement', async () => {
        vi.mocked(remindersApi.listReminders).mockResolvedValue({
            items: [mockReminder(1), mockReminder(2)],
            counts: { active: 2, today: 1, upcoming: 1, overdue: 0 },
        });
        vi.mocked(remindersApi.deleteReminder).mockResolvedValue();

        const store = useRemindersStore();
        await store.load();
        await store.remove(1);

        expect(store.items).toHaveLength(1);
        expect(store.counts.active).toBe(1);
    });

    it('remove() при reject — revert', async () => {
        vi.mocked(remindersApi.listReminders).mockResolvedValue({
            items: [mockReminder(1), mockReminder(2)],
            counts: { active: 2, today: 1, upcoming: 1, overdue: 0 },
        });
        vi.mocked(remindersApi.deleteReminder).mockRejectedValue(new Error('500'));

        const store = useRemindersStore();
        await store.load();
        await store.remove(1);

        expect(store.items).toHaveLength(2);
        expect(store.counts.active).toBe(2);
    });

    it('reset() очищает', async () => {
        vi.mocked(remindersApi.listReminders).mockResolvedValue({
            items: [mockReminder(1)],
            counts: { active: 1, today: 1, upcoming: 0, overdue: 0 },
        });
        const store = useRemindersStore();
        await store.load();
        store.reset();
        expect(store.items).toEqual([]);
        expect(store.counts).toEqual({ active: 0, today: 0, upcoming: 0, overdue: 0 });
    });
});
