// SPDX-License-Identifier: Apache-2.0
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import Injectable from "../../../core/injectable/Injectable";
import { QueryBus } from "../../../core/query/QueryBus";
import { UnlistedKycIssuer } from "../../../domain/context/security/error/operations/UnlistedKycIssuer";
import Service from "../Service";
import { singleton } from "tsyringe";
import { AccountNotKycd } from "../../../domain/context/security/error/operations/AccountNotKycd";
import { IsIssuerQuery } from "../../usecase/query/security/ssi/isIssuer/IsIssuerQuery";
import { GetKycStatusForQuery } from "../../usecase/query/security/kyc/getKycStatusFor/GetKycStatusForQuery";
import { IsClearingActivatedQuery } from "../../usecase/query/security/clearing/isClearingActivated/IsClearingActivatedQuery";
import { ClearingDeactivated } from "../../../domain/context/security/error/operations/ClearingDeactivated";
import { ClearingActivated } from "../../../domain/context/security/error/operations/ClearingActivated";
import { IsOperatorForPartitionQuery } from "../../usecase/query/security/operator/isOperatorForPartition/IsOperatorForPartitionQuery";
import { HasRoleQuery } from "../../usecase/query/security/roles/hasRole/HasRoleQuery";
import { IsPausedQuery } from "../../usecase/query/security/isPaused/IsPausedQuery";
import { IsOperatorQuery } from "../../usecase/query/security/operator/isOperator/IsOperatorQuery";
import { AccountIsNotOperator } from "../../../domain/context/security/error/operations/AccountIsNotOperator";
import { NotGrantedRole } from "../../../domain/context/security/error/operations/NotGrantedRole";
import { SecurityPaused } from "../../../domain/context/security/error/operations/SecurityPaused";
import { DecimalsOverRange } from "../../../domain/context/security/error/operations/DecimalsOverRange";
import { PartitionsUnProtected } from "../../../domain/context/security/error/operations/PartitionsUnprotected";
import { ContractsErrorMapper } from "../../../domain/context/security/error/operations/contractsErrorsMapper/ContractsErrorMapper";
import { CanTransferByPartitionQuery } from "../../usecase/query/security/canTransferByPartition/CanTransferByPartitionQuery";
import CheckNums from "../../../core/checks/numbers/CheckNums";
import { getProtectedPartitionRole } from "../../../domain/context/security/SecurityRole";
import { GetNounceQuery } from "../../usecase/query/security/protectedPartitions/getNounce/GetNounceQuery";
import { NounceAlreadyUsed } from "../../../domain/context/security/error/operations/NounceAlreadyUsed";
import { IsInControlListQuery } from "../../usecase/query/account/controlList/IsInControlListQuery";
import { AccountNotInControlList } from "../../../domain/context/security/error/operations/AccountNotInControlList";
import { AccountAlreadyInControlList } from "../../../domain/context/security/error/operations/AccountAlreadyInControlList";
import { AccountIsAlreadyAnIssuer } from "../../../domain/context/security/error/operations/AccountAlreadyIsAnIssuer";
import { CanRedeemByPartitionQuery } from "../../usecase/query/security/canRedeemByPartition/CanRedeemByPartitionQuery";
import { InsufficientHoldBalance } from "../../../domain/context/security/error/operations/InsufficientHoldBalance";
import { BalanceOfQuery } from "../../usecase/query/security/balanceof/BalanceOfQuery";
import { InsufficientBalance } from "../../../domain/context/security/error/operations/InsufficientBalance";
import { GetHoldForByPartitionQuery } from "../../usecase/query/security/hold/getHoldForByPartition/GetHoldForByPartitionQuery";
import { GetControlListTypeQuery } from "../../usecase/query/security/controlList/getControlListType/GetControlListTypeQuery";
import { SecurityControlListType } from "../../../domain/context/security/SecurityControlListType";
import { GetControlListCountQuery } from "../../usecase/query/security/controlList/getControlListCount/GetControlListCountQuery";
import { GetControlListMembersQuery } from "../../usecase/query/security/controlList/getControlListMembers/GetControlListMembersQuery";
import { AccountInBlackList } from "../../../domain/context/security/error/operations/AccountInBlackList";
import { AccountNotInWhiteList } from "../../../domain/context/security/error/operations/AccountNotInWhiteList";
import { GetMaxSupplyQuery } from "../../usecase/query/security/cap/getMaxSupply/GetMaxSupplyQuery";
import { GetMaxSupplyByPartitionQuery } from "../../usecase/query/security/cap/getMaxSupplyByPartition/GetMaxSupplyByPartitionQuery";
import { MaxSupplyByPartitionReached } from "../../../domain/context/security/error/operations/MaxSupplyByPartitionReached";
import { MaxSupplyReached } from "../../../domain/context/security/error/operations/MaxSupplyReached";
import { NotAllowedInMultiPartition } from "../../../domain/context/security/error/operations/NotAllowedInMultiPartition";
import { OnlyDefaultPartitionAllowed } from "../../../domain/context/security/error/operations/OnlyDefaultPartitionAllowed";
import { NotIssuable } from "../../../domain/context/security/error/operations/NotIssuable";
import { _PARTITION_ID_1 } from "../../../core/Constants";
import { Terminal3Vc } from "../../../domain/context/kyc/Terminal3";
import { InvalidVcHolder } from "../../../domain/context/security/error/operations/InvalidVcHolder";
import { GetTotalSupplyByPartitionQuery } from "../../usecase/query/security/cap/getTotalSupplyByPartition/GetTotalSupplyByPartitionQuery";
import { SecurityUnPaused } from "../../../domain/context/security/error/operations/SecurityUnPaused";
import { PartitionsProtected } from "../../../domain/context/security/error/operations/PartitionsProtected";
import { GetBondDetailsQuery } from "../../usecase/query/bond/get/getBondDetails/GetBondDetailsQuery";
import { OperationNotAllowed } from "../../../domain/context/security/error/operations/OperationNotAllowed";
import { IsInternalKycActivatedQuery } from "../../usecase/query/security/kyc/isInternalKycActivated/IsInternalKycActivatedQuery";
import { IsExternallyGrantedQuery } from "../../usecase/query/security/externalKycLists/isExternallyGranted/IsExternallyGrantedQuery";
import { GetTokenBySaltQuery } from "../../usecase/query/factory/trex/getTokenBySalt/GetTokenBySaltQuery";
import { InvalidTrexTokenSalt } from "../../../domain/context/factory/error/InvalidTrexTokenSalt";
import { IsProceedRecipientQuery } from "../../usecase/query/security/proceedRecipient/isProceedRecipient/IsProceedRecipientQuery";
import { AccountIsNotProceedRecipient } from "../../../domain/context/security/error/operations/AccountIsNotProceedRecipient";
import { AccountIsProceedRecipient } from "../../../domain/context/security/error/operations/AccountIsProceedRecipient";
let ValidationService = class ValidationService extends Service {
    queryBus;
    constructor() {
        super();
    }
    async checkIssuer(securityId, issuer) {
        this.queryBus = Injectable.resolve(QueryBus);
        const res = await this.queryBus.execute(new IsIssuerQuery(securityId, issuer));
        if (!res.payload)
            throw new UnlistedKycIssuer(issuer);
    }
    async checkKycAddresses(securityId, addresses, kycStatus) {
        const queryBus = Injectable.resolve(QueryBus);
        const isInternalKycActivated = await queryBus.execute(new IsInternalKycActivatedQuery(securityId));
        for (const address of addresses) {
            const isKycValid = await this.validateAddressKyc(queryBus, securityId, address, kycStatus, isInternalKycActivated.payload);
            if (!isKycValid) {
                throw new AccountNotKycd(address, kycStatus);
            }
        }
    }
    async checkClearingActivated(securityId) {
        this.queryBus = Injectable.resolve(QueryBus);
        const result = (await this.queryBus.execute(new IsClearingActivatedQuery(securityId))).payload;
        if (!result) {
            throw new ClearingDeactivated();
        }
    }
    async checkClearingDeactivated(securityId) {
        this.queryBus = Injectable.resolve(QueryBus);
        const result = (await this.queryBus.execute(new IsClearingActivatedQuery(securityId))).payload;
        if (result) {
            throw new ClearingActivated();
        }
    }
    async checkOperator(securityId, partitionId, operatorId, targetId) {
        this.queryBus = Injectable.resolve(QueryBus);
        if ((await this.queryBus.execute(new IsOperatorQuery(securityId, operatorId, targetId))).payload ||
            (await this.queryBus.execute(new IsOperatorForPartitionQuery(securityId, partitionId, operatorId, targetId)))
                .payload) {
            return;
        }
        throw new AccountIsNotOperator(operatorId, targetId);
    }
    async checkRole(role, accountId, securityId) {
        this.queryBus = Injectable.resolve(QueryBus);
        const res = await this.queryBus.execute(new HasRoleQuery(role, accountId, securityId));
        if (!res.payload) {
            throw new NotGrantedRole(role);
        }
    }
    async checkAnyRole(roles, accountId, securityId) {
        this.queryBus = Injectable.resolve(QueryBus);
        const roleChecks = roles.map((r) => this.queryBus.execute(new HasRoleQuery(r, accountId, securityId)));
        const results = await Promise.all(roleChecks);
        const granted = results.some((r) => r.payload === true);
        if (!granted) {
            throw new NotGrantedRole(`any of [${roles.join(", ")}]`);
        }
    }
    async checkPause(securityId) {
        this.queryBus = Injectable.resolve(QueryBus);
        const res = await this.queryBus.execute(new IsPausedQuery(securityId));
        if (res.payload) {
            throw new SecurityPaused();
        }
    }
    async checkUnpause(securityId) {
        this.queryBus = Injectable.resolve(QueryBus);
        const res = await this.queryBus.execute(new IsPausedQuery(securityId));
        if (!res.payload) {
            throw new SecurityUnPaused();
        }
    }
    async checkProtectedPartitions(security) {
        if (!security.arePartitionsProtected) {
            throw new PartitionsUnProtected();
        }
    }
    async checkUnprotectedPartitions(security) {
        if (security.arePartitionsProtected) {
            throw new PartitionsProtected();
        }
    }
    async checkCanTransfer(securityId, targetId, amount, operatorId, sourceId, partitionId) {
        this.queryBus = Injectable.resolve(QueryBus);
        const res = await this.queryBus.execute(new CanTransferByPartitionQuery(securityId, sourceId ?? operatorId, targetId, partitionId ?? _PARTITION_ID_1, amount));
        if (res.payload[0] != "0x01") {
            throw ContractsErrorMapper.mapError(res.payload[0], res.payload[1]);
        }
    }
    async checkCanRedeem(securityId, sourceId, amount, partitionId) {
        this.queryBus = Injectable.resolve(QueryBus);
        const res = await this.queryBus.execute(new CanRedeemByPartitionQuery(securityId, sourceId, partitionId, amount));
        if (res.payload[0] != "0x01") {
            throw ContractsErrorMapper.mapError(res.payload[0], res.payload[1]);
        }
    }
    async checkMaxSupply(securityId, amount, security, partitionId) {
        let res;
        this.queryBus = Injectable.resolve(QueryBus);
        if (partitionId) {
            res = await this.queryBus.execute(new GetMaxSupplyByPartitionQuery(securityId, partitionId));
            const partitionTotalSupply = await this.queryBus.execute(new GetTotalSupplyByPartitionQuery(securityId, partitionId));
            if (this.isMaxSupplyExceeded(res.payload.toBigInt(), amount.toBigInt(), partitionTotalSupply.payload.toBigInt())) {
                throw new MaxSupplyByPartitionReached();
            }
        }
        res = await this.queryBus.execute(new GetMaxSupplyQuery(securityId));
        if (this.isMaxSupplyExceeded(res.payload.toBigInt(), amount.toBigInt(), security.totalSupply.toBigInt())) {
            throw new MaxSupplyReached();
        }
    }
    async checkDecimals(security, amount) {
        if (CheckNums.hasMoreDecimals(amount, security.decimals)) {
            throw new DecimalsOverRange(security.decimals);
        }
    }
    async checkProtectedPartitionRole(partitionId, accountId, securityId) {
        const protectedPartitionRole = getProtectedPartitionRole(partitionId);
        await this.checkRole(protectedPartitionRole, accountId, securityId);
    }
    async checkValidNounce(securityId, targetId, nounce) {
        this.queryBus = Injectable.resolve(QueryBus);
        const nextNounce = (await this.queryBus.execute(new GetNounceQuery(securityId, targetId))).payload;
        if (nounce <= nextNounce) {
            throw new NounceAlreadyUsed(nounce);
        }
    }
    async checkAccountInControlList(securityId, targetId, add) {
        this.queryBus = Injectable.resolve(QueryBus);
        const res = await this.queryBus.execute(new IsInControlListQuery(securityId, targetId));
        if (add && res.payload) {
            throw new AccountAlreadyInControlList(targetId.toString());
        }
        if (!add && !res.payload) {
            throw new AccountNotInControlList(targetId.toString());
        }
    }
    async checkAccountInIssuersList(securityId, targetId, add) {
        this.queryBus = Injectable.resolve(QueryBus);
        const res = await this.queryBus.execute(new IsIssuerQuery(securityId, targetId));
        if (add && res.payload) {
            throw new AccountIsAlreadyAnIssuer(targetId.toString());
        }
        if (!add && !res.payload) {
            throw new UnlistedKycIssuer(targetId.toString());
        }
    }
    async checkHoldBalance(securityId, partitionId, sourceId, holdId, amount) {
        this.queryBus = Injectable.resolve(QueryBus);
        const holdDetails = await this.queryBus.execute(new GetHoldForByPartitionQuery(securityId, partitionId, sourceId, holdId));
        if (holdDetails.payload.amount < amount.toBigInt()) {
            throw new InsufficientHoldBalance();
        }
    }
    async checkBalance(securityId, accountId, amount) {
        this.queryBus = Injectable.resolve(QueryBus);
        const res = await this.queryBus.execute(new BalanceOfQuery(securityId, accountId));
        if (res.payload.toBigInt() < amount.toBigInt()) {
            throw new InsufficientBalance();
        }
    }
    async checkControlList(securityId, sourceEvmAddress, targetEvmAddress) {
        this.queryBus = Injectable.resolve(QueryBus);
        const controListType = (await this.queryBus.execute(new GetControlListTypeQuery(securityId))).payload;
        const controlListCount = (await this.queryBus.execute(new GetControlListCountQuery(securityId))).payload;
        const controlListMembers = (await this.queryBus.execute(new GetControlListMembersQuery(securityId, 0, controlListCount))).payload.map(function (x) {
            return x.toUpperCase();
        });
        if (sourceEvmAddress) {
            await this.checkUserInControlList(controListType, controlListMembers, sourceEvmAddress);
        }
        if (targetEvmAddress) {
            await this.checkUserInControlList(controListType, controlListMembers, targetEvmAddress);
        }
    }
    async checkMultiPartition(security, partitionId) {
        if (!partitionId && security.isMultiPartition) {
            throw new NotAllowedInMultiPartition();
        }
        if (partitionId && partitionId != _PARTITION_ID_1 && !security.isMultiPartition) {
            throw new OnlyDefaultPartitionAllowed();
        }
    }
    async checkIssuable(security) {
        if (!security.isIssuable) {
            throw new NotIssuable();
        }
    }
    async checkValidVc(signedCredential, targetEvmAddress, securityId) {
        const issuer = Terminal3Vc.extractIssuer(signedCredential);
        signedCredential = Terminal3Vc.checkValidDates(signedCredential);
        const holder = Terminal3Vc.extractHolder(signedCredential);
        if (targetEvmAddress.toString().toLowerCase() !== holder.toLowerCase()) {
            throw new InvalidVcHolder();
        }
        await this.checkIssuer(securityId, issuer);
        return [issuer, signedCredential];
    }
    async checkMaturityDate(securityId, maturityDate) {
        this.queryBus = Injectable.resolve(QueryBus);
        const bondDetails = (await this.queryBus.execute(new GetBondDetailsQuery(securityId))).bond;
        if (parseInt(maturityDate) <= bondDetails.maturityDate) {
            throw new OperationNotAllowed("The maturity date cannot be earlier or equal than the current one");
        }
    }
    async checkTrexTokenSaltExists(factory, salt) {
        this.queryBus = Injectable.resolve(QueryBus);
        const exists = (await this.queryBus.execute(new GetTokenBySaltQuery(factory, salt))).token;
        if (!exists) {
            throw new InvalidTrexTokenSalt(salt);
        }
    }
    async checkUserInControlList(controListType, controlListMembers, user) {
        if (controListType === SecurityControlListType.BLACKLIST &&
            controlListMembers.includes(user.toString().toUpperCase())) {
            throw new AccountInBlackList(user.toString());
        }
        if (controListType === SecurityControlListType.WHITELIST &&
            !controlListMembers.includes(user.toString().toUpperCase())) {
            throw new AccountNotInWhiteList(user.toString());
        }
    }
    isMaxSupplyExceeded(maxSupply, amount, totalSupply) {
        return maxSupply < totalSupply + amount;
    }
    async validateAddressKyc(queryBus, securityId, address, kycStatus, isInternalKycActivated) {
        const internalKycValid = await this.checkInternalKyc(queryBus, securityId, address, kycStatus, isInternalKycActivated);
        if (!internalKycValid) {
            return false;
        }
        return (await queryBus.execute(new IsExternallyGrantedQuery(securityId, kycStatus, address))).payload;
    }
    async checkInternalKyc(queryBus, securityId, address, kycStatus, isInternalKycActivated) {
        if (!isInternalKycActivated) {
            return true;
        }
        const kycResult = await queryBus.execute(new GetKycStatusForQuery(securityId, address));
        return kycResult.payload === kycStatus;
    }
    async checkIsProceedRecipient(securityId, proceedRecipient) {
        this.queryBus = Injectable.resolve(QueryBus);
        const res = (await this.queryBus.execute(new IsProceedRecipientQuery(securityId, proceedRecipient))).payload;
        if (!res) {
            throw new AccountIsNotProceedRecipient(securityId, proceedRecipient);
        }
        return res;
    }
    async checkIsNotProceedRecipient(securityId, proceedRecipient) {
        this.queryBus = Injectable.resolve(QueryBus);
        const res = (await this.queryBus.execute(new IsProceedRecipientQuery(securityId, proceedRecipient))).payload;
        if (res) {
            throw new AccountIsProceedRecipient(securityId, proceedRecipient);
        }
        return !res;
    }
};
ValidationService = __decorate([
    singleton(),
    __metadata("design:paramtypes", [])
], ValidationService);
export default ValidationService;
