"use strict";
// SPDX-FileCopyrightText: 2025 Gnuxie <Gnuxie@protonmail.com>
//
// SPDX-License-Identifier: Apache-2.0
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SqliteUserRestrictionAuditLog = void 0;
const matrix_protection_suite_1 = require("matrix-protection-suite");
const SqliteSchema_1 = require("../../backingstore/better-sqlite3/SqliteSchema");
const BetterSqliteStore_1 = require("../../backingstore/better-sqlite3/BetterSqliteStore");
const typescript_result_1 = require("@gnuxie/typescript-result");
const path_1 = __importDefault(require("path"));
const log = new matrix_protection_suite_1.Logger("SqliteUserAuditLog");
const SchemaText = [
    `
  CREATE TABLE policy_info (
    policy_id TEXT PRIMARY KEY NOT NULL,
    sender_user_id TEXT NOT NULL,
    entity TEXT NOT NULL,
    policy_room_id TEXT NOT NULL,
    state_key TEXT NOT NULL,
    type TEXT NOT NULL,
    recommendation TEXT NOT NULL
  ) STRICT;
  CREATE TABLE user_restriction (
    policy_id TEXT,
    target_user_id TEXT NOT NULL,
    sender_user_id TEXT NOT NULL,
    restriction_type TEXT NOT NULL,
    is_existing_restriction INTEGER NOT NULL CHECK (is_existing_restriction IN (0, 1)),
    created_at INTEGER DEFAULT (unixepoch()) NOT NULL,
    FOREIGN KEY (policy_id) REFERENCES policy_info(policy_id)
  ) STRICT;
  CREATE INDEX idx_user_restriction ON user_restriction (target_user_id, created_at);
  CREATE TABLE user_unrestriction (
    target_user_id TEXT NOT NULL,
    sender_user_id TEXT NOT NULL,
    created_at INTEGER DEFAULT (unixepoch()) NOT NULL
    ) STRICT;
  CREATE INDEX idx_user_unrestriction ON user_unrestriction (target_user_id, created_at);`,
];
const SchemaOptions = {
    upgradeSteps: SchemaText.map((text) => function (db) {
        db.exec(text);
    }),
    consistencyCheck(db) {
        return (0, SqliteSchema_1.checkKnownTables)(db, [
            "policy_info",
            "user_restriction",
            "user_unrestriction",
        ]);
    },
};
function wrapInTryCatch(cb, message) {
    try {
        return cb();
    }
    catch (e) {
        if (e instanceof Error) {
            return matrix_protection_suite_1.ActionException.Result(message, {
                exception: e,
                exceptionKind: matrix_protection_suite_1.ActionExceptionKind.Unknown,
            });
        }
        else {
            throw e;
        }
    }
}
class SqliteUserRestrictionAuditLog extends BetterSqliteStore_1.BetterSqliteStore {
    constructor(db) {
        super(SchemaOptions, db, log);
    }
    static StoreName = "user-restriction-audit-log.db";
    static createToplevel(storagePath) {
        const options = {
            path: path_1.default.join(storagePath, SqliteUserRestrictionAuditLog.StoreName),
            WALMode: true,
            foreignKeys: true,
            fileMustExist: false,
        };
        return new SqliteUserRestrictionAuditLog((0, BetterSqliteStore_1.makeBetterSqliteDB)(options, log));
    }
    async isUserRestricted(userID) {
        return wrapInTryCatch(() => {
            const timeOfRestriction = this.db
                .prepare("SELECT MAX(created_at) FROM user_restriction WHERE target_user_id = :user_id;")
                .pluck()
                .get({ user_id: userID });
            if (timeOfRestriction === null) {
                return (0, typescript_result_1.Ok)(false);
            }
            const timeOfUnrestriction = this.db
                .prepare("SELECT MAX(created_at) FROM user_unrestriction WHERE target_user_id = :user_id;")
                .pluck()
                .get({ user_id: userID });
            if (timeOfUnrestriction != null &&
                timeOfUnrestriction >= timeOfRestriction) {
                return (0, typescript_result_1.Ok)(false);
            }
            else {
                return (0, typescript_result_1.Ok)(true);
            }
        }, `Failed to check if user ${userID} is suspended`);
    }
    insertPolicyInfo(policy) {
        this.db
            .prepare(`REPLACE INTO policy_info (policy_id, sender_user_id, policy_room_id, entity, state_key, type, recommendation)
      VALUES (?, ?, ?, ?, ?, ?, ?)`)
            .run([
            policy.sourceEvent.event_id,
            policy.sourceEvent.sender,
            policy.sourceEvent.room_id,
            policy.entity,
            policy.sourceEvent.state_key,
            policy.sourceEvent.type,
            policy.recommendation,
        ]);
    }
    async recordUserRestriction(userID, restrictionType, { sender, rule, isExistingRestriction, }) {
        return wrapInTryCatch(() => {
            this.db.transaction(() => {
                if (rule) {
                    this.insertPolicyInfo(rule);
                }
                const policyID = rule?.sourceEvent.event_id ?? null;
                this.db
                    .prepare(`
          INSERT INTO user_restriction (
            policy_id,
            target_user_id,
            sender_user_id,
            restriction_type,
            is_existing_restriction
          ) VALUES (?, ?, ?, ?, ?)
        `)
                    .run([
                    policyID,
                    userID,
                    sender,
                    restrictionType,
                    Number(Boolean(isExistingRestriction)),
                ]);
            })();
            return (0, typescript_result_1.Ok)(undefined);
        }, `Failed to suspend user ${userID}`);
    }
    async recordExistingUserRestriction(userID, restriction) {
        return await this.recordUserRestriction(userID, restriction, {
            sender: userID,
            rule: null,
            isExistingRestriction: true,
        });
    }
    async unrestrictUser(userID, sender) {
        return wrapInTryCatch(() => {
            this.db
                .prepare(`
          INSERT INTO user_unrestriction (target_user_id, sender_user_id) VALUES (?, ?)
          `)
                .run([userID, sender]);
            return (0, typescript_result_1.Ok)(undefined);
        }, `Failed to unsuspend user ${userID}`);
    }
}
exports.SqliteUserRestrictionAuditLog = SqliteUserRestrictionAuditLog;
//# sourceMappingURL=SqliteUserRestrictionAuditLog.js.map