"use strict";
/**
 * NightgateAdminService, System Administration
 *
 * Provides session management for wallet connections.
 * Entity projections (WalletSessions) are handled by CDS automatically.
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const cds_1 = __importDefault(require("@sap/cds"));
const { SELECT, UPDATE, INSERT } = cds_1.default.ql;
const cds_model_1 = require("./utils/cds-model");
const disclosure_role_1 = require("./middleware/disclosure-role");
const midnight_1 = require("#cds-models/midnight");
class NightgateAdminService extends cds_1.default.ApplicationService {
    db;
    async init() {
        await (0, cds_model_1.ensureNightgateModelLoaded)();
        this.db = await cds_1.default.connect.to('db');
        this.on('invalidateSession', async (req) => {
            const { sessionId } = req.data;
            if (!sessionId) {
                return req.reject(400, 'sessionId is required');
            }
            const session = await this.db.run(SELECT.one.from(midnight_1.WalletSessions).where({ sessionId }));
            if (!session) {
                return req.reject(404, `Session ${sessionId} not found`);
            }
            if (!session.isActive) {
                return req.reject(409, `Session ${sessionId} is already inactive`);
            }
            await this.db.run(UPDATE.entity(midnight_1.WalletSessions).set({
                isActive: false,
                disconnectedAt: new Date().toISOString(),
                encryptedViewingKey: null // Clear encrypted key
            }).where({ sessionId }));
        });
        this.on('invalidateAllSessions', async () => {
            const result = await this.db.run(UPDATE.entity(midnight_1.WalletSessions).set({
                isActive: false,
                disconnectedAt: new Date().toISOString(),
                encryptedViewingKey: null // Clear all encrypted keys
            }).where({ isActive: true }));
            return result;
        });
        // grantRole. Service-level @requires: 'admin' has already gated the
        // CAP auth side. Belt-and-suspenders: additionally require the caller
        // to hold the 'authority' disclosure tier, so a sysadmin who is not
        // also a regulator cannot grant data-tier access.
        this.on('grantRole', async (req) => {
            const { userId, role, scope, validUntil } = req.data;
            if (!userId)
                return req.reject(400, 'userId is required');
            if (!role)
                return req.reject(400, 'role is required');
            if (!(0, disclosure_role_1.isValidDisclosureRoleValue)(role)) {
                return req.reject(400, `role must be one of: ${disclosure_role_1.DISCLOSURE_ROLE_VALUES.join(', ')}`);
            }
            const callerRole = await (0, disclosure_role_1.attachDisclosureRole)(req, this.db);
            if (!(0, disclosure_role_1.isAuthority)(callerRole)) {
                return req.reject(403, 'caller must hold the authority disclosure role to grant roles');
            }
            const grantedBy = req.user?.id || 'unknown';
            const now = new Date().toISOString();
            await this.db.run(INSERT.into(midnight_1.DisclosureRoles).entries({
                userId,
                role,
                scope: scope && scope.length > 0 ? scope : null,
                grantedBy,
                validFrom: now,
                validUntil: validUntil && validUntil.length > 0 ? validUntil : null
            }));
        });
        await super.init();
    }
}
exports.default = NightgateAdminService;
