"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.attachRoles = attachRoles;
exports.createUser = createUser;
exports.getUser = getUser;
exports.getUserByExternalId = getUserByExternalId;
exports.getUserByEmail = getUserByEmail;
exports.updateUser = updateUser;
exports.deleteUser = deleteUser;
exports.listUsers = listUsers;
const bcryptjs_1 = __importDefault(require("bcryptjs"));
const db_1 = require("../../lib/db");
const sql_1 = require("./sql");
// ─── Private helpers (exported for internal use by auth.ts) ──────────────────
async function attachRoles(user) {
    const pool = (0, db_1.getPool)();
    const { rows } = await pool.query(sql_1.GET_ROLES_BY_USER_ID, [user.id]);
    return { ...user, roles: rows };
}
async function attachRolesToMany(users) {
    if (users.length === 0)
        return [];
    const pool = (0, db_1.getPool)();
    const ids = users.map((u) => u.id);
    const { rows } = await pool.query(sql_1.GET_ROLES_BY_USER_IDS, [ids]);
    const roleMap = new Map();
    for (const row of rows) {
        const list = roleMap.get(row.user_id) || [];
        list.push({ role: row.role, type: row.type, created_at: row.created_at });
        roleMap.set(row.user_id, list);
    }
    return users.map((u) => ({ ...u, roles: roleMap.get(u.id) || [] }));
}
// ─── CRUD ─────────────────────────────────────────────────────────────────────
async function createUser(input) {
    const pool = (0, db_1.getPool)();
    const passwordHash = input.password
        ? await bcryptjs_1.default.hash(input.password, 10)
        : null;
    const { rows } = await pool.query(sql_1.INSERT_USER, [
        input.external_id,
        input.email || null,
        input.display_name || null,
        input.status || 'active',
        input.metadata ? JSON.stringify(input.metadata) : null,
        passwordHash,
        input.oauth_provider || null,
        input.oauth_provider_id || null,
    ]);
    const user = rows[0];
    if (input.roles && input.roles.length > 0) {
        for (const r of input.roles) {
            // Ensure the role exists in lt_roles (FK constraint)
            await pool.query(sql_1.ENSURE_ROLE_EXISTS, [r.role]);
            await pool.query(sql_1.INSERT_USER_ROLE_IGNORE, [user.id, r.role, r.type]);
        }
    }
    return attachRoles(user);
}
async function getUser(id) {
    const pool = (0, db_1.getPool)();
    const { rows } = await pool.query(sql_1.GET_USER_BY_ID, [id]);
    if (!rows[0])
        return null;
    return attachRoles(rows[0]);
}
async function getUserByExternalId(externalId) {
    const pool = (0, db_1.getPool)();
    const { rows } = await pool.query(sql_1.GET_USER_BY_EXTERNAL_ID, [externalId]);
    if (!rows[0])
        return null;
    return attachRoles(rows[0]);
}
async function getUserByEmail(email) {
    const pool = (0, db_1.getPool)();
    const { rows } = await pool.query(sql_1.GET_USER_BY_EMAIL, [email]);
    if (!rows[0])
        return null;
    return attachRoles(rows[0]);
}
async function updateUser(id, input) {
    const pool = (0, db_1.getPool)();
    const sets = [];
    const values = [];
    let idx = 1;
    if (input.email !== undefined) {
        sets.push(`email = $${idx++}`);
        values.push(input.email);
    }
    if (input.display_name !== undefined) {
        sets.push(`display_name = $${idx++}`);
        values.push(input.display_name);
    }
    if (input.status !== undefined) {
        sets.push(`status = $${idx++}`);
        values.push(input.status);
    }
    if (input.password !== undefined) {
        sets.push(`password_hash = $${idx++}`);
        values.push(await bcryptjs_1.default.hash(input.password, 10));
    }
    if (input.metadata !== undefined) {
        sets.push(`metadata = $${idx++}`);
        values.push(JSON.stringify(input.metadata));
    }
    if (sets.length === 0) {
        return getUser(id);
    }
    values.push(id);
    const { rows } = await pool.query(`UPDATE lt_users SET ${sets.join(', ')} WHERE id = $${idx} RETURNING *`, values);
    if (!rows[0])
        return null;
    return attachRoles(rows[0]);
}
async function deleteUser(id) {
    const pool = (0, db_1.getPool)();
    const { rowCount } = await pool.query(sql_1.DELETE_USER_BY_ID, [id]);
    return (rowCount ?? 0) > 0;
}
async function listUsers(filters) {
    const pool = (0, db_1.getPool)();
    const conditions = [];
    const values = [];
    let idx = 1;
    let needsJoin = false;
    if (filters.role) {
        needsJoin = true;
        conditions.push(`r.role = $${idx++}`);
        values.push(filters.role);
    }
    if (filters.roleType) {
        needsJoin = true;
        conditions.push(`r.type = $${idx++}`);
        values.push(filters.roleType);
    }
    if (filters.status) {
        conditions.push(`u.status = $${idx++}`);
        values.push(filters.status);
    }
    const join = needsJoin ? 'INNER JOIN lt_user_roles r ON r.user_id = u.id' : '';
    const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';
    const limit = filters.limit || 50;
    const offset = filters.offset || 0;
    const [countResult, dataResult] = await Promise.all([
        pool.query(`SELECT COUNT(DISTINCT u.id) FROM lt_users u ${join} ${where}`, values),
        pool.query(`SELECT DISTINCT u.* FROM lt_users u ${join} ${where} ORDER BY u.created_at DESC LIMIT $${idx++} OFFSET $${idx++}`, [...values, limit, offset]),
    ]);
    return {
        users: await attachRolesToMany(dataResult.rows),
        total: parseInt(countResult.rows[0].count, 10),
    };
}
