import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import Database from 'better-sqlite3';
import { runMigrations } from '../../src/main/db/migrations/index.js';
import { NoteRepository } from '../../src/main/repository/NoteRepository.js';

const baseInput = {
  id: '00000000-0000-0000-0000-000000000001',
  rawText: 'sync 본문',
  createdAt: '2026-05-09T00:00:00Z',
  updatedAt: '2026-05-10T00:00:00Z',
  aiTitle: 'sync 제목',
  aiSummary: 'sync 요약',
  titleEditedByUser: false,
  summaryEditedByUser: false,
  aiProvider: 'p',
  aiGeneratedAt: '2026-05-10T00:00:00Z',
  userIntent: null,
  intentPromptedAt: null,
  tags: [{ name: '동기', source: 'user' as const }],
  status: 'active' as const,
  statusChangedAt: null,
  moveReason: null,
  dueDate: null,
  dueDateEditedByUser: false
};

describe('NoteRepository.upsertFromSync', () => {
  let db: Database.Database;
  let repo: NoteRepository;

  beforeEach(() => {
    db = new Database(':memory:');
    db.pragma('foreign_keys = ON');
    runMigrations(db);
    repo = new NoteRepository(db);
  });

  afterEach(() => { db.close(); });

  it('id 없음 → INSERT (status=inserted) + capture revision + tags FTS sync', () => {
    const r = repo.upsertFromSync(baseInput);
    expect(r.status).toBe('inserted');
    expect(r.id).toBe(baseInput.id);
    const note = repo.findById(baseInput.id);
    expect(note?.rawText).toBe('sync 본문');
    expect(note?.aiTitle).toBe('sync 제목');
    const revs = repo.listRevisions(baseInput.id);
    expect(revs).toHaveLength(1);
    expect(revs[0]!.editedBy).toBe('capture');
    const fts = db.prepare(`SELECT tags FROM notes_fts WHERE note_id=?`).get(baseInput.id) as { tags: string };
    expect(fts.tags).toBe('동기');
  });

  it('id 있음 + raw_text 동일 + source 더 최신 → metadata 갱신 (status=updated)', () => {
    const created = repo.create({ rawText: 'sync 본문' }, new Date('2026-05-09T00:00:00Z'));
    repo.updateAiResult(created.id, { title: '옛 제목', summary: '옛 요약', tags: ['old'], provider: 'p' });
    db.prepare(`UPDATE notes SET updated_at=? WHERE id=?`).run('2026-05-08T00:00:00Z', created.id);
    const r = repo.upsertFromSync({ ...baseInput, id: created.id });
    expect(r.status).toBe('updated');
    const note = repo.findById(created.id);
    expect(note?.aiTitle).toBe('sync 제목');
    expect(note?.tags.map((t) => t.name)).toEqual(['동기']);
    const fts = db.prepare(`SELECT tags FROM notes_fts WHERE note_id=?`).get(created.id) as { tags: string };
    expect(fts.tags).toBe('동기');
  });

  it('id 있음 + raw_text 동일 + source 더 옛 → skip (status=skipped)', () => {
    const created = repo.create({ rawText: 'sync 본문' });
    repo.updateAiResult(created.id, { title: '신선한 제목', summary: 'fresh', tags: ['x'], provider: 'p' });
    db.prepare(`UPDATE notes SET updated_at=? WHERE id=?`).run('2026-05-12T00:00:00Z', created.id);
    const r = repo.upsertFromSync({ ...baseInput, id: created.id, updatedAt: '2026-05-10T00:00:00Z' });
    expect(r.status).toBe('skipped');
    const note = repo.findById(created.id);
    expect(note?.aiTitle).toBe('신선한 제목');
  });

  it('id 있음 + raw_text 다름 + source 더 최신 → updateRawText (status=updated) + new user revision', () => {
    const created = repo.create({ rawText: 'old text' }, new Date('2026-05-09T00:00:00Z'));
    db.prepare(`UPDATE notes SET updated_at=? WHERE id=?`).run('2026-05-08T00:00:00Z', created.id);
    const r = repo.upsertFromSync({ ...baseInput, id: created.id, rawText: 'new sync text' });
    expect(r.status).toBe('updated');
    const note = repo.findById(created.id);
    expect(note?.rawText).toBe('new sync text');
    const revs = repo.listRevisions(created.id);
    expect(revs).toHaveLength(2); // capture (old) + user (new)
    expect(revs[0]!.editedBy).toBe('user');
    expect(revs[0]!.rawText).toBe('new sync text');
  });

  it('id 있음 + raw_text 다름 + source 더 옛 → skip', () => {
    const created = repo.create({ rawText: 'local fresh' });
    db.prepare(`UPDATE notes SET updated_at=? WHERE id=?`).run('2026-05-15T00:00:00Z', created.id);
    const r = repo.upsertFromSync({ ...baseInput, id: created.id, rawText: 'old sync text', updatedAt: '2026-05-10T00:00:00Z' });
    expect(r.status).toBe('skipped');
    const note = repo.findById(created.id);
    expect(note?.rawText).toBe('local fresh');
  });
});
