import { WitnessScope, parse as parseWitnessScope, toString, } from "./WitnessScope";
import { num2hexstring, HexString, deserializeArrayOf, serializeArrayOf, } from "../../u";
export class Signer {
    constructor(signer = {}) {
        const { account = "", scopes = WitnessScope.None, allowedContracts = [], allowedGroups = [], } = signer;
        this.account = HexString.fromHex(account);
        this.scopes =
            (typeof scopes === "string" ? parseWitnessScope(scopes) : scopes) & 0xff;
        this.allowedContracts = allowedContracts.map((i) => HexString.fromHex(i));
        this.allowedGroups = allowedGroups.map((i) => HexString.fromHex(i));
    }
    static fromJson(input) {
        var _a, _b;
        return new Signer({
            account: input.account,
            scopes: parseWitnessScope(input.scopes),
            allowedContracts: (_a = input.allowedcontracts) !== null && _a !== void 0 ? _a : [],
            allowedGroups: (_b = input.allowedgroups) !== null && _b !== void 0 ? _b : [],
        });
    }
    /**
     * Returns the number of bytes this object will take when serialized.
     */
    get size() {
        return this.serialize().length / 2;
    }
    addAllowedContracts(...contracts) {
        if (this.scopes & WitnessScope.Global) {
            return;
        }
        this.scopes |= WitnessScope.CustomContracts;
        contracts
            .map((i) => HexString.fromHex(i))
            .forEach((i) => this.allowedContracts.push(i));
    }
    addAllowedGroups(...groups) {
        if (this.scopes & WitnessScope.Global) {
            return;
        }
        this.scopes |= WitnessScope.CustomGroups;
        groups
            .map((i) => HexString.fromHex(i))
            .forEach((i) => this.allowedGroups.push(i));
    }
    static deserialize(ss) {
        const account = HexString.fromHex(ss.read(20), true);
        const scopes = parseInt(ss.read(), 16);
        const allowedContracts = scopes & WitnessScope.CustomContracts
            ? deserializeArrayOf((s) => HexString.fromHex(s.read(20), true), ss)
            : [];
        const allowedGroups = scopes & WitnessScope.CustomGroups
            ? deserializeArrayOf((s) => HexString.fromHex(s.read(33)), ss)
            : [];
        return new Signer({ account, scopes, allowedContracts, allowedGroups });
    }
    /**
     * Merges the other Signer into this signer.
     * Deduplicates contracts and groups.
     * Modifies the original Signer and returns it.
     */
    merge(other) {
        const otherSigner = other instanceof Signer ? other : new Signer(other);
        if (!this.account.equals(otherSigner.account)) {
            throw new Error("Cannot merge Signers of different accounts!");
        }
        this.scopes |= otherSigner.scopes;
        // Global scope
        if (this.scopes & WitnessScope.Global) {
            this.scopes = WitnessScope.Global;
            this.allowedContracts = [];
            this.allowedGroups = [];
            return this;
        }
        if (otherSigner.allowedContracts) {
            const deduplicatedContracts = otherSigner.allowedContracts.filter((i) => !this.allowedContracts.some((j) => j.equals(i)));
            this.allowedContracts = this.allowedContracts.concat(deduplicatedContracts);
        }
        if (otherSigner.allowedGroups) {
            const deduplicatedGroups = otherSigner.allowedGroups.filter((i) => !this.allowedGroups.some((j) => j.equals(i)));
            this.allowedGroups = this.allowedGroups.concat(deduplicatedGroups);
        }
        return this;
    }
    serialize() {
        let out = "";
        out += this.account.toLittleEndian();
        out += num2hexstring(this.scopes, 1);
        if (this.scopes & WitnessScope.CustomContracts) {
            out += serializeArrayOf(this.allowedContracts.map((i) => i.toLittleEndian()));
        }
        if (this.scopes & WitnessScope.CustomGroups) {
            out += serializeArrayOf(this.allowedGroups.map((i) => i.toBigEndian()));
        }
        return out;
    }
    export() {
        const output = {
            account: this.account.toBigEndian(),
            scopes: this.scopes,
        };
        if (this.scopes & WitnessScope.CustomContracts) {
            output.allowedContracts = [
                ...this.allowedContracts.map((i) => i.toBigEndian()),
            ];
        }
        if (this.scopes & WitnessScope.CustomGroups) {
            output.allowedGroups = [
                ...this.allowedGroups.map((i) => i.toBigEndian()),
            ];
        }
        return output;
    }
    toJson() {
        const output = {
            account: "0x" + this.account.toBigEndian(),
            scopes: toString(this.scopes),
        };
        if (this.scopes & WitnessScope.CustomContracts) {
            output.allowedcontracts = [
                ...this.allowedContracts.map((i) => "0x" + i.toBigEndian()),
            ];
        }
        if (this.scopes & WitnessScope.CustomGroups) {
            output.allowedgroups = [
                ...this.allowedGroups.map((i) => i.toBigEndian()),
            ];
        }
        return output;
    }
}
export default Signer;
//# sourceMappingURL=Signer.js.map