import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { createMigratedTestDb } from '@/tests/helpers/db';
import type { SqliteDatabase } from '@/lib/db/sqlite';
import { UserRepository } from '@/repositories/UserRepository';
import { ProjectRepository } from '@/repositories/ProjectRepository';
import { ProjectMemberRepository } from '@/repositories/ProjectMemberRepository';
import { TodoRepository } from '@/repositories/TodoRepository';

describe('TodoRepository', () => {
  let db: SqliteDatabase;
  let repo: TodoRepository;
  let projectId: number;
  let userId: number;
  let columnId: number;

  beforeEach(() => {
    db = createMigratedTestDb();
    repo = new TodoRepository(db);
    userId = new UserRepository(db).create({
      name: 'U',
      email: 'u@example.com',
      passwordHash: 'h',
    }).id;
    projectId = new ProjectRepository(db).create({
      name: 'P',
      ownerId: userId,
    }).id;
    new ProjectMemberRepository(db).add(projectId, userId, 'admin');
    columnId = repo.createColumn({ projectId, name: 'Todo', orderIndex: 0 }).id;
  });

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

  it('creates and lists columns ordered by order_index', () => {
    repo.createColumn({ projectId, name: 'Done', orderIndex: 2 });
    repo.createColumn({ projectId, name: 'Doing', orderIndex: 1 });
    const cols = repo.findColumns(projectId);
    expect(cols.map((c) => c.name)).toEqual(['Todo', 'Doing', 'Done']);
  });

  it('updates and deletes a column', () => {
    expect(repo.updateColumn(columnId, { name: 'Renamed' })?.name).toBe(
      'Renamed'
    );
    repo.deleteColumn(columnId);
    expect(repo.findColumnById(columnId)).toBeNull();
  });

  it('creates an item and lists by column order then item order', () => {
    repo.createItem({
      projectId,
      columnId,
      title: 'second',
      creatorId: userId,
      orderIndex: 1,
    });
    repo.createItem({
      projectId,
      columnId,
      title: 'first',
      creatorId: userId,
      orderIndex: 0,
    });
    const items = repo.findItemsByProject(projectId);
    expect(items.map((i) => i.title)).toEqual(['first', 'second']);
  });

  it('excludes soft-deleted items', () => {
    const item = repo.createItem({
      projectId,
      columnId,
      title: 'x',
      creatorId: userId,
      orderIndex: 0,
    });
    repo.deleteItem(item.id);
    expect(repo.findItemById(item.id)).toBeNull();
    expect(repo.findItemsByProject(projectId)).toHaveLength(0);
  });

  it('maxItemOrderIndex returns -1 for empty column, else max', () => {
    expect(repo.maxItemOrderIndex(columnId)).toBe(-1);
    repo.createItem({
      projectId,
      columnId,
      title: 'a',
      creatorId: userId,
      orderIndex: 5,
    });
    expect(repo.maxItemOrderIndex(columnId)).toBe(5);
  });

  it('updates item fields including column move', () => {
    const col2 = repo.createColumn({
      projectId,
      name: 'Done',
      orderIndex: 1,
    }).id;
    const item = repo.createItem({
      projectId,
      columnId,
      title: 'x',
      creatorId: userId,
      orderIndex: 0,
    });
    const updated = repo.updateItem(item.id, {
      title: 'renamed',
      columnId: col2,
      orderIndex: 0,
      completedAt: '2026-01-01T00:00:00.000Z',
    });
    expect(updated?.columnId).toBe(col2);
    expect(updated?.title).toBe('renamed');
    expect(updated?.completedAt).toBeTruthy();
  });

  it('persists startDate and tags on create', () => {
    const item = repo.createItem({
      projectId,
      columnId,
      title: 't',
      creatorId: userId,
      orderIndex: 0,
      startDate: '2026-07-01',
      tags: 'frontend,urgent',
    });
    const found = repo.findItemById(item.id);
    expect(found?.startDate).toBe('2026-07-01');
    expect(found?.tags).toBe('frontend,urgent');
  });

  it('updates startDate and tags', () => {
    const item = repo.createItem({
      projectId,
      columnId,
      title: 't',
      creatorId: userId,
      orderIndex: 0,
    });
    const updated = repo.updateItem(item.id, {
      startDate: '2026-08-01',
      tags: 'backend',
    });
    expect(updated?.startDate).toBe('2026-08-01');
    expect(updated?.tags).toBe('backend');
  });

  it('defaults startDate and tags to null when omitted', () => {
    const item = repo.createItem({
      projectId,
      columnId,
      title: 't',
      creatorId: userId,
      orderIndex: 0,
    });
    expect(item.startDate).toBeNull();
    expect(item.tags).toBeNull();
  });

  it('isolates items by project', () => {
    const p2 = new ProjectRepository(db).create({
      name: 'P2',
      ownerId: userId,
    }).id;
    const c2 = repo.createColumn({
      projectId: p2,
      name: 'X',
      orderIndex: 0,
    }).id;
    repo.createItem({
      projectId,
      columnId,
      title: 'mine',
      creatorId: userId,
      orderIndex: 0,
    });
    repo.createItem({
      projectId: p2,
      columnId: c2,
      title: 'theirs',
      creatorId: userId,
      orderIndex: 0,
    });
    expect(repo.findItemsByProject(projectId)).toHaveLength(1);
    expect(repo.findItemsByProject(p2)).toHaveLength(1);
  });
});
