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

const mockApi = {
  listNotes: vi.fn(async () => [] as Note[]),
  listTrash: vi.fn(async () => [] as Note[]),
  getTrashCount: vi.fn(async () => 0),
  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),
  restoreNote: vi.fn(async () => {}),
  permanentDeleteNote: vi.fn(async () => ({ confirmed: true })),
  emptyTrash: vi.fn(async () => ({ confirmed: true, count: 0 })),
  deleteNote: vi.fn(async () => {}),
  onNoteUpdated: vi.fn(() => () => {}),
  updateAiFields: vi.fn(async () => {}),
  setDueDate: vi.fn(async () => {}),
  setIntent: vi.fn(async () => {}),
  dismissIntent: vi.fn(async () => {})
};

vi.mock('../../src/renderer/inbox/api.js', () => ({ inboxApi: mockApi }));

const noteStub = (id: string, deletedAt: string | null = null): Note => ({
  id, rawText: 'x',
  aiTitle: null, aiSummary: null, aiStatus: 'done', aiError: null,
  aiProvider: null, aiGeneratedAt: null,
  titleEditedByUser: false, summaryEditedByUser: false,
  userIntent: null, intentPromptedAt: null,
  dueDate: null, dueDateEditedByUser: false,
  deletedAt, lastRecalledAt: null, recallDismissedAt: null,
  status: deletedAt ? 'trashed' : 'active', statusChangedAt: deletedAt, moveReason: null,
  createdAt: '2026-05-01T00:00:00Z', updatedAt: '2026-05-01T00:00:00Z',
  tags: [], media: []
});

describe('useInbox — trash state (v0.2.3 #4)', () => {
  beforeEach(async () => {
    const { useInbox } = await import('../../src/renderer/inbox/store.js');
    useInbox.setState({
      notes: [], trashNotes: [], trashCount: 0, showTrash: false,
      loading: false, tagFilter: null, pendingCount: 0, todayCount: 0,
      ollamaStatus: { ok: true },
      continuity: { weekStart: '', weekCount: 0, weekTarget: 7, consecutiveCompleteWeeks: 0, showRecoveryToast: false, lastNoteAt: null }
    });
    Object.values(mockApi).forEach((fn) => 'mockClear' in fn && (fn as any).mockClear());
  });

  it('toggleShowTrash flips state and triggers loadTrash on enter', async () => {
    mockApi.listTrash.mockResolvedValueOnce([noteStub('t1', '2026-05-01T00:00:00Z')]);
    const { useInbox } = await import('../../src/renderer/inbox/store.js');
    await useInbox.getState().toggleShowTrash();
    expect(useInbox.getState().showTrash).toBe(true);
    expect(useInbox.getState().trashNotes).toHaveLength(1);
    expect(mockApi.listTrash).toHaveBeenCalled();
    await useInbox.getState().toggleShowTrash();
    expect(useInbox.getState().showTrash).toBe(false);
  });

  it('upsertNote routes to trashNotes when deletedAt IS NOT NULL', async () => {
    const { useInbox } = await import('../../src/renderer/inbox/store.js');
    useInbox.getState().upsertNote(noteStub('a', '2026-05-01T00:00:00Z'));
    expect(useInbox.getState().notes).toHaveLength(0);
    expect(useInbox.getState().trashNotes).toHaveLength(1);
  });

  it('upsertNote moves note from notes to trashNotes when trashed', async () => {
    const { useInbox } = await import('../../src/renderer/inbox/store.js');
    useInbox.getState().upsertNote(noteStub('a'));
    expect(useInbox.getState().notes).toHaveLength(1);
    useInbox.getState().upsertNote(noteStub('a', '2026-05-01T00:00:00Z'));
    expect(useInbox.getState().notes).toHaveLength(0);
    expect(useInbox.getState().trashNotes).toHaveLength(1);
  });

  it('restoreNote calls api + moves note from trashNotes to notes (낙관적 갱신)', async () => {
    const { useInbox } = await import('../../src/renderer/inbox/store.js');
    useInbox.getState().upsertNote(noteStub('a', '2026-05-01T00:00:00Z'));
    expect(useInbox.getState().trashNotes).toHaveLength(1);
    await useInbox.getState().restoreNote('a');
    expect(mockApi.restoreNote).toHaveBeenCalledWith('a');
    // main 은 restore 시 pushNoteUpdated 안 보냄 — store 자가 갱신 검증
    expect(useInbox.getState().trashNotes).toHaveLength(0);
    expect(useInbox.getState().notes).toHaveLength(1);
    expect(useInbox.getState().notes[0]!.deletedAt).toBeNull();
  });

  it('upsertNote with showTrash=false preserves server trashCount (regression I1)', async () => {
    const { useInbox } = await import('../../src/renderer/inbox/store.js');
    // server 가 trashCount=5 알려줬는데 trashNotes 는 미로드 (showTrash=false 기본)
    useInbox.setState({ trashCount: 5, trashNotes: [] });
    useInbox.getState().upsertNote(noteStub('active-1'));
    expect(useInbox.getState().trashCount).toBe(5); // server 값 보존
    expect(useInbox.getState().notes).toHaveLength(1);
  });

  it('emptyTrash with cancelled confirm leaves trashNotes intact', async () => {
    mockApi.emptyTrash.mockResolvedValueOnce({ confirmed: false, count: 0 });
    const { useInbox } = await import('../../src/renderer/inbox/store.js');
    useInbox.getState().upsertNote(noteStub('a', '2026-05-01T00:00:00Z'));
    await useInbox.getState().emptyTrash();
    expect(useInbox.getState().trashNotes).toHaveLength(1);
  });
});
