import { getLookupFn, getDynamicBuilder } from '@polkadot-api/metadata-builders';
import { u32, unifyMetadata, decAnyMetadata, compact } from '@polkadot-api/substrate-bindings';
import { getExtrinsicDecoder as getExtrinsicDecoder$1 } from '@polkadot-api/tx-utils';
import { Binary } from 'polkadot-api';
import { mergeUint8 } from 'polkadot-api/utils';
import { runRuntimeCall } from './executor.js';
import { logger } from './logger.js';

const log = logger.child({ module: "codecs" });
const blockMeta = /* @__PURE__ */ new WeakMap();
const setBlockMeta = async (chain, block) => {
  const parentMeta = blockMeta.get(chain.getBlock(block.parent));
  if (!block.hasNewRuntime && parentMeta) {
    blockMeta.set(block, parentMeta);
    return;
  }
  blockMeta.set(
    block,
    new Promise(async (resolve) => {
      const metadata = await runRuntimeCall({
        chain,
        hash: block.hash,
        call: "Metadata_metadata_at_version",
        params: Binary.toHex(u32.enc(15))
      });
      const metadataRaw = Binary.fromHex(metadata.result);
      const lookup = getLookupFn(unifyMetadata(decAnyMetadata(metadataRaw)));
      const dynamicBuilder = getDynamicBuilder(lookup);
      resolve({ lookup, dynamicBuilder, metadataRaw });
    })
  );
};
const getConstant = async (block, palletName, entryName) => {
  const meta = await blockMeta.get(block);
  if (!meta) {
    throw new Error("Block doesn't have metadata set");
  }
  try {
    const codec = meta.dynamicBuilder.buildConstant(palletName, entryName);
    const pallet = meta.lookup.metadata.pallets.find(
      (p) => p.name === palletName
    );
    const entry = pallet.constants.find((ct) => ct.name === entryName);
    return codec.dec(entry.value);
  } catch (e) {
    return null;
  }
};
const getStorageCodecs = async (block, palletName, entryName) => {
  const meta = await blockMeta.get(block);
  if (!meta) {
    throw new Error("Block doesn't have metadata set");
  }
  try {
    return meta.dynamicBuilder.buildStorage(palletName, entryName);
  } catch {
    return null;
  }
};
const getTxCodec = async (block, palletName, txName) => {
  const meta = await blockMeta.get(block);
  if (!meta) {
    throw new Error("Block doesn't have metadata set");
  }
  try {
    return meta.dynamicBuilder.buildCall(palletName, txName);
  } catch (ex) {
    return null;
  }
};
const getCallCodec = async (block, palletName, apiName) => {
  const meta = await blockMeta.get(block);
  if (!meta) {
    throw new Error("Block doesn't have metadata set");
  }
  try {
    return meta.dynamicBuilder.buildRuntimeCall(palletName, apiName);
  } catch (ex) {
    return null;
  }
};
const getCallData = async (block, palletName, txName, params) => {
  const tx = await getTxCodec(block, palletName, txName);
  if (!tx) return null;
  try {
    const { location, codec } = tx;
    return mergeUint8([new Uint8Array(location), codec.enc(params)]);
  } catch (ex) {
    log.error(ex, "getCallData failed");
    return null;
  }
};
const getExtrinsicDecoder = async (block) => {
  const meta = await blockMeta.get(block);
  if (!meta) {
    throw new Error("Block doesn't have metadata set");
  }
  return getExtrinsicDecoder$1(meta.metadataRaw);
};
const unsignedExtrinsic = (callData) => mergeUint8([compact.enc(callData.length + 1), new Uint8Array([4]), callData]);

export { getCallCodec, getCallData, getConstant, getExtrinsicDecoder, getStorageCodecs, getTxCodec, setBlockMeta, unsignedExtrinsic };
//# sourceMappingURL=codecs.js.map
