const path = require('path');
const fs = require('fs');
const { DatabaseSync } = require('node:sqlite');
const { NIVELES, buildSeedNodos, DEPARTAMENTOS_ENCUESTA, PLANTILLA_ENCUESTA } = require('./organizacionDefaults');

const DATA_DIR = path.join(__dirname, '..', 'data');
const DB_PATH = path.join(DATA_DIR, 'encuestas.db');

let db;

function slugify(text) {
  return String(text || '')
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-|-$/g, '');
}

function initDatabase() {
  if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR, { recursive: true });
  db = new DatabaseSync(DB_PATH);
  db.exec('PRAGMA journal_mode = WAL');
  db.exec('PRAGMA foreign_keys = ON');

  db.exec(`
    CREATE TABLE IF NOT EXISTS organizacion_nodos (
      id TEXT PRIMARY KEY,
      nombre TEXT NOT NULL,
      nivel TEXT NOT NULL,
      descripcion TEXT,
      catalogo_id TEXT,
      padre_id TEXT,
      sub_id TEXT,
      grupo_gerencial TEXT,
      orden INTEGER DEFAULT 0,
      activo INTEGER DEFAULT 1
    );

    CREATE TABLE IF NOT EXISTS encuestas (
      id TEXT PRIMARY KEY,
      titulo TEXT NOT NULL,
      departamento_id TEXT NOT NULL,
      descripcion TEXT,
      preguntas TEXT NOT NULL,
      activa INTEGER DEFAULT 1,
      creado_en TEXT DEFAULT (datetime('now')),
      FOREIGN KEY (departamento_id) REFERENCES organizacion_nodos(id)
    );

    CREATE TABLE IF NOT EXISTS respuestas (
      id TEXT PRIMARY KEY,
      encuesta_id TEXT NOT NULL,
      departamento_id TEXT NOT NULL,
      datos TEXT NOT NULL,
      respondido_por TEXT,
      creado_en TEXT DEFAULT (datetime('now')),
      FOREIGN KEY (encuesta_id) REFERENCES encuestas(id),
      FOREIGN KEY (departamento_id) REFERENCES organizacion_nodos(id)
    );
  `);

  seedOrganizacion();
  seedEncuestasDefault();
  return db;
}

function seedOrganizacion() {
  const count = db.prepare('SELECT COUNT(*) as c FROM organizacion_nodos').get().c;
  if (count > 0) return;

  const insert = db.prepare(`
    INSERT INTO organizacion_nodos (id, nombre, nivel, descripcion, catalogo_id, padre_id, sub_id, grupo_gerencial, orden)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
  `);
  for (const n of buildSeedNodos()) {
    insert.run(n.id, n.nombre, n.nivel, n.descripcion, n.catalogo_id, n.padre_id, n.sub_id, n.grupo_gerencial, n.orden);
  }
}

function seedEncuestasDefault() {
  const count = db.prepare('SELECT COUNT(*) as c FROM encuestas').get().c;
  if (count > 0) return;

  const insert = db.prepare(`
    INSERT INTO encuestas (id, titulo, departamento_id, descripcion, preguntas, activa)
    VALUES (?, ?, ?, ?, ?, 1)
  `);

  const titulos = {
    'gerencia-de-tecnologia-de-la-informacion': 'Encuesta de Satisfacción — Tecnología de la Información',
    'gerencia-de-procura': 'Encuesta de Satisfacción — Procura',
    'gerencia-de-logistica-y-transporte': 'Encuesta de Satisfacción — Logística y Transporte',
    'gerencia-de-sistemas-de-gestion': 'Encuesta de Satisfacción — Gestión de la Calidad',
    'direccion-de-operaciones': 'Encuesta de Satisfacción — Operaciones',
  };

  for (const deptId of DEPARTAMENTOS_ENCUESTA) {
    const nodo = db.prepare('SELECT * FROM organizacion_nodos WHERE id = ?').get(deptId);
    if (!nodo) continue;
    insert.run(
      `encuesta-${deptId}`,
      titulos[deptId] || `Encuesta de Satisfacción — ${nodo.nombre}`,
      deptId,
      `Evaluación de satisfacción del cliente para ${nodo.nombre}`,
      JSON.stringify(PLANTILLA_ENCUESTA)
    );
  }
}

function rowToNodo(row) {
  return {
    id: row.id,
    nombre: row.nombre,
    nivel: row.nivel,
    descripcion: row.descripcion,
    desc: row.descripcion,
    catalogoId: row.catalogo_id,
    catalogo_id: row.catalogo_id,
    padreId: row.padre_id,
    padre_id: row.padre_id,
    subId: row.sub_id,
    sub_id: row.sub_id,
    grupoGerencial: row.grupo_gerencial,
    grupo_gerencial: row.grupo_gerencial,
    orden: row.orden,
    activo: row.activo === 1,
  };
}

