"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBotRoles = exports.removeBotRole = exports.addBotRole = exports.revokeBotKey = exports.listBotKeys = void 0;
exports.createBot = createBot;
exports.getBot = getBot;
exports.listBots = listBots;
exports.updateBot = updateBot;
exports.deactivateBot = deactivateBot;
exports.deleteBot = deleteBot;
exports.createBotKey = createBotKey;
exports.ensureSystemBot = ensureSystemBot;
/**
 * Bot account management.
 *
 * Bot accounts are rows in lt_users with account_type = 'bot'.
 * They share the same RBAC, OAuth credentials, and delegation tokens
 * as human users — no separate infrastructure needed.
 */
const db_1 = require("../../lib/db");
const user_1 = require("../user");
const user_2 = require("../user");
Object.defineProperty(exports, "addBotRole", { enumerable: true, get: function () { return user_2.addUserRole; } });
Object.defineProperty(exports, "removeBotRole", { enumerable: true, get: function () { return user_2.removeUserRole; } });
Object.defineProperty(exports, "getBotRoles", { enumerable: true, get: function () { return user_2.getUserRoles; } });
const bot_api_key_1 = require("../auth/bot-api-key");
Object.defineProperty(exports, "listBotKeys", { enumerable: true, get: function () { return bot_api_key_1.listBotApiKeys; } });
Object.defineProperty(exports, "revokeBotKey", { enumerable: true, get: function () { return bot_api_key_1.revokeBotApiKey; } });
const sql_1 = require("./sql");
/**
 * Create a new bot account.
 */
async function createBot(input) {
    const userInput = {
        external_id: input.name,
        display_name: input.display_name ?? input.name,
        roles: input.roles,
        metadata: {
            account_type: 'bot',
            description: input.description,
            created_by: input.created_by,
        },
    };
    // Create the user row, then set account_type column
    const user = await (0, user_1.createUser)(userInput);
    const pool = await (0, db_1.getPool)();
    await pool.query(sql_1.SET_ACCOUNT_TYPE_BOT, ['bot', user.id]);
    return toBotRecord(user, input.description, input.created_by);
}
/**
 * Get a single bot account by ID.
 */
async function getBot(id) {
    const user = await (0, user_1.getUser)(id);
    if (!user || user.metadata?.account_type !== 'bot')
        return null;
    return toBotRecord(user);
}
/**
 * List all bot accounts with pagination.
 */
async function listBots(limit = 50, offset = 0) {
    const pool = await (0, db_1.getPool)();
    const [{ rows }, countResult] = await Promise.all([
        pool.query(sql_1.LIST_BOTS, [limit, offset]),
        pool.query(sql_1.COUNT_BOTS),
    ]);
    // Attach roles to each bot
    const bots = await Promise.all(rows.map(async (row) => {
        const roles = await (0, user_2.getUserRoles)(row.id);
        return toBotRecord({ ...row, roles });
    }));
    return { bots, total: countResult.rows[0].total };
}
/**
 * Update a bot account.
 */
async function updateBot(id, input) {
    const existing = await getBot(id);
    if (!existing)
        return null;
    const metadata = {
        ...(existing.metadata || {}),
        ...(input.description !== undefined ? { description: input.description } : {}),
    };
    const user = await (0, user_1.updateUser)(id, {
        display_name: input.display_name,
        status: input.status,
        metadata,
    });
    if (!user)
        return null;
    return toBotRecord(user);
}
/**
 * Deactivate a bot account (sets status to 'inactive').
 */
async function deactivateBot(id) {
    const bot = await getBot(id);
    if (!bot)
        return false;
    const updated = await (0, user_1.updateUser)(id, { status: 'inactive' });
    return !!updated;
}
/**
 * Delete a bot account and all its API keys (cascaded).
 */
async function deleteBot(id) {
    const bot = await getBot(id);
    if (!bot)
        return false;
    return (0, user_1.deleteUser)(id);
}
// ── Bot API key management ─────────────────────────────────────────────────
/**
 * Generate a new API key for a bot.
 */
async function createBotKey(botId, name, scopes = [], expiresAt) {
    const bot = await getBot(botId);
    if (!bot)
        throw new Error('Bot not found');
    return (0, bot_api_key_1.generateBotApiKey)(name, botId, scopes, expiresAt);
}
// ── System bot ─────────────────────────────────────────────────────────────
const SYSTEM_BOT_NAME = 'lt-system';
/**
 * Ensure the system bot account exists.
 * Called at startup so cron and system-initiated workflows
 * always have a principal (the `lt-system` bot).
 */
async function ensureSystemBot() {
    const pool = await (0, db_1.getPool)();
    const { rows } = await pool.query(sql_1.GET_USER_BY_EXTERNAL_ID, [SYSTEM_BOT_NAME]);
    if (rows.length > 0)
        return rows[0].id;
    try {
        const bot = await createBot({
            name: SYSTEM_BOT_NAME,
            display_name: 'System',
            description: 'System bot for cron and system-initiated workflows',
            roles: [{ role: 'system', type: 'superadmin' }],
        });
        return bot.id;
    }
    catch (err) {
        // Concurrent container already created it — re-read
        if (err.code === '23505') {
            const { rows: retry } = await pool.query(sql_1.GET_USER_BY_EXTERNAL_ID, [SYSTEM_BOT_NAME]);
            if (retry.length > 0)
                return retry[0].id;
        }
        throw err;
    }
}
// ── Helpers ────────────────────────────────────────────────────────────────
function toBotRecord(user, description, createdBy) {
    return {
        ...user,
        account_type: 'bot',
        description: description ?? user.metadata?.description,
        created_by: createdBy ?? user.metadata?.created_by,
    };
}
