import { Chain } from "@src/models";
import { isServer } from "@src/utils";
import { defineChain, Transport } from "viem";
import * as WagmiChains from "viem/chains";
import { mainnet } from "viem/chains";
import { Config, createConfig, createStorage, http } from "@wagmi/core";
import { injected, walletConnect } from "@wagmi/connectors";

const storage = createStorage({
  key: "xpay.wagmi.store",
  storage: !isServer ? localStorage : undefined,
});

export const getWagmiConfig = (supportedChains: Chain[]): Config => {
  const chains = mapChains(supportedChains);
  const transports = mapTransports(chains);
  return createConfig({
    chains,
    transports,
    connectors: [
      injected(),
      walletConnect({
        projectId: "c392898b45ac587a280b5eb33e92aeb0",
        showQrModal: true,
      }),
    ],
    storage,
  });
};

const mapChains = (
  supportedChains: Chain[],
): [WagmiChains.Chain, ...WagmiChains.Chain[]] => {
  const result: [WagmiChains.Chain, ...WagmiChains.Chain[]] = [mainnet];
  result.push(
    ...Object.values(WagmiChains).filter(
      (chain) =>
        chain.id !== mainnet.id &&
        supportedChains.some(({ chainId }) => chainId === chain.id.toString()),
    ),
  );
  for (const s of supportedChains) {
    if (s.ecosystem !== "evm") continue;
    const id = Number(s.chainId);
    const exists = result.some((c) => c.id === id);
    if (!exists) {
      const custom = defineChain({
        id,
        name: s.name,
        nativeCurrency: {
          name: s.tokenSymbol,
          symbol: s.tokenSymbol,
          decimals: 18,
        },
        rpcUrls: {
          default: { http: s.publicRpcUrls },
        },
        blockExplorers: {
          default: {
            name: s.transactionExplorer.match(/\/\/([^.]*)\./)?.[1] || "",
            url: s.transactionExplorer,
          },
        },
      });
      result.push(custom);
    }
  }
  const seen = new Set<number>();
  const deduped = result.filter((c) => {
    if (seen.has(c.id)) return false;
    seen.add(c.id);
    return true;
  });
  return deduped as [WagmiChains.Chain, ...WagmiChains.Chain[]];
};

const mapTransports = (
  chains: WagmiChains.Chain[],
): Record<number, Transport> => {
  const transports: Record<number, Transport> = {};
  chains.forEach((chain) => {
    transports[chain.id] = http();
  });
  return transports;
};
