import { assert, objFilter, objLength } from '@hyperlane-xyz/utils';
import { WARP_ROUTE_ID_REGEX } from '../consts.js';
import { stripLeadingSlash } from '../utils.js';
import { MergedRegistry } from './MergedRegistry.js';
import { createWarpRouteConfigId } from './warp-utils.js';
export class BaseRegistry {
    uri;
    logger;
    // Caches
    listContentCache;
    metadataCache;
    isMetadataCacheFull = false;
    addressCache;
    isAddressCacheFull = false;
    warpRouteCache;
    isWarpRouteCacheFull = false;
    constructor({ uri, logger }) {
        this.uri = uri;
        // @ts-ignore forcing in to avoid a @hyperlane-xyz/utils
        // dependency here, which could bloat consumer bundles
        // unnecessarily (e.g. they just want metadata)
        this.logger = logger || console;
    }
    getUri(itemPath) {
        if (itemPath)
            itemPath = stripLeadingSlash(itemPath);
        return itemPath ? `${this.uri}/${itemPath}` : this.uri;
    }
    getChainsPath() {
        return 'chains';
    }
    getWarpRoutesPath() {
        return 'deployments/warp_routes';
    }
    /**
     * Generates a warp route ID from a warp core config.
     *
     * The function handles three main cases:
     * 1. If a warpRouteId is provided in options, it uses that directly
     * 2. If there is exactly one synthetic token, it uses that token's chain and symbol
     * 3. Otherwise, it uses all chains and requires a single symbol (either from options or tokens)
     */
    static warpRouteConfigToId(config, options) {
        assert(config?.tokens?.length > 0, 'Cannot generate ID for empty warp config');
        const syntheticTokens = config.tokens.filter((token) => token.standard?.includes('Synthetic'));
        let warpRouteId;
        if (options && 'warpRouteId' in options) {
            warpRouteId = options.warpRouteId;
        }
        else if (syntheticTokens.length === 1) {
            const syntheticChain = syntheticTokens[0].chainName;
            const syntheticSymbol = syntheticTokens[0].symbol;
            const symbol = options?.symbol || syntheticSymbol;
            warpRouteId = createWarpRouteConfigId(symbol, syntheticChain);
        }
        else {
            // Only support one symbol per warp config for now
            const allChains = config.tokens.map((token) => token.chainName);
            const allSymbols = new Set(config.tokens.map((token) => token.symbol));
            if (!options?.symbol && allSymbols.size !== 1) {
                throw new Error(`Only one token symbol per warp config is supported for now. Found: [${[
                    ...allSymbols,
                ].join()}]`);
            }
            const symbol = options?.symbol || [...allSymbols][0];
            warpRouteId = createWarpRouteConfigId(symbol, allChains.sort().join('-'));
        }
        assert(warpRouteId.match(WARP_ROUTE_ID_REGEX), `Invalid warp route ID: ${warpRouteId}. Must be in the format such as: TOKENSYMBOL/label...`);
        return warpRouteId;
    }
    getWarpRouteCoreConfigPath(config, options) {
        const warpRouteId = BaseRegistry.warpRouteConfigToId(config, options);
        return `${this.getWarpRoutesPath()}/${warpRouteId}-config.yaml`;
    }
    /**
     * Generates a warp route ID based on the deploy config and options.
     *
     * @param config The warp route deployment config
     * @param options Additional config options for the warp route
     * @returns A string ID for the warp route
     *
     * If a warpRouteId is provided in options, use it directly.
     * Otherwise, the method attempts to generate an ID based on 1 synthetic chain, or defaults to all chains.
     */
    static warpDeployConfigToId(config, options) {
        assert(objLength(config) > 0, 'Cannot generate ID for empty warp deploy config');
        const syntheticChains = objFilter(config, (_, c) => c.type?.includes('synthetic'));
        let warpRouteId;
        if ('warpRouteId' in options) {
            warpRouteId = options.warpRouteId;
        }
        else if (objLength(syntheticChains) === 1) {
            warpRouteId = createWarpRouteConfigId(options.symbol, Object.keys(syntheticChains)[0]);
        }
        else {
            warpRouteId = createWarpRouteConfigId(options.symbol, Object.keys(config).sort().join('-'));
        }
        assert(warpRouteId.match(WARP_ROUTE_ID_REGEX), `Invalid warp route ID: ${warpRouteId}. Must be in the format such as: TOKENSYMBOL/label...`);
        return warpRouteId;
    }
    getWarpRouteDeployConfigPath(config, options) {
        const warpRouteId = BaseRegistry.warpDeployConfigToId(config, options);
        return `${this.getWarpRoutesPath()}/${warpRouteId}-deploy.yaml`;
    }
    async getChainLogoUri(chainName) {
        const registryContent = await this.listRegistryContent();
        const chain = registryContent.chains[chainName];
        return chain?.logo ?? null;
    }
    merge(otherRegistry) {
        return new MergedRegistry({ registries: [this, otherRegistry], logger: this.logger });
    }
}
