import type { Pool } from 'pg';
import { prisma } from '../config/database.js';

export interface CarteraRow {
  id: string;
  supervisorUserId: string | null;
  auxiliarUserId: string | null;
  parentId: string | null;
  nombre: string;
  descripcion: string | null;
  createdAt: string;
  entidadesCount?: number;
  subcarterasCount?: number;
}

const BASE_SELECT = `
  SELECT c.id, c.supervisor_user_id AS "supervisorUserId",
    c.auxiliar_user_id AS "auxiliarUserId", c.parent_id AS "parentId",
    c.nombre, c.descripcion, c.created_at AS "createdAt",
    (SELECT count(*) FROM cartera_entidades ce WHERE ce.cartera_id = c.id)::int AS "entidadesCount",
    (SELECT count(*) FROM carteras sc WHERE sc.parent_id = c.id)::int AS "subcarterasCount"
  FROM carteras c
`;

/**
 * List top-level carteras (parent_id IS NULL).
 * If supervisorUserId is provided, filter by that supervisor.
 */
export async function listCarteras(pool: Pool, supervisorUserId?: string): Promise<CarteraRow[]> {
  const conditions = ['c.parent_id IS NULL'];
  const params: unknown[] = [];
  if (supervisorUserId) {
    params.push(supervisorUserId);
    conditions.push(`c.supervisor_user_id = $${params.length}`);
  }
  const { rows } = await pool.query(
    `${BASE_SELECT} WHERE ${conditions.join(' AND ')} ORDER BY c.created_at DESC`,
    params,
  );
  return rows;
}

/**
 * List subcarteras of a parent cartera.
 */
export async function listSubcarteras(pool: Pool, parentId: string): Promise<CarteraRow[]> {
  const { rows } = await pool.query(
    `${BASE_SELECT} WHERE c.parent_id = $1 ORDER BY c.nombre`,
    [parentId],
  );
  return rows;
}

export async function getCarteraById(pool: Pool, id: string): Promise<CarteraRow | null> {
  const { rows } = await pool.query(`${BASE_SELECT} WHERE c.id = $1`, [id]);
  return rows[0] ?? null;
}

export async function createCartera(pool: Pool, data: {
  supervisorUserId: string;
  nombre: string;
  descripcion?: string;
}): Promise<CarteraRow> {
  const { rows: [row] } = await pool.query(`
    INSERT INTO carteras (supervisor_user_id, nombre, descripcion)
    VALUES ($1, $2, $3) RETURNING id
  `, [data.supervisorUserId, data.nombre, data.descripcion ?? null]);
  return (await getCarteraById(pool, row.id))!;
}

/**
 * Create a subcartera within a parent cartera, assigned to an auxiliar.
 */
export async function createSubcartera(pool: Pool, data: {
  parentId: string;
  auxiliarUserId: string;
  nombre: string;
  descripcion?: string;
}): Promise<CarteraRow> {
  const { rows: [row] } = await pool.query(`
    INSERT INTO carteras (parent_id, auxiliar_user_id, nombre, descripcion)
    VALUES ($1, $2, $3, $4) RETURNING id
  `, [data.parentId, data.auxiliarUserId, data.nombre, data.descripcion ?? null]);
  return (await getCarteraById(pool, row.id))!;
}

export async function updateCartera(pool: Pool, id: string, data: {
  nombre?: string;
  descripcion?: string;
  supervisorUserId?: string;
}): Promise<CarteraRow | null> {
  const existing = await getCarteraById(pool, id);
  if (!existing) return null;
  const sets: string[] = [];
  const vals: unknown[] = [];
  let idx = 1;
  if (data.nombre !== undefined) { sets.push(`nombre = $${idx}`); vals.push(data.nombre); idx++; }
  if (data.descripcion !== undefined) { sets.push(`descripcion = $${idx}`); vals.push(data.descripcion); idx++; }
  if (data.supervisorUserId !== undefined) { sets.push(`supervisor_user_id = $${idx}`); vals.push(data.supervisorUserId); idx++; }
  if (sets.length === 0) return existing;
  vals.push(id);
  await pool.query(`UPDATE carteras SET ${sets.join(', ')} WHERE id = $${idx}`, vals);
  return (await getCarteraById(pool, id))!;
}

