"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PermissionedOp = void 0;
const bn_js_1 = __importDefault(require("bn.js"));
/**
 * Permission operation encodings matching the Rust PermissionedOp bitflags
 */
class PermissionedOp {
    bitfield;
    /** Canonical zero bitfield. The string form is obtained via `toString()`. */
    static NONE = new bn_js_1.default(0);
    // On-chain Rust: pub struct PermissionedOp: u64 { DEPOSIT=1<<0; BORROW=1<<1; LIQUIDATE=1<<2; }
    // REPAY and WITHDRAW are never permissioned.
    static BIT_INDEX_MAP = new Map([
        ['DEPOSIT', 0],
        ['BORROW', 1],
        ['LIQUIDATE', 2],
    ]);
    /** PermissionedOp with no flags set. */
    static empty() {
        return new PermissionedOp(PermissionedOp.NONE);
    }
    /**
     * PermissionedOp with every known flag set.
     */
    static allValid() {
        return PermissionedOp.fromBN(PermissionedOp.allValidBN());
    }
    /**
     * Single-bit mask (as a BN) for a single operation name (case-insensitive).
     */
    static toBitMask(op) {
        const operation = op.toUpperCase();
        const bitIndex = this.BIT_INDEX_MAP.get(operation);
        if (bitIndex === undefined) {
            throw new Error(`Unknown operation: ${op}`);
        }
        return new bn_js_1.default(1).shln(bitIndex);
    }
    /**
     * Build a PermissionedOp from a pipe-separated op list (e.g., "DEPOSIT|BORROW").
     * Empty string or "NONE" (case-insensitive) yields a zero bitfield.
     */
    static fromString(ops) {
        return new PermissionedOp(ops);
    }
    /**
     * Build a PermissionedOp from a raw BN bitfield. Unknown bits are masked off.
     */
    static fromBN(bitfield) {
        return new PermissionedOp(bitfield);
    }
    /**
     * Build a PermissionedOp from an unknown input, accepting only `string`, `BN`, or `undefined`.
     * `undefined` yields a zero (NONE) bitfield.
     */
    static fromUnknown(input) {
        if (input === undefined) {
            return PermissionedOp.empty();
        }
        if (typeof input !== 'string' && !bn_js_1.default.isBN(input)) {
            throw new Error(`PermissionedOp.fromUnknown: expected string, BN, or undefined, got ${typeof input}`);
        }
        return new PermissionedOp(input);
    }
    /**
     * BN with every known flag set. Internal helper used for masking,
     */
    static allValidBN() {
        let result = new bn_js_1.default(0);
        for (const bitIndex of this.BIT_INDEX_MAP.values()) {
            result = result.or(new bn_js_1.default(1).shln(bitIndex));
        }
        return result;
    }
    /**
     * Create a PermissionedOp from a human-readable op string (e.g., "DEPOSIT|BORROW")
     * or a raw BN bitfield. Unknown bits in a BN input are masked off.
     */
    constructor(input) {
        if (typeof input !== 'string') {
            this.bitfield = input.and(PermissionedOp.allValidBN());
            return;
        }
        const normalized = input.trim().toUpperCase();
        if (normalized === '' || normalized === PermissionedOp.empty().toString()) {
            this.bitfield = PermissionedOp.NONE;
            return;
        }
        let bits = new bn_js_1.default(0);
        normalized.split('|').forEach((operation) => {
            bits = bits.or(PermissionedOp.toBitMask(operation.trim()));
        });
        this.bitfield = bits;
    }
    /**
     * Underlying bitfield as a BN.
     */
    toBN() {
        return this.bitfield;
    }
    /**
     * Human-readable form, e.g. "DEPOSIT|BORROW", or "NONE" when the bitfield is zero.
     */
    toString() {
        const operations = [];
        for (const [operation, bitIndex] of PermissionedOp.BIT_INDEX_MAP.entries()) {
            const mask = new bn_js_1.default(1).shln(bitIndex);
            if (!this.bitfield.and(mask).isZero()) {
                operations.push(operation);
            }
        }
        return operations.length > 0 ? operations.join('|') : 'NONE';
    }
    /** True if this PermissionedOp has the same bitfield as `other`. */
    equals(other) {
        return this.bitfield.eq(other.bitfield);
    }
    /** True if this PermissionedOp has no flags set. */
    isEmpty() {
        return this.equals(PermissionedOp.empty());
    }
    /**
     * Returns true if any bit set in `other` is also set in this bitfield.
     */
    intersects(other) {
        return !this.bitfield.and(other.bitfield).isZero();
    }
}
exports.PermissionedOp = PermissionedOp;
//# sourceMappingURL=permission.js.map