import { describe, it, expect, vi, beforeEach } from 'vitest';
import type { Note } from '@shared/types';

vi.mock('../../src/renderer/inbox/api.js', () => ({
  inboxApi: {
    listRecallCandidate: vi.fn(),
    markRecallOpened: vi.fn(),
    dismissRecall: vi.fn(),
    emitRecallShown: vi.fn(),
    emitRecallSnoozed: vi.fn(),
    listNotes: vi.fn(async () => []),
    getContinuity: vi.fn(async () => ({ weekStart: '', weekCount: 0, weekTarget: 7, consecutiveCompleteWeeks: 0, showRecoveryToast: false, lastNoteAt: null })),
    getPendingCount: vi.fn(async () => 0),
    getOllamaStatus: vi.fn(async () => ({ ok: true })),
    getTodayCount: vi.fn(async () => 0),
    getTrashCount: vi.fn(async () => 0),
    listExpired: vi.fn(async () => []),
    getFailedCount: vi.fn(async () => 0)
  }
}));

import { useInbox } from '../../src/renderer/inbox/store.js';
import { inboxApi } from '../../src/renderer/inbox/api.js';

const inboxApiMock = inboxApi as unknown as {
  listRecallCandidate: ReturnType<typeof vi.fn>;
  markRecallOpened: ReturnType<typeof vi.fn>;
  dismissRecall: ReturnType<typeof vi.fn>;
  emitRecallShown: ReturnType<typeof vi.fn>;
  emitRecallSnoozed: ReturnType<typeof vi.fn>;
};

const note = (id: string): Note => ({
  id, rawText: 'x', aiTitle: 't', aiSummary: 'a\nb\nc',
  tags: [], media: [], aiStatus: 'done', aiProvider: null, aiGeneratedAt: null, aiError: null,
  titleEditedByUser: false, summaryEditedByUser: false,
  dueDate: null, dueDateEditedByUser: false,
  userIntent: null, intentPromptedAt: null,
  createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
  deletedAt: null, lastRecalledAt: null, recallDismissedAt: null,
  status: 'active', statusChangedAt: null, moveReason: null
});

describe('store recall actions', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    useInbox.setState({
      recallCandidate: null,
      recallSnoozeUntilMs: null,
    } as Parameters<typeof useInbox.setState>[0]);
  });

  it('snoozeRecall sets snoozeUntilMs to next KST midnight + emits recall_snoozed', async () => {
    useInbox.setState({ recallCandidate: note('n1') } as Parameters<typeof useInbox.setState>[0]);
    await useInbox.getState().snoozeRecall();
    const ms = useInbox.getState().recallSnoozeUntilMs;
    expect(ms).not.toBeNull();
    expect(ms!).toBeGreaterThan(Date.now());
    expect(inboxApiMock.emitRecallSnoozed).toHaveBeenCalledWith('n1');
  });

  it('openRecall calls API + fetches next candidate', async () => {
    inboxApiMock.markRecallOpened.mockResolvedValueOnce({ note: note('n1') });
    inboxApiMock.listRecallCandidate.mockResolvedValueOnce(null);
    await useInbox.getState().openRecall('n1');
    expect(inboxApiMock.markRecallOpened).toHaveBeenCalledWith('n1');
    expect(inboxApiMock.listRecallCandidate).toHaveBeenCalled();
    expect(useInbox.getState().recallCandidate).toBeNull();
  });

  it('dismissRecallNote calls API + fetches next candidate', async () => {
    inboxApiMock.dismissRecall.mockResolvedValueOnce({ note: note('n1') });
    inboxApiMock.listRecallCandidate.mockResolvedValueOnce(note('n2'));
    await useInbox.getState().dismissRecallNote('n1');
    expect(inboxApiMock.dismissRecall).toHaveBeenCalledWith('n1');
    expect(useInbox.getState().recallCandidate?.id).toBe('n2');
  });
});
