// SPDX-License-Identifier: Apache-2.0
import { ethers } from "ethers";
import { Factory__factory, TREXFactoryAts__factory } from "@hashgraph/asset-tokenization-contracts";
import { EVM_ZERO_ADDRESS, GAS } from "../../../../core/Constants";
import { FactoryBondToken, FactoryEquityToken, FactoryRegulationData, } from "../../../../domain/context/factory/FactorySecurityToken";
import { CastRegulationSubType, CastRegulationType } from "../../../../domain/context/factory/RegulationType";
import { SecurityRole } from "../../../../domain/context/security/SecurityRole";
import { BondDetailsData } from "../../../../domain/context/factory/BondDetailsData";
import { CastDividendType } from "../../../../domain/context/equity/DividendType";
import { MissingRegulationSubType } from "../../../../domain/context/factory/error/MissingRegulationSubType";
import { MissingRegulationType } from "../../../../domain/context/factory/error/MissingRegulationType";
import { SigningError } from "../../../out/error/SigningError";
import LogService from "../../../../app/service/log/LogService";
import { InterestRate } from "../../../../domain/context/bond/InterestRate";
import { ImpactData } from "../../../../domain/context/bond/ImpactData";
export class FactoryOperations {
    executor;
    constructor(executor) {
        this.executor = executor;
    }
    async createEquity(securityInfo, equityInfo, factory, resolver, configId, configVersion, compliance, identityRegistryAddress, externalPauses, externalControlLists, externalKycLists, diamondOwnerAccount, factoryId) {
        try {
            if (!securityInfo.regulationType)
                throw new MissingRegulationType();
            if (!securityInfo.regulationsubType)
                throw new MissingRegulationSubType();
            const rbacAdmin = {
                role: SecurityRole._DEFAULT_ADMIN_ROLE,
                members: [diamondOwnerAccount.toString()],
            };
            const erc20MetadataInfo = {
                name: securityInfo.name,
                symbol: securityInfo.symbol,
                isin: securityInfo.isin,
                decimals: securityInfo.decimals,
            };
            const resolverProxyConfiguration = {
                key: configId,
                version: configVersion,
            };
            const security = {
                arePartitionsProtected: securityInfo.arePartitionsProtected,
                isMultiPartition: securityInfo.isMultiPartition,
                resolver: resolver.toString(),
                resolverProxyConfiguration,
                rbacs: [rbacAdmin],
                isControllable: securityInfo.isControllable,
                isWhiteList: securityInfo.isWhiteList,
                maxSupply: securityInfo.maxSupply ? securityInfo.maxSupply.toString() : "0",
                erc20VotesActivated: securityInfo.erc20VotesActivated,
                erc20MetadataInfo,
                clearingActive: securityInfo.clearingActive,
                internalKycActivated: securityInfo.internalKycActivated,
                externalPauses: externalPauses?.map((address) => address.toString()) ?? [],
                externalControlLists: externalControlLists?.map((address) => address.toString()) ?? [],
                externalKycLists: externalKycLists?.map((address) => address.toString()) ?? [],
                compliance: compliance.toString(),
                identityRegistry: identityRegistryAddress?.toString(),
            };
            const equityDetails = {
                votingRight: equityInfo.votingRight,
                informationRight: equityInfo.informationRight,
                liquidationRight: equityInfo.liquidationRight,
                subscriptionRight: equityInfo.subscriptionRight,
                conversionRight: equityInfo.conversionRight,
                redemptionRight: equityInfo.redemptionRight,
                putRight: equityInfo.putRight,
                dividendRight: CastDividendType.toNumber(equityInfo.dividendRight),
                currency: equityInfo.currency,
                nominalValue: equityInfo.nominalValue.toString(),
                nominalValueDecimals: equityInfo.nominalValueDecimals,
            };
            const securityTokenToCreate = new FactoryEquityToken(security, equityDetails);
            const additionalSecurityData = {
                countriesControlListType: securityInfo.isCountryControlListWhiteList,
                listOfCountries: securityInfo.countries ?? "",
                info: securityInfo.info ?? "",
            };
            const factoryRegulationData = new FactoryRegulationData(CastRegulationType.toNumber(securityInfo.regulationType), CastRegulationSubType.toNumber(securityInfo.regulationsubType), additionalSecurityData);
            LogService.logTrace(`Deploying equity: ${{ security: securityTokenToCreate }}`);
            return this.executor.executeContractCall(factoryId.toString(), Factory__factory.createInterface(), "deployEquity", [securityTokenToCreate, factoryRegulationData], GAS.CREATE_EQUITY_ST);
        }
        catch (error) {
            LogService.logError(error);
            throw new SigningError(`Unexpected error in HederaTransactionAdapter create operation : ${error}`);
        }
    }
    async createBond(securityInfo, bondInfo, factory, resolver, configId, configVersion, compliance, identityRegistry, externalPauses, externalControlLists, externalKycLists, diamondOwnerAccount, proceedRecipients = [], proceedRecipientsData = [], factoryId) {
        try {
            if (!securityInfo.regulationType)
                throw new MissingRegulationType();
            if (!securityInfo.regulationsubType)
                throw new MissingRegulationSubType();
            const rbacAdmin = {
                role: SecurityRole._DEFAULT_ADMIN_ROLE,
                members: [diamondOwnerAccount.toString()],
            };
            const erc20MetadataInfo = {
                name: securityInfo.name,
                symbol: securityInfo.symbol,
                isin: securityInfo.isin,
                decimals: securityInfo.decimals,
            };
            const resolverProxyConfiguration = {
                key: configId,
                version: configVersion,
            };
            const security = {
                arePartitionsProtected: securityInfo.arePartitionsProtected,
                isMultiPartition: securityInfo.isMultiPartition,
                resolver: resolver.toString(),
                resolverProxyConfiguration,
                rbacs: [rbacAdmin],
                isControllable: securityInfo.isControllable,
                isWhiteList: securityInfo.isWhiteList,
                maxSupply: securityInfo.maxSupply ? securityInfo.maxSupply.toString() : "0",
                erc20VotesActivated: securityInfo.erc20VotesActivated,
                erc20MetadataInfo,
                clearingActive: securityInfo.clearingActive,
                internalKycActivated: securityInfo.internalKycActivated,
                externalPauses: externalPauses?.map((address) => address.toString()) ?? [],
                externalControlLists: externalControlLists?.map((address) => address.toString()) ?? [],
                externalKycLists: externalKycLists?.map((address) => address.toString()) ?? [],
                compliance: compliance.toString(),
                identityRegistry: identityRegistry.toString(),
            };
            const bondDetails = new BondDetailsData(bondInfo.currency, bondInfo.nominalValue.toString(), bondInfo.nominalValueDecimals, bondInfo.startingDate.toString(), bondInfo.maturityDate.toString());
            const securityTokenToCreate = new FactoryBondToken(security, bondDetails, proceedRecipients.map((addr) => addr.toString()), proceedRecipientsData.map((data) => (data == "" ? "0x" : data)));
            const additionalSecurityData = {
                countriesControlListType: securityInfo.isCountryControlListWhiteList,
                listOfCountries: securityInfo.countries ?? "",
                info: securityInfo.info ?? "",
            };
            const factoryRegulationData = new FactoryRegulationData(CastRegulationType.toNumber(securityInfo.regulationType), CastRegulationSubType.toNumber(securityInfo.regulationsubType), additionalSecurityData);
            LogService.logTrace(`Deploying bond: ${{ security: securityTokenToCreate }}`);
            return this.executor.executeContractCall(factoryId.toString(), Factory__factory.createInterface(), "deployBond", [securityTokenToCreate, factoryRegulationData], GAS.CREATE_BOND_ST);
        }
        catch (error) {
            LogService.logError(error);
            throw new SigningError(`Unexpected error in HederaTransactionAdapter create operation : ${error}`);
        }
    }
    async createBondFixedRate(securityInfo, bondInfo, factory, resolver, configId, configVersion, compliance, identityRegistry, externalPauses, externalControlLists, externalKycLists, diamondOwnerAccount, proceedRecipients = [], proceedRecipientsData = [], factoryId) {
        try {
            if (!securityInfo.regulationType)
                throw new MissingRegulationType();
            if (!securityInfo.regulationsubType)
                throw new MissingRegulationSubType();
            const rbacAdmin = {
                role: SecurityRole._DEFAULT_ADMIN_ROLE,
                members: [diamondOwnerAccount.toString()],
            };
            const erc20MetadataInfo = {
                name: securityInfo.name,
                symbol: securityInfo.symbol,
                isin: securityInfo.isin,
                decimals: securityInfo.decimals,
            };
            const resolverProxyConfiguration = {
                key: configId,
                version: configVersion,
            };
            const security = {
                arePartitionsProtected: securityInfo.arePartitionsProtected,
                isMultiPartition: securityInfo.isMultiPartition,
                resolver: resolver.toString(),
                resolverProxyConfiguration,
                rbacs: [rbacAdmin],
                isControllable: securityInfo.isControllable,
                isWhiteList: securityInfo.isWhiteList,
                maxSupply: securityInfo.maxSupply ? securityInfo.maxSupply.toString() : "0",
                erc20VotesActivated: securityInfo.erc20VotesActivated,
                erc20MetadataInfo,
                clearingActive: securityInfo.clearingActive,
                internalKycActivated: securityInfo.internalKycActivated,
                externalPauses: externalPauses?.map((address) => address.toString()) ?? [],
                externalControlLists: externalControlLists?.map((address) => address.toString()) ?? [],
                externalKycLists: externalKycLists?.map((address) => address.toString()) ?? [],
                compliance: compliance.toString(),
                identityRegistry: identityRegistry.toString(),
            };
            const bondDetails = new BondDetailsData(bondInfo.currency, bondInfo.nominalValue.toString(), bondInfo.nominalValueDecimals, bondInfo.startingDate.toString(), bondInfo.maturityDate.toString());
            const securityTokenToCreate = new FactoryBondToken(security, bondDetails, proceedRecipients.map((addr) => addr.toString()), proceedRecipientsData.map((data) => (data == "" ? "0x" : data)));
            const additionalSecurityData = {
                countriesControlListType: securityInfo.isCountryControlListWhiteList,
                listOfCountries: securityInfo.countries ?? "",
                info: securityInfo.info ?? "",
            };
            const factoryRegulationData = new FactoryRegulationData(CastRegulationType.toNumber(securityInfo.regulationType), CastRegulationSubType.toNumber(securityInfo.regulationsubType), additionalSecurityData);
            const bondFixedRateData = {
                bondData: securityTokenToCreate,
                factoryRegulationData: factoryRegulationData,
                fixedRateData: { rate: bondInfo.rate, rateDecimals: bondInfo.rateDecimals },
            };
            LogService.logTrace(`Deploying bond fixed rate: ${{ security: securityTokenToCreate }}`);
            return this.executor.executeContractCall(factoryId.toString(), Factory__factory.createInterface(), "deployBondFixedRate", [bondFixedRateData], GAS.CREATE_BOND_ST);
        }
        catch (error) {
            LogService.logError(error);
            throw new SigningError(`Unexpected error in HederaTransactionAdapter create operation : ${error}`);
        }
    }
    async createBondKpiLinkedRate(securityInfo, bondInfo, factory, resolver, configId, configVersion, compliance, identityRegistry, externalPauses, externalControlLists, externalKycLists, diamondOwnerAccount, proceedRecipients = [], proceedRecipientsData = [], factoryId) {
        try {
            if (!securityInfo.regulationType)
                throw new MissingRegulationType();
            if (!securityInfo.regulationsubType)
                throw new MissingRegulationSubType();
            const rbacAdmin = {
                role: SecurityRole._DEFAULT_ADMIN_ROLE,
                members: [diamondOwnerAccount.toString()],
            };
            const erc20MetadataInfo = {
                name: securityInfo.name,
                symbol: securityInfo.symbol,
                isin: securityInfo.isin,
                decimals: securityInfo.decimals,
            };
            const resolverProxyConfiguration = {
                key: configId,
                version: configVersion,
            };
            const security = {
                arePartitionsProtected: securityInfo.arePartitionsProtected,
                isMultiPartition: securityInfo.isMultiPartition,
                resolver: resolver.toString(),
                resolverProxyConfiguration,
                rbacs: [rbacAdmin],
                isControllable: securityInfo.isControllable,
                isWhiteList: securityInfo.isWhiteList,
                maxSupply: securityInfo.maxSupply ? securityInfo.maxSupply.toString() : "0",
                erc20VotesActivated: securityInfo.erc20VotesActivated,
                erc20MetadataInfo,
                clearingActive: securityInfo.clearingActive,
                internalKycActivated: securityInfo.internalKycActivated,
                externalPauses: externalPauses?.map((address) => address.toString()) ?? [],
                externalControlLists: externalControlLists?.map((address) => address.toString()) ?? [],
                externalKycLists: externalKycLists?.map((address) => address.toString()) ?? [],
                compliance: compliance.toString(),
                identityRegistry: identityRegistry.toString(),
            };
            const bondDetails = new BondDetailsData(bondInfo.currency, bondInfo.nominalValue.toString(), bondInfo.nominalValueDecimals, bondInfo.startingDate.toString(), bondInfo.maturityDate.toString());
            const securityTokenToCreate = new FactoryBondToken(security, bondDetails, proceedRecipients.map((addr) => addr.toString()), proceedRecipientsData.map((data) => (data == "" ? "0x" : data)));
            const additionalSecurityData = {
                countriesControlListType: securityInfo.isCountryControlListWhiteList,
                listOfCountries: securityInfo.countries ?? "",
                info: securityInfo.info ?? "",
            };
            const factoryRegulationData = new FactoryRegulationData(CastRegulationType.toNumber(securityInfo.regulationType), CastRegulationSubType.toNumber(securityInfo.regulationsubType), additionalSecurityData);
            const interestRate = new InterestRate(bondInfo.interestRate.maxRate, bondInfo.interestRate.baseRate, bondInfo.interestRate.minRate, bondInfo.interestRate.startPeriod, bondInfo.interestRate.startRate, bondInfo.interestRate.missedPenalty, bondInfo.interestRate.reportPeriod, bondInfo.interestRate.rateDecimals);
            const impactData = new ImpactData(bondInfo.impactData.maxDeviationCap, bondInfo.impactData.baseLine, bondInfo.impactData.maxDeviationFloor, bondInfo.impactData.impactDataDecimals, bondInfo.impactData.adjustmentPrecision);
            const bondKpiLinkedRateData = {
                bondData: securityTokenToCreate,
                factoryRegulationData: factoryRegulationData,
                interestRate: interestRate,
                impactData: impactData,
                kpiOracle: EVM_ZERO_ADDRESS,
            };
            LogService.logTrace(`Deploying bond kpi linked rate: ${{ security: securityTokenToCreate }}`);
            return this.executor.executeContractCall(factoryId.toString(), Factory__factory.createInterface(), "deployBondKpiLinkedRate", [bondKpiLinkedRateData], GAS.CREATE_BOND_ST);
        }
        catch (error) {
            LogService.logError(error);
            throw new SigningError(`Unexpected error in HederaTransactionAdapter create operation : ${error}`);
        }
    }
    async createTrexSuiteBond(salt, owner, irs, onchainId, irAgents, tokenAgents, compliancesModules, complianceSettings, claimTopics, issuers, issuerClaims, security, bondDetails, factory, resolver, configId, configVersion, compliance, identityRegistryAddress, diamondOwnerAccount, proceedRecipients = [], proceedRecipientsData = [], externalPauses, externalControlLists, externalKycLists, factoryId) {
        LogService.logTrace(`Deploying trex suite bond: ${security.toString()}`);
        if (!security.regulationType)
            throw new MissingRegulationType();
        if (!security.regulationsubType)
            throw new MissingRegulationSubType();
        const rbacAdmin = {
            role: SecurityRole._DEFAULT_ADMIN_ROLE,
            members: [diamondOwnerAccount.toString()],
        };
        const erc20MetadataInfo = {
            name: security.name,
            symbol: security.symbol,
            isin: security.isin,
            decimals: security.decimals,
        };
        const resolverProxyConfiguration = {
            key: configId,
            version: configVersion,
        };
        const securityData = {
            arePartitionsProtected: security.arePartitionsProtected,
            isMultiPartition: security.isMultiPartition,
            resolver: resolver.toString(),
            resolverProxyConfiguration,
            rbacs: [rbacAdmin],
            isControllable: security.isControllable,
            isWhiteList: security.isWhiteList,
            maxSupply: security.maxSupply ? security.maxSupply.toString() : "0",
            erc20MetadataInfo,
            clearingActive: security.clearingActive,
            internalKycActivated: security.internalKycActivated,
            externalPauses: externalPauses?.map((address) => address.toString()) ?? [],
            externalControlLists: externalControlLists?.map((address) => address.toString()) ?? [],
            externalKycLists: externalKycLists?.map((address) => address.toString()) ?? [],
            compliance: compliance.toString(),
            identityRegistry: identityRegistryAddress.toString(),
            erc20VotesActivated: security.erc20VotesActivated,
        };
        const bondDetailsData = new BondDetailsData(bondDetails.currency, bondDetails.nominalValue.toString(), bondDetails.nominalValueDecimals, bondDetails.startingDate.toString(), bondDetails.maturityDate.toString());
        const securityTokenToCreate = new FactoryBondToken(securityData, bondDetailsData, proceedRecipients.map((b) => b.toString()), proceedRecipientsData.map((data) => (data == "" ? "0x" : data)));
        const additionalSecurityData = {
            countriesControlListType: security.isCountryControlListWhiteList,
            listOfCountries: security.countries ?? "",
            info: security.info ?? "",
        };
        const factoryRegulationData = new FactoryRegulationData(CastRegulationType.toNumber(security.regulationType), CastRegulationSubType.toNumber(security.regulationsubType), additionalSecurityData);
        try {
            return this.executor.executeContractCall(factoryId.toString(), new ethers.Interface(TREXFactoryAts__factory.abi), "deployTREXSuiteAtsBond", [
                salt,
                {
                    owner,
                    irs,
                    ONCHAINID: onchainId,
                    irAgents,
                    tokenAgents,
                    complianceModules: compliancesModules,
                    complianceSettings,
                },
                { claimTopics, issuers, issuerClaims },
                securityTokenToCreate,
                factoryRegulationData,
            ], GAS.TREX_CREATE_SUITE);
        }
        catch (error) {
            LogService.logError(error);
            throw new SigningError(`Unexpected error in TREXFactoryAts__factory deploy operation : ${error}`);
        }
    }
    async createTrexSuiteEquity(salt, owner, irs, onchainId, irAgents, tokenAgents, compliancesModules, complianceSettings, claimTopics, issuers, issuerClaims, security, equityDetails, factory, resolver, configId, configVersion, compliance, identityRegistryAddress, diamondOwnerAccount, externalPauses, externalControlLists, externalKycLists, factoryId) {
        LogService.logTrace(`Deploying trex suite equity: ${security.toString()}`);
        try {
            if (!security.regulationType)
                throw new MissingRegulationType();
            if (!security.regulationsubType)
                throw new MissingRegulationSubType();
            const rbacAdmin = {
                role: SecurityRole._DEFAULT_ADMIN_ROLE,
                members: [diamondOwnerAccount.toString()],
            };
            const erc20MetadataInfo = {
                name: security.name,
                symbol: security.symbol,
                isin: security.isin,
                decimals: security.decimals,
            };
            const resolverProxyConfiguration = {
                key: configId,
                version: configVersion,
            };
            const securityData = {
                arePartitionsProtected: security.arePartitionsProtected,
                isMultiPartition: security.isMultiPartition,
                resolver: resolver.toString(),
                resolverProxyConfiguration,
                rbacs: [rbacAdmin],
                isControllable: security.isControllable,
                isWhiteList: security.isWhiteList,
                maxSupply: security.maxSupply ? security.maxSupply.toString() : "0",
                erc20MetadataInfo,
                clearingActive: security.clearingActive,
                internalKycActivated: security.internalKycActivated,
                externalPauses: externalPauses?.map((address) => address.toString()) ?? [],
                externalControlLists: externalControlLists?.map((address) => address.toString()) ?? [],
                externalKycLists: externalKycLists?.map((address) => address.toString()) ?? [],
                compliance: compliance.toString(),
                identityRegistry: identityRegistryAddress?.toString(),
                erc20VotesActivated: security.erc20VotesActivated,
            };
            const equityDetailsData = {
                votingRight: equityDetails.votingRight,
                informationRight: equityDetails.informationRight,
                liquidationRight: equityDetails.liquidationRight,
                subscriptionRight: equityDetails.subscriptionRight,
                conversionRight: equityDetails.conversionRight,
                redemptionRight: equityDetails.redemptionRight,
                putRight: equityDetails.putRight,
                dividendRight: CastDividendType.toNumber(equityDetails.dividendRight),
                currency: equityDetails.currency,
                nominalValue: equityDetails.nominalValue.toString(),
                nominalValueDecimals: equityDetails.nominalValueDecimals,
            };
            const securityTokenToCreate = new FactoryEquityToken(securityData, equityDetailsData);
            const additionalSecurityData = {
                countriesControlListType: security.isCountryControlListWhiteList,
                listOfCountries: security.countries ?? "",
                info: security.info ?? "",
            };
            const factoryRegulationData = new FactoryRegulationData(CastRegulationType.toNumber(security.regulationType), CastRegulationSubType.toNumber(security.regulationsubType), additionalSecurityData);
            LogService.logTrace(`Deploying equity: ${{ security: securityTokenToCreate }}`);
            return this.executor.executeContractCall(factoryId.toString(), new ethers.Interface(TREXFactoryAts__factory.abi), "deployTREXSuiteAtsEquity", [
                salt,
                {
                    owner,
                    irs,
                    ONCHAINID: onchainId,
                    irAgents,
                    tokenAgents,
                    complianceModules: compliancesModules,
                    complianceSettings,
                },
                { claimTopics, issuers, issuerClaims },
                securityTokenToCreate,
                factoryRegulationData,
            ], GAS.TREX_CREATE_SUITE);
        }
        catch (error) {
            LogService.logError(error);
            throw new SigningError(`Unexpected error in HederaTransactionAdapter create operation : ${error}`);
        }
    }
}