export async function deleteCartera(pool: Pool, id: string): Promise<boolean> {
  const { rowCount } = await pool.query('DELETE FROM carteras WHERE id = $1', [id]);
  return (rowCount ?? 0) > 0;
}

// Entidades in cartera
export async function addEntidadToCartera(pool: Pool, carteraId: string, entidadId: string): Promise<void> {
  // Si es subcartera, validar que la entidad pertenezca a la cartera padre
  const cartera = await getCarteraById(pool, carteraId);
  if (cartera?.parentId) {
    const { rows } = await pool.query(
      'SELECT 1 FROM cartera_entidades WHERE cartera_id = $1 AND entidad_id = $2',
      [cartera.parentId, entidadId],
    );
    if (rows.length === 0) {
      throw new Error('La entidad no pertenece a la cartera padre de esta subcartera');
    }
  }
  await pool.query('INSERT INTO cartera_entidades (cartera_id, entidad_id) VALUES ($1, $2) ON CONFLICT DO NOTHING', [carteraId, entidadId]);
}

export async function removeEntidadFromCartera(pool: Pool, carteraId: string, entidadId: string): Promise<void> {
  await pool.query('DELETE FROM cartera_entidades WHERE cartera_id = $1 AND entidad_id = $2', [carteraId, entidadId]);
}

export async function getCarteraEntidades(pool: Pool, carteraId: string): Promise<string[]> {
  const { rows } = await pool.query('SELECT entidad_id AS "entidadId" FROM cartera_entidades WHERE cartera_id = $1', [carteraId]);
  return rows.map(r => r.entidadId);
}

// Auxiliares assigned to a supervisor
export async function getAuxiliaresDelSupervisor(pool: Pool, supervisorUserId: string): Promise<Array<{ auxiliarUserId: string }>> {
  const { rows } = await pool.query(
    'SELECT auxiliar_user_id AS "auxiliarUserId" FROM auxiliar_supervisores WHERE supervisor_user_id = $1',
    [supervisorUserId],
  );
  return rows;
}

// Legacy auxiliares in cartera (backward compat)
export async function addAuxiliarToCartera(pool: Pool, carteraId: string, auxiliarUserId: string): Promise<void> {
  await pool.query('INSERT INTO cartera_auxiliares (cartera_id, auxiliar_user_id) VALUES ($1, $2) ON CONFLICT DO NOTHING', [carteraId, auxiliarUserId]);
}

export async function removeAuxiliarFromCartera(pool: Pool, carteraId: string, auxiliarUserId: string): Promise<void> {
  await pool.query('DELETE FROM cartera_auxiliares WHERE cartera_id = $1 AND auxiliar_user_id = $2', [carteraId, auxiliarUserId]);
}

export async function getCarteraAuxiliares(pool: Pool, carteraId: string): Promise<string[]> {
  const { rows } = await pool.query('SELECT auxiliar_user_id AS "auxiliarUserId" FROM cartera_auxiliares WHERE cartera_id = $1', [carteraId]);
  return rows.map(r => r.auxiliarUserId);
}

// Supervisors list (for the invite form dropdown)
export async function getSupervisores(pool: Pool, tenantId: string): Promise<Array<{ userId: string; nombre: string; email: string }>> {
  // Query tenant_memberships joined with users for supervisor role (rolId=9)
  const memberships = await prisma.tenantMembership.findMany({
    where: { tenantId, rolId: 9, active: true },
    include: { user: { select: { id: true, nombre: true, email: true } } },
  });
  return memberships.map(m => ({
    userId: m.user.id,
    nombre: m.user.nombre,
    email: m.user.email,
  }));
}
