import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { mkdtempSync, rmSync } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
import { Repository } from './repository.js';

describe('Repository dashboard widgets', () => {
  let tmpDir: string;
  let repo: Repository;

  beforeEach(() => {
    tmpDir = mkdtempSync(join(tmpdir(), 'dashboard-repo-test-'));
    repo = new Repository(join(tmpDir, 'test.db'));
  });

  afterEach(() => {
    rmSync(tmpDir, { recursive: true, force: true });
  });

  it('creates and lists widgets scoped to user_id', async () => {
    const a = await repo.createDashboardWidget({ userId: 'u1', slug: 'memo', title: 'Memo', content: 'hello' });
    await repo.createDashboardWidget({ userId: 'u2', slug: 'memo', title: 'Memo2', content: 'other-user' });
    const widgets = await repo.listDashboardWidgets('u1');
    expect(widgets).toHaveLength(1);
    expect(widgets[0]!.id).toBe(a.id);
    expect(widgets[0]!.slug).toBe('memo');
    expect(widgets[0]!.title).toBe('Memo');
    expect(widgets[0]!.markdownContent).toBe('hello');
  });

  it('rejects duplicate slug for same user', async () => {
    await repo.createDashboardWidget({ userId: 'u1', slug: 'memo', title: 'a', content: '' });
    await expect(
      repo.createDashboardWidget({ userId: 'u1', slug: 'memo', title: 'b', content: '' })
    ).rejects.toThrow();
  });

  it('updates content and bumps updated_at', async () => {
    const w = await repo.createDashboardWidget({ userId: 'u1', slug: 's', title: 't', content: 'old' });
    const originalUpdatedAt = w.updatedAt;
    await new Promise(r => setTimeout(r, 1100)); // datetime('now') has 1s precision
    const updated = await repo.updateDashboardWidget(w.id, 'u1', { content: 'new' });
    expect(updated.markdownContent).toBe('new');
    expect(updated.updatedAt).not.toBe(originalUpdatedAt);
  });

  it('updateDashboardWidget rejects updates from other users', async () => {
    const w = await repo.createDashboardWidget({ userId: 'u1', slug: 's', title: 't', content: 'orig' });
    await expect(
      repo.updateDashboardWidget(w.id, 'u2', { content: 'hack' })
    ).rejects.toThrow(/not found/i);
    const list = await repo.listDashboardWidgets('u1');
    expect(list[0]!.markdownContent).toBe('orig');
  });

  it('upserts by (user_id, slug): returns existing if slug already exists', async () => {
    const created = await repo.upsertDashboardWidgetBySlug({ userId: 'u1', slug: 'news', title: 'News', content: 'a' });
    const second = await repo.upsertDashboardWidgetBySlug({ userId: 'u1', slug: 'news', content: 'b' });
    expect(second.id).toBe(created.id);
    expect(second.markdownContent).toBe('b');
  });

  it('deletes widget by id', async () => {
    const w = await repo.createDashboardWidget({ userId: 'u1', slug: 's', title: 't', content: '' });
    await repo.deleteDashboardWidget(w.id, 'u1');
    const list = await repo.listDashboardWidgets('u1');
    expect(list).toHaveLength(0);
  });

  it('reorders widgets by id list', async () => {
    const a = await repo.createDashboardWidget({ userId: 'u1', slug: 'a', title: 'A', content: '' });
    const b = await repo.createDashboardWidget({ userId: 'u1', slug: 'b', title: 'B', content: '' });
    const c = await repo.createDashboardWidget({ userId: 'u1', slug: 'c', title: 'C', content: '' });
    await repo.reorderDashboardWidgets('u1', [c.id, a.id, b.id]);
    const list = await repo.listDashboardWidgets('u1');
    expect(list.map(w => w.slug)).toEqual(['c', 'a', 'b']);
  });

  it('reorder rejects ids from other users (silent skip + leave order intact)', async () => {
    const u1a = await repo.createDashboardWidget({ userId: 'u1', slug: 'a', title: 'A', content: '' });
    const u2x = await repo.createDashboardWidget({ userId: 'u2', slug: 'x', title: 'X', content: '' });
    await repo.reorderDashboardWidgets('u1', [u2x.id, u1a.id]);
    const list = await repo.listDashboardWidgets('u1');
    expect(list.map(w => w.id)).toEqual([u1a.id]); // u2x should not appear
  });
});
