import { describe, it, expect, beforeAll, beforeEach } from 'bun:test';
import { Database } from 'bun:sqlite';
import { initializeDatabase, ensureUserExists } from '../../../src/db';
import { TaskService } from '../../../src/tasks/service';
import { CommandService } from '../../../src/services/command';
import { setDb } from '../../../src/db/locator';

describe('CommandService - t tomar y t soltar', () => {
  let memdb: Database;

  beforeAll(() => {
    memdb = new Database(':memory:');
    initializeDatabase(memdb);
    setDb(memdb);
  });

  beforeEach(() => {
    memdb.exec(`
      DELETE FROM task_assignments;
      DELETE FROM tasks;
      DELETE FROM users;
    `);
  });

  function createTask(description: string, creator: string, due?: string | null, assignees: string[] = []): number {
    const createdBy = ensureUserExists(creator, memdb)!;
    const taskId = TaskService.createTask(
      {
        description,
        due_date: due ?? null,
        group_id: null,
        created_by: createdBy,
      },
      assignees.map(uid => ({ user_id: ensureUserExists(uid, memdb)!, assigned_by: createdBy }))
    );
    return taskId;
  }

  function getDisplayCode(id: number): number {
    const row = memdb.prepare('SELECT display_code FROM tasks WHERE id = ?').get(id) as any;
    return Number(row?.display_code || 0);
  }

  function code4(n: number): string {
    return '`' + String(n).padStart(4, '0') + '`';
  }

  const ctx = (sender: string, message: string) => ({
    sender,
    groupId: '', // DM o vacío; sin relevancia para tomar/soltar
    message,
    mentions: [] as string[],
  });

  it('tomar: uso inválido (sin id)', async () => {
    const res = await CommandService.handle(ctx('111', 't tomar'));
    expect(res).toHaveLength(1);
    expect(res[0].recipient).toBe('111');
    expect(res[0].message).toContain('Uso: `t tomar 26`');
  });

  it('tomar: not_found', async () => {
    const res = await CommandService.handle(ctx('111', 't tomar 99999'));
    expect(res[0].message).toContain('no encontrada');
  });

  it('tomar: happy y luego already', async () => {
    const taskId = createTask('Desc tomar', '999', '2025-09-12');
    const dc = getDisplayCode(taskId);
    const r1 = await CommandService.handle(ctx('111', `t tomar ${dc}`));
    expect(r1[0].message).toContain('Has tomado');
    expect(r1[0].message).toContain(code4(dc));
    expect(r1[0].message).toContain('Desc tomar');
    expect(r1[0].message).toContain('📅'); // formato dd/MM

    const r2 = await CommandService.handle(ctx('111', `t tomar ${dc}`));
    expect(r2[0].message).toContain('ya la tenías');
  });

  it('tomar: completed', async () => {
    const taskId = createTask('Tarea completa', '111', '2025-10-10', ['111']);
    const comp = TaskService.completeTask(taskId, '111');
    expect(comp.status).toBe('updated');

    const dc = getDisplayCode(taskId);
    const res = await CommandService.handle(ctx('222', `t tomar ${dc}`));
    expect(res[0].message).toContain('no encontrada');
  });

  it('soltar: uso inválido (sin id)', async () => {
    const res = await CommandService.handle(ctx('111', 't soltar'));
    expect(res[0].message).toContain('Uso: `t soltar 26`');
  });

  it('soltar: not_found', async () => {
    const res = await CommandService.handle(ctx('111', 't soltar 123456'));
    expect(res[0].message).toContain('no encontrada');
  });

  it('soltar: personal única asignación → denegado', async () => {
    const taskId = createTask('Desc soltar', '999', '2025-09-12', ['111']);
    const dc = getDisplayCode(taskId);
    const res = await CommandService.handle(ctx('111', `t soltar ${dc}`));
    expect(res[0].message).toContain('No puedes soltar una tarea personal. Márcala como completada para eliminarla');
  });

  it('soltar: not_assigned muestra mensaje informativo', async () => {
    const taskId = createTask('Nunca asignada a 111', '999', null, ['222']);
    const dc = getDisplayCode(taskId);
    const res = await CommandService.handle(ctx('111', `t soltar ${dc}`));
    expect(res[0].message).toContain('no la tenías asignada');
  });

  it('soltar: completed', async () => {
    const taskId = createTask('Completa y soltar', '111', null, ['111']);
    const comp = TaskService.completeTask(taskId, '111');
    expect(comp.status).toBe('updated');

    const dc = getDisplayCode(taskId);
    const res = await CommandService.handle(ctx('111', `t soltar ${dc}`));
    expect(res[0].message).toContain('no encontrada');
  });
});