function getOrganigramaCompleto() {
  const rows = db.prepare('SELECT * FROM organizacion_nodos WHERE activo = 1 ORDER BY orden ASC, nombre ASC').all();
  return { niveles: NIVELES, nodos: rows.map(rowToNodo) };
}

function uniqueId(baseId) {
  let id = baseId;
  let n = 2;
  while (db.prepare('SELECT id FROM organizacion_nodos WHERE id = ?').get(id)) {
    id = `${baseId}-${n++}`;
  }
  return id;
}

function createNodo(data) {
  const nombre = String(data.nombre || '').trim();
  if (!nombre) throw new Error('El nombre es obligatorio');
  const nivel = data.nivel;
  if (!nivel) throw new Error('El nivel es obligatorio');

  const baseId = slugify(data.id || nombre);
  const id = uniqueId(baseId);
  const maxOrden = db.prepare('SELECT MAX(orden) as m FROM organizacion_nodos WHERE nivel = ?').get(nivel).m || 0;

  db.prepare(
    `INSERT INTO organizacion_nodos (id, nombre, nivel, descripcion, catalogo_id, padre_id, sub_id, grupo_gerencial, orden)
     VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
  ).run(
    id, nombre, nivel,
    data.descripcion || data.desc || null,
    data.catalogo_id || data.catalogoId || null,
    data.padre_id || data.padreId || null,
    data.sub_id || data.subId || null,
    data.grupo_gerencial || data.grupoGerencial || null,
    maxOrden + 1
  );

  return rowToNodo(db.prepare('SELECT * FROM organizacion_nodos WHERE id = ?').get(id));
}

function updateNodo(id, data) {
  const existing = db.prepare('SELECT * FROM organizacion_nodos WHERE id = ?').get(id);
  if (!existing) throw new Error('Unidad organizativa no encontrada');

  const nombre = data.nombre !== undefined ? String(data.nombre).trim() : existing.nombre;
  if (!nombre) throw new Error('El nombre es obligatorio');

  db.prepare(
    `UPDATE organizacion_nodos SET
      nombre = ?, nivel = ?, descripcion = ?, catalogo_id = ?, padre_id = ?, sub_id = ?, grupo_gerencial = ?
     WHERE id = ?`
  ).run(
    nombre,
    data.nivel || existing.nivel,
    data.descripcion !== undefined ? data.descripcion : data.desc !== undefined ? data.desc : existing.descripcion,
    data.catalogo_id !== undefined ? data.catalogo_id : data.catalogoId !== undefined ? data.catalogoId : existing.catalogo_id,
    data.padre_id !== undefined ? data.padre_id : data.padreId !== undefined ? data.padreId : existing.padre_id,
    data.sub_id !== undefined ? data.sub_id : data.subId !== undefined ? data.subId : existing.sub_id,
    data.grupo_gerencial !== undefined ? data.grupo_gerencial : data.grupoGerencial !== undefined ? data.grupoGerencial : existing.grupo_gerencial,
    id
  );

  return rowToNodo(db.prepare('SELECT * FROM organizacion_nodos WHERE id = ?').get(id));
}

function deleteNodo(id) {
  const existing = db.prepare('SELECT * FROM organizacion_nodos WHERE id = ?').get(id);
  if (!existing) throw new Error('Unidad organizativa no encontrada');

  const hijos = db.prepare('SELECT COUNT(*) as c FROM organizacion_nodos WHERE padre_id = ? AND activo = 1').get(id).c;
  if (hijos > 0) {
    throw new Error(`No se puede eliminar: tiene ${hijos} unidad(es) dependiente(s).`);
  }

  const encuestas = db.prepare('SELECT COUNT(*) as c FROM encuestas WHERE departamento_id = ?').get(id).c;
  if (encuestas > 0) {
    throw new Error(`No se puede eliminar: tiene ${encuestas} encuesta(s) asociada(s).`);
  }

  db.prepare('UPDATE organizacion_nodos SET activo = 0 WHERE id = ?').run(id);
  return { deleted: id };
}

function listDepartamentosOptions() {
  return db
    .prepare('SELECT id, nombre, nivel FROM organizacion_nodos WHERE activo = 1 ORDER BY nivel, orden, nombre')
    .all()
    .map((r) => ({ id: r.id, nombre: r.nombre, nivel: r.nivel }));
}

function getDb() {
  return db;
}

module.exports = {
  initDatabase,
  getOrganigramaCompleto,
  createNodo,
  updateNodo,
  deleteNodo,
  listDepartamentosOptions,
  slugify,
  getDb,
  PLANTILLA_ENCUESTA,
};
