import Database, { type Database as SqliteDatabase } from 'bun:sqlite';
import { initializeDatabase } from '../../src/db';
import { setDb } from '../../src/db/locator';
import { toIsoSql } from './dates';

// Servicios opcionales para inyección de DB en tests.
// Importamos con nombres existentes en la base de código para respetar convenciones.
import { TaskService } from '../../src/tasks/service';
import { CommandService } from '../../src/services/command';
import { ResponseQueue } from '../../src/services/response-queue';
import { IdentityService } from '../../src/services/identity';
import { GroupSyncService } from '../../src/services/group-sync';
import { RemindersService } from '../../src/services/reminders';
import { AllowedGroups } from '../../src/services/allowed-groups';

/**
 * Crea una DB en memoria y aplica initializeDatabase() con todas las migraciones.
 */
export function makeMemDb(): SqliteDatabase {
  const memdb = new Database(':memory:');
  initializeDatabase(memdb);
  return memdb;
}

/**
 * Inyecta la instancia de DB en los servicios que la exponen como propiedad estática.
 * Pensado para usarse en beforeAll/beforeEach de tests que usan estos servicios.
 */
export function injectAllServices(db: SqliteDatabase): void {
  setDb(db);
}

/**
 * Restablece estado global/cachés en servicios entre tests.
 * Best-effort: solo llama si existen los métodos.
 */
export function resetServices(): void {
  try { (IdentityService as any).clearCache?.(); } catch {}
  try { (GroupSyncService as any).clearCaches?.(); } catch {}
  try { (CommandService as any).resetForTests?.(); } catch {}
  try { (ResponseQueue as any).resetForTests?.(); } catch {}
  try { (RemindersService as any).resetForTests?.(); } catch {}
}

/**
 * Marca como 'allowed' los groupIds indicados en la DB provista.
 */
/**
 * Sembrar un grupo en la DB rellenando columnas NOT NULL sin valor por defecto.
 * Usa PRAGMA table_info para adaptarse automáticamente a la forma actual de la tabla.
 */
export function seedGroup(db: SqliteDatabase, groupId: string): void {
  const cols = db.query(`PRAGMA table_info(groups)`).all() as any[];
  const values: Record<string, any> = {};
  const nowIso = toIsoSql(new Date());

  for (const c of cols) {
    const name = String(c.name);
    const type = String(c.type || '').toUpperCase();
    const notnull = Number(c.notnull || 0) === 1;
    const hasDefault = c.dflt_value != null;

    if (name === 'id') {
      values[name] = groupId;
      continue;
    }

    // Preconfigurar algunos alias comunes
    if (name === 'name' || name === 'title' || name === 'subject') {
      values[name] = 'Test Group';
      continue;
    }
    if (name === 'created_by') {
      values[name] = 'tester';
      continue;
    }
    if (name.endsWith('_at')) {
      values[name] = nowIso;
      continue;
    }
    if (name === 'is_active' || name === 'active') {
      values[name] = 1;
      continue;
    }

    // Para columnas NOT NULL sin valor por defecto, asignar valores genéricos
    if (notnull && !hasDefault) {
      if (type.includes('INT')) values[name] = 1;
      else if (type.includes('REAL')) values[name] = 0;
      else values[name] = 'N/A';
    }
  }

  // Asegurar que id esté siempre
  if (!('id' in values)) values['id'] = groupId;

  const colsList = Object.keys(values);
  const placeholders = colsList.map(() => '?').join(', ');
  const sql = `INSERT OR REPLACE INTO groups (${colsList.join(', ')}) VALUES (${placeholders})`;
  db.prepare(sql).run(...colsList.map(k => values[k]));
}

export function seedAllowed(db: SqliteDatabase, groupIds: string[]): void {
  for (const gid of groupIds) {
    const g = String(gid || '').trim();
    if (!g) continue;
    try { AllowedGroups.setStatus(g, 'allowed'); } catch {}
  }
}
